prick 0.29.2 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/TODO +2 -0
  3. data/exe/prick +290 -518
  4. data/lib/prick/builder/batch.rb +1 -4
  5. data/lib/prick/builder/builder.rb +15 -9
  6. data/lib/prick/builder/node.rb +3 -2
  7. data/lib/prick/builder/node_pool.rb +3 -1
  8. data/lib/prick/builder/parser.rb +2 -1
  9. data/lib/prick/constants.rb +12 -12
  10. data/lib/prick/diff.rb +2 -2
  11. data/lib/prick/environment.rb +23 -10
  12. data/lib/prick/local/command.rb +8 -2
  13. data/lib/prick/local/fmt.rb +56 -0
  14. data/lib/prick/prick_version.rb +1 -1
  15. data/lib/prick/share/init/{.gitignore → dot.gitignore} +1 -1
  16. data/lib/prick/share/init/prick.environment.yml +16 -0
  17. data/lib/prick/share/init/prick.yml +3 -3
  18. data/lib/prick/share/init/schema/prick/build.yml +11 -2
  19. data/lib/prick/share/init/schema/prick/tables.sql +30 -9
  20. data/lib/prick/share/init/schema/prick/views.sql +6 -0
  21. data/lib/prick/state.rb +297 -95
  22. data/lib/prick/subcommand/prick-build.rb +26 -20
  23. data/lib/prick/subcommand/prick-clean.rb +5 -5
  24. data/lib/prick/subcommand/prick-create.rb +41 -6
  25. data/lib/prick/subcommand/prick-drop.rb +57 -14
  26. data/lib/prick/subcommand/prick-fox.rb +1 -1
  27. data/lib/prick/subcommand/prick-init.rb +25 -18
  28. data/lib/prick/subcommand/prick-list.rb +99 -0
  29. data/lib/prick/subcommand/prick-make.rb +8 -8
  30. data/lib/prick/subcommand/prick-migrate.rb +8 -7
  31. data/lib/prick/subcommand/prick-release.rb +4 -2
  32. data/lib/prick/subcommand/prick-set.rb +52 -0
  33. data/lib/prick/subcommand/prick-setup.rb +3 -13
  34. data/lib/prick/subcommand/prick-teardown.rb +13 -9
  35. data/lib/prick/subcommand/subcommand.rb +12 -0
  36. data/lib/prick/version.rb +1 -1
  37. data/lib/prick.rb +54 -15
  38. metadata +9 -5
  39. data/lib/prick/share/init/schema/prick/data.sql +0 -6
  40. data/prick.environments.yml +0 -14
@@ -1,7 +1,7 @@
1
1
  module Prick
2
2
  module Build
3
3
  class BuildBatch
4
- include ::Timer
4
+ include Timer
5
5
 
6
6
  attr_reader :builder
7
7
  forward_to :builder, :conn
@@ -144,9 +144,6 @@ module Prick
144
144
  delete = builder.clean ? :none : :touched
145
145
  begin
146
146
  conn.execute fox.to_sql(format: :exec, delete: delete)
147
-
148
- # FIXME: Why only in FoxBatch - should be set higher up in the system
149
- conn.execute "update prick.versions set built_at = now() at time zone 'UTC'"
150
147
  rescue PG::SyntaxError, PG::Error => ex
151
148
  raise PostgresError.new(ex.message)
152
149
  end
@@ -1,4 +1,4 @@
1
- require_relative '../local/command'
1
+ require_relative '../local/command.rb'
2
2
 
3
3
  require_relative './node.rb'
4
4
  require_relative './node_pool.rb'
@@ -103,18 +103,24 @@ module Prick
103
103
  end
104
104
 
105
105
  def execute(conn, create_schemas: schemas)
106
+ # Group batches
106
107
  group if batches.nil?
108
+
109
+ # Register build in database
110
+ Prick.state.save_build_begin
111
+
112
+ # Create schemas
107
113
  conn.exec create_schemas.map { |schema| "create schema #{schema}" }
108
- for batch in batches
109
- batch.execute
110
- end
111
- end
112
114
 
113
- # def setup
114
- # end
115
+ # Execute batch groups
116
+ t0 = Time.now
117
+ batches.each(&:execute)
118
+ t1 = Time.now
115
119
 
116
- # def teardown
117
- # end
120
+ # Register build result in database
121
+ dt = t1 - t0
122
+ Prick.state.save_build_end(true, dt)
123
+ end
118
124
 
119
125
  def dump
120
126
  batches ? batches.each(&:dump) : pool.dump
@@ -140,7 +140,7 @@ module Prick
140
140
  Command.command(Prick.state.bash_environment, command)
141
141
  rescue Command::Error => ex
142
142
  message = "Error executing '#{command}'\n" + ex.stderr.map { |l| " #{l}" }.join("\n")
143
- raise Prick::Error.new(message)
143
+ Prick.error message
144
144
  end
145
145
  end
146
146
  end
@@ -188,12 +188,13 @@ module Prick
188
188
  puts "BuildNode #{path}"
189
189
  indent {
190
190
  puts "schema: #{schema}" if schema
191
+ puts "refresh: #{refresh_schema.to_s}"
191
192
  puts "pg_graph_ignore_schema: #{pg_graph_ignore_schema}"
192
193
  decl_nodes.each(&:dump)
193
194
  for kind in [:init, :term, :seed]
194
195
  kind_nodes = self.send("#{kind}_nodes".to_sym)
195
196
  if !kind_nodes.empty?
196
- puts "#{kind.upcase}:"
197
+ puts "#{kind}:"
197
198
  indent { kind_nodes.each(&:dump) }
198
199
  end
199
200
  end
@@ -25,7 +25,7 @@ module Prick
25
25
  def build_nodes() nodes.select { |node| node.is_a?(BuildNode) } end
26
26
 
27
27
  # List of schemas to ignore when building PgGraph objects. This is used
28
- # to exclude foreign schemes that doesn't follow the PgGraph naming
28
+ # to exclude foreign schemas that doesn't follow the PgGraph naming
29
29
  # conventions
30
30
  def pg_graph_ignore_schemas()
31
31
  all_nodes.select { |node|
@@ -33,6 +33,8 @@ module Prick
33
33
  }.map(&:schema).uniq
34
34
  end
35
35
 
36
+ # List of schemas that should be rebuilt. #refresh_schemas is not cached
37
+ # and can be manipulated by removing build nodes from the pool
36
38
  def refresh_schemas()
37
39
  build_nodes.select(&:refresh_schema).map(&:schema).uniq
38
40
  end
@@ -130,7 +130,8 @@ module Prick
130
130
  rest = $3
131
131
  args = expand_string(rest || '').split
132
132
  path = expand_filename(dir, command)
133
- path || optional or raise Error, "Can't find '#{entry}' in #{dir}/ from #{unit}"
133
+ path || optional or
134
+ raise Error, "Can't find file\n #{command}\n #{path}\n in #{dir}/\n from #{unit}"
134
135
  !path.nil? or return nil
135
136
  else
136
137
  raise Error, "Not a file name: '#{entry}'"
@@ -7,8 +7,8 @@ module Prick
7
7
  ### DIRECTORIES AND FILE NAMES
8
8
 
9
9
  # Shared files (part of the installation)
10
- SHARE_PATH = "#{File.dirname(File.dirname(__dir__))}/lib/share"
11
- LIBEXEC_PATH = "#{File.dirname(File.dirname(__dir__))}/lib/libexec"
10
+ SHARE_PATH = "#{File.dirname(File.dirname(__dir__))}/lib/prick/share"
11
+ LIBEXEC_PATH = "#{File.dirname(File.dirname(__dir__))}/lib/prick/libexec"
12
12
 
13
13
  # Project directories
14
14
  DIRS = [
@@ -30,19 +30,19 @@ module Prick
30
30
  PRICK_DIR = Dir.getwd
31
31
 
32
32
  # Search path for executables
33
- PRICK_PATH = "#{ENV['PATH']}:#{PRICK_DIR}/#{BIN_DIR}:#{PRICK_DIR}/#{LIBEXEC_DIR}"
33
+ # PRICK_PATH = "#{ENV['PATH']}:#{PRICK_DIR}/#{BIN_DIR}:#{PRICK_DIR}/#{LIBEXEC_DIR}"
34
34
 
35
- # Project specification file
35
+ # Project file
36
36
  PRICK_PROJECT_FILE = "prick.yml"
37
37
  PRICK_PROJECT_PATH = PRICK_PROJECT_FILE
38
38
 
39
- # # Environment specification file
40
- # PRICK_ENVIRONMENT_FILE = "prick.environment.yml"
41
- # PRICK_ENVIRONMENTS_PATH = PRICK_ENVIRONMENT_FILE
39
+ # Environment file
40
+ PRICK_ENVIRONMENT_FILE = "prick.environment.yml"
41
+ PRICK_ENVIRONMENT_PATH = PRICK_ENVIRONMENT_FILE
42
42
 
43
- # Context file
44
- PRICK_CONTEXT_FILE = ".prick-context"
45
- PRICK_CONTEXT_PATH = PRICK_CONTEXT_FILE
43
+ # State file
44
+ PRICK_STATE_FILE = ".prick.state.yml"
45
+ PRICK_STATE_PATH = PRICK_STATE_FILE
46
46
 
47
47
  # Fox state file (contains anchors and table sizes)
48
48
  FOX_STATE_FILE = ".fox-state.yml"
@@ -69,8 +69,8 @@ module Prick
69
69
  AFTER_TABLES_DIFF_FILE = "diff.after-tables.sql"
70
70
  ]
71
71
 
72
-
73
-
72
+ # Default environment
73
+ DEFAULT_ENVIRONMENT = "default"
74
74
 
75
75
  # Not in use:
76
76
 
data/lib/prick/diff.rb CHANGED
@@ -34,7 +34,7 @@ module Prick
34
34
  file2 = file3 = file1
35
35
  mark = mark.nil? ? true : mark
36
36
  elsif file2.nil? != file3.nil?
37
- raise Prick::Fail, "Either none or both of `file2` and `file3` should be nil"
37
+ Prick.failure "Either none or both of `file2` and `file3` should be nil"
38
38
  else
39
39
  mark = mark.nil? ? false : mark
40
40
  end
@@ -48,7 +48,7 @@ module Prick
48
48
  command = "migra --unsafe --with-privileges postgres:///#{@db1} postgres:///#{@db2}"
49
49
  @diff = Command.command(command, fail: false)
50
50
  [0,2].include?(Command.status) or
51
- raise Prick::Fail, "migrate command failed with status #{Command.status}: #{command}"
51
+ Prick.failure "migrate command failed with status #{Command.status}: #{command}"
52
52
  end
53
53
 
54
54
  # Initialize table change variables
@@ -1,11 +1,21 @@
1
1
  require 'yaml'
2
2
  require 'dsort'
3
3
 
4
+ # TODO:
5
+ # o Check :parent vs. :inherit (or explain the difference). Also check
6
+ # handling of :comment
7
+
4
8
  module Prick
9
+ # An environment as defined in the prick.environment file. The environment is
10
+ # constant across all instances of State so we ensure that it is loaded only
11
+ # once
5
12
  class Environment
6
13
  # Environments name
7
14
  attr_reader :name
8
15
 
16
+ # Environment comment. If not nil, this environment is considered a user-environment
17
+ attr_accessor :comment
18
+
9
19
  # Names of parent environments
10
20
  def parents = @values[:parents]
11
21
 
@@ -18,7 +28,7 @@ module Prick
18
28
  def variables = @@VARIABLES
19
29
 
20
30
  # List of user defined variables
21
- def user_variables = @@VARIABLES - [:parent]
31
+ def user_variables = @@VARIABLES - [:parents, :comment]
22
32
 
23
33
  # Hash from variable to value
24
34
  attr_accessor :values
@@ -34,14 +44,15 @@ module Prick
34
44
 
35
45
  def initialize(name)
36
46
  @name = name
47
+ @comment = nil
37
48
  @values = variables.map { |key| [key, []] }.to_h
38
49
  @effective_values = variables.map { |key| [key, []] }.to_h
39
50
  @@ENVIRONMENTS[name] = self
40
51
  end
41
52
 
42
- def self.load_environments(hash) # hash can be nil
53
+ def self.load_environments(yaml) # hash maps from environment name to object
43
54
  if hash
44
- parse(hash)
55
+ parse(yaml)
45
56
  analyze
46
57
  end
47
58
  end
@@ -84,18 +95,20 @@ module Prick
84
95
 
85
96
  def self.parse(hash)
86
97
  hash = hash.dup
87
- @@VARIABLES = [:parents] + (yaml_to_array(hash.delete("variables")).map(&:to_sym) || [])
98
+ @@VARIABLES = [:parents, :comment] + (yaml_to_array(hash.delete("variables") || []).map(&:to_sym) || [])
88
99
 
89
100
  for environment, settings in hash
90
101
  env = Environment.new(environment)
102
+ settings ||= {}
91
103
  if settings.is_a? Hash
92
104
  for variable, value in settings
93
- variable = (variable == "inherit" ? :parents : variable.to_sym)
94
- value = yaml_to_array(value)
95
- if variables.include?(variable)
96
- env.values[variable] = value
97
- else
98
- raise ArgumentError, "Illegal variable: '#{variable}'"
105
+ if variable == "comment"
106
+ env.comment = value
107
+ else
108
+ variable = (variable == "inherit" ? :parents : variable.to_sym)
109
+ value = yaml_to_array(value)
110
+ variables.include?(variable) or raise ArgumentError, "Illegal variable: '#{variable}'"
111
+ env.values[variable] = value
99
112
  end
100
113
  end
101
114
  else
@@ -128,8 +128,14 @@ module Command
128
128
  STDERR.reopen(pe[1])
129
129
  pe[1].close
130
130
 
131
- env
132
- exec(env.map { |k,v| [k.to_s, v.to_s] }.to_h, cmd)
131
+ # Clean bundler environment so that prick can be run in development mode.
132
+ # The problem is that the bundler environment is inherited by
133
+ # subprocesses and interferes with loading ruby commands. FIXME This is
134
+ # only relevant when running prick in development mode
135
+ ENV.delete_if { |k,v| %w(RUBYOPT RUBYLIB _).include?(k) || k =~ /^BUNDLER?_/ }
136
+ env = env.map { |k,v| [k.to_s, v.to_s] }.to_h # Convert array values to strings
137
+ env.each { |k,v| ENV[k] = v }
138
+ Kernel.exec(env, cmd)
133
139
  }
134
140
 
135
141
  pw[0].close
@@ -0,0 +1,56 @@
1
+
2
+ module Fmt
3
+ # Print table
4
+ def self.puts_table(headers, table)
5
+ widths = headers.map(&:size)
6
+ signs = []
7
+ types = []
8
+ for i in (0...headers.size)
9
+ widths[i] =
10
+ (
11
+ [widths[i]] +
12
+ table.map { |row|
13
+ case value = row[i]
14
+ when TrueClass, FalseClass
15
+ types[i] = 's'
16
+ signs[i] = '-'
17
+ 5
18
+ when NilClass
19
+ types[i] = 's'
20
+ signs[i] = '-'
21
+ 4
22
+ when String
23
+ types[i] = 's'
24
+ signs[i] = '-'
25
+ value.size
26
+ when Integer
27
+ types[i] = 'i'
28
+ signs[i] = ''
29
+ Math.log10(value) + 1
30
+ else
31
+ raise ArgumentError, value
32
+ end
33
+ }
34
+ ).max
35
+ end
36
+
37
+ widths = widths.map { _1 }
38
+
39
+ for width, value in widths.zip(headers)
40
+ printf "%-#{width}s ", value
41
+ end
42
+ puts
43
+ widths.each.with_index { |width, index|
44
+ char = (headers[index] =~ /^\s*$/ ? " " : "-")
45
+ printf "%#{width}s ", char * width
46
+ }
47
+ puts
48
+ for row in table
49
+ for sign, width, type, value in signs.zip(widths, types, row)
50
+ value = (value.nil? ? "-" : value)
51
+ printf "%#{sign}#{width}#{type} ", value
52
+ end
53
+ puts
54
+ end
55
+ end
56
+ end
@@ -77,7 +77,7 @@ module Prick
77
77
  @semver = version.semver.dup
78
78
  @feature = feature || version.feature
79
79
  else
80
- raise Internal, "Expected a String, PrickVersion, or Semantic::Version, got #{version.class}"
80
+ raise ArgumentError, "Expected a String, PrickVersion, or Semantic::Version, got #{version.class}"
81
81
  end
82
82
  end
83
83
 
@@ -1,6 +1,6 @@
1
1
 
2
2
  # Local database and environment
3
- /.prick-context
3
+ /.prick-state.yml
4
4
 
5
5
  # Fox state file
6
6
  /.fox-state.yml
@@ -0,0 +1,16 @@
1
+
2
+ variables:
3
+
4
+ all:
5
+
6
+ production:
7
+ inherit: all
8
+
9
+ development:
10
+ inherit: all
11
+
12
+ test:
13
+ inherit: all
14
+
15
+ default:
16
+ inherit: all
@@ -1,6 +1,6 @@
1
+ ---
2
+ # Initial project configuration file
1
3
  name:
2
- title:
3
- database:
4
- username:
4
+ title:
5
5
  version:
6
6
  prick:
@@ -1,5 +1,14 @@
1
+ # Controlled by the prick command. Don't change
2
+ #
3
+ # Note the SQL scripts are also called directly from 'prick setup' when the
4
+ # database is created because we don't want to parse the whole build
5
+ # environment just to create the prick schema. After the initial setup, the
6
+ # scripts are only run by 'prick build' with the --force option
7
+ #
8
+ # This is hardcoded an should be fixed somehow
9
+ #
1
10
  ---
2
11
  - schema: prick
12
+ refresh: false # Because the build process takes care of this
3
13
  - tables.sql
4
- - seed:
5
- - data.sql
14
+ - views.sql
@@ -1,16 +1,37 @@
1
1
  -- Controlled by prick(1). Don't touch
2
2
  --
3
+ -- TODO
4
+ -- o Replace view with a function to return the current build
3
5
 
4
6
  set search_path to prick;
5
7
 
6
- create table versions (
8
+ create table builds (
7
9
  id integer generated by default as identity primary key,
8
- fork varchar,
9
- major integer not null,
10
- minor integer not null,
11
- patch integer not null,
12
- pre integer,
13
- feature varchar,
14
- version varchar not null,
15
- built_at timestamp without time zone not null default (now() at time zone 'UTC')
10
+
11
+ -- Project name
12
+ name varchar not null,
13
+
14
+ -- Version
15
+ version varchar not null, -- Project version
16
+ prick varchar not null,-- Prick version
17
+
18
+ -- Git
19
+ branch varchar not null,
20
+ rev varchar not null, -- commit ID
21
+ clean boolean not null default true, -- True if git repository is clean
22
+
23
+ -- Environment
24
+ environment varchar not null default 'default',
25
+
26
+ -- Build timestamp. This is the time of the start of the build
27
+ built_at timestamp without time zone default (now() at time zone 'UTC'),
28
+
29
+ -- Build status
30
+ success boolean default false,-- True if the database built successfully
31
+
32
+ -- Durations
33
+ duration float,-- Duration of database build. Null if success is false
34
+ prick_duration float, -- Duration of the full prick command
35
+ make_duration float -- Duration of enclosing make script
16
36
  );
37
+
@@ -0,0 +1,6 @@
1
+ create view versions as
2
+ select *
3
+ from builds
4
+ where (select count(*) from builds) = 1
5
+ or built_at = (select max(built_at) from builds)
6
+