prick 0.33.0 → 0.35.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c38cab1d940acbbaf8c36dadfddd5ce8a003e45fd881c0af033ee16b9b1bcb9b
4
- data.tar.gz: c9c67dd1b746adf191a2193c536a7c2a97a962f5a7b70c371ecf42bb60621cec
3
+ metadata.gz: b8acf851da65b094d2abab5a6d9469f20a974732b9e8a8f5bbc4542f72bf8dae
4
+ data.tar.gz: d7ce7beb146b47aea6f25a93771b206a41434bd2ecbd3a1df33b8580374e29ea
5
5
  SHA512:
6
- metadata.gz: 7f81c8872d37f1b2f772c013c3fd1dad4f5936552aa8a6fa32b1b594d6da5ed20e06725590fd2a5317a8c9cda41b591845c6a68ec7ab4c2b82842b3fd2599c9c
7
- data.tar.gz: 17c08c190070820e63facc09a7411c8f90b43f7994a8a5eefc04baa2c7f0a9647ec562ce000d0677289d922f56c5eae410f68d0b323e8f177df122c1167b9fec
6
+ metadata.gz: b861e5129259bcb0dd384ba7e3c2db09c826cd50105ec514bda309268779e56458a99a3ef8ca1b83226accf7ce6569b957790e5c4374473a3cfb3700ba5ef380
7
+ data.tar.gz: 6c1b7227ffa63e49825f4acb503d855b9110f18224c1b3f2f7b27b72a92ac0eb3865ea8926470995a71988cb64ab9aa4a5bb26420adafd152364fd31ee28d23a
data/TODO CHANGED
@@ -1,3 +1,4 @@
1
+ o make it possible to build only one scheme
1
2
  o cleanup connection
2
3
  o make environment optional
3
4
  o eval vs exit
data/exe/prick CHANGED
@@ -119,20 +119,27 @@ SPEC = %(
119
119
 
120
120
  TODO
121
121
 
122
- build! -f,force -t,time --dump=KIND? -- [SCHEMA]
123
- Build the project. If SCHEMA is defined, later schemas are excluded.
124
- KIND can be 'nodes', 'allnodes' or 'batches' (the default).
122
+ build! --step -f,force -t,time --dump=KIND? -- [SCHEMA]
123
+ Build the project. If SCHEMA is defined, later schemas are excluded. KIND
124
+ can be 'nodes', 'allnodes' or 'batches' (the default). Schemas marked
125
+ with 'no refresh' is not built unless the --force is present
125
126
 
126
- Schemas marked with 'no refresh' is not built unless the --force is
127
- present
128
-
129
- make! -t,time --dump=KIND? -- [SCHEMA]
127
+ make! --step -t,time --dump=KIND? -- [SCHEMA]
130
128
  @ Only rebuild changed files
131
129
 
132
130
  Checks file timestamps against the time of the last build and only
133
131
  rebuild affected parts of the project. KIND can be 'nodes', 'allnodes' or
134
132
  'batches' (the default)
135
133
 
134
+ run! --step -t,time --dump=KIND? --schema=SCHEMA -- PATH
135
+ @ Execute path in Prick environment
136
+
137
+ Execute a single directory or file within the Prick environment. If given
138
+ a directory argument, the directory is searched for a build.yml file. If
139
+ given a file argument, the file should be a .sql, .fox, or build file
140
+
141
+ The --schema option sets the current schema before executing the PATH
142
+
136
143
  bash! --main
137
144
  Emit a bash script to build the database. The script is constructed from
138
145
  the build attributes in the environment file
@@ -354,12 +361,22 @@ begin
354
361
  dump = cmd.dump? ? cmd.dump("batches")&.to_sym || :batches : nil
355
362
  # exclude = cmd.exclude? ? cmd.exclude.split(",") : []
356
363
  Prick::SubCommand.build(
357
- database, username, args.expect(0..1), force: cmd.force?, timer: cmd.time?, dump: dump)
364
+ database, username, args.expect(0..1),
365
+ force: cmd.force?, step: cmd.step?, timer: cmd.time?, dump: dump)
358
366
 
359
367
  when :make!
360
368
  require_db
361
369
  dump = cmd.dump? ? cmd.dump("batches")&.to_sym || :batches : nil
362
- Prick::SubCommand.make(database, username, args.expect(0..1), timer: cmd.time?, dump: dump)
370
+ Prick::SubCommand.make(
371
+ database, username, args.expect(0..1),
372
+ step: cmd.step?, timer: cmd.time?, dump: dump)
373
+
374
+ when :run!
375
+ require_db
376
+ dump = cmd.dump? ? cmd.dump("batches")&.to_sym || :batches : nil
377
+ Prick::SubCommand.run(
378
+ database, username, args.expect(1),
379
+ step: cmd.step?, timer: cmd.time?, dump: dump, schema: cmd.schema)
363
380
 
364
381
  when :bash!
365
382
  Prick::SubCommand.bash(main: cmd.main?)
@@ -479,7 +496,8 @@ rescue ShellOpts::Error, Prick::Error => ex
479
496
  raise
480
497
  ShellOpts.error(ex.message)
481
498
 
482
- rescue RuntimeError, IOError, ShellOpts::Failure, Prick::Failure, Prick::Build::PostgresError => ex
483
- ShellOpts.failure(ex.message)
499
+ # FIXME
500
+ #rescue RuntimeError, IOError, ShellOpts::Failure, Prick::Failure, Prick::Build::PostgresError => ex
501
+ # ShellOpts.failure(ex.message)
484
502
  end
485
503
 
@@ -28,7 +28,8 @@ module Prick
28
28
  end
29
29
 
30
30
  class SqlBatch < BuildBatch
31
- def execute(step: true) # This is marginally faster!
31
+ def execute
32
+ # puts "#execute"
32
33
  super {
33
34
  begin
34
35
  sql = []
@@ -41,22 +42,16 @@ module Prick
41
42
  sql = [node.source]
42
43
  end
43
44
 
44
- if step
45
- conn.execute sql, silent: true if !sql.empty?
46
- for node in nodes
47
- conn.execute node.source, silent: true
48
- end
49
- else
50
- node = nil
51
- conn.execute sql + nodes[sql.size..-1].map(&:source), silent: true
45
+ conn.execute sql, silent: true if !sql.empty?
46
+ for node in nodes # This is marginally faster than concatenating all nodes
47
+ # puts node.source
48
+ conn.execute node.source, silent: true
52
49
  end
53
50
 
54
51
  rescue PG::Error => ex
55
52
  error, line, char = conn.err
56
53
  file = nil
57
- if step
58
- ;
59
- elsif line
54
+ if line
60
55
  # Locate error node and make line number relative
61
56
  if line < nodes.first.lines
62
57
  node = nodes.first
@@ -81,6 +76,7 @@ module Prick
81
76
  elsif node
82
77
  message = "#{error} from #{node.path}"
83
78
  else
79
+ raise ArgumentError, "Oops"
84
80
  message = conn.errmsg + " in SQL batch"
85
81
  end
86
82
  raise PostgresError.new(message, file, line, char)
@@ -27,9 +27,12 @@ module Prick
27
27
  # PgConn object
28
28
  attr_reader :conn
29
29
 
30
- # Root schema directory
30
+ # Schema directory
31
31
  attr_reader :dir
32
32
 
33
+ # Path to file or directory
34
+ attr_reader :path
35
+
33
36
  # Reflections YAML file
34
37
  attr_reader :reflections_file
35
38
 
@@ -39,6 +42,12 @@ module Prick
39
42
  # Root build node
40
43
  attr_reader :root
41
44
 
45
+ # True if this is a single-file build
46
+ attr_reader :single
47
+
48
+ # True if SQL entries should be single-stepped. Default false
49
+ attr_reader :step
50
+
42
51
  # Pool of nodes. Initialized by #load_pool
43
52
  attr_reader :pool
44
53
 
@@ -49,21 +58,31 @@ module Prick
49
58
  :pg_graph_ignore_schemas,
50
59
  :refresh_schemas, :keep_schemas
51
60
 
52
- def batches() @batches ||= group end
61
+ def batches() @batches || create_batches end
62
+
63
+ def initialize(conn, path, clean = true, single: false, touched: false, load_pool: true, step: false)
64
+ File.exist?(path) or raise Error, "Can't find #{path}"
65
+ single || File.directory?(path) or raise Error, "Can't find directory #{path}"
53
66
 
54
- def initialize(conn, dir, clean = true, touched: false)
55
67
  @conn = conn
56
- @dir = dir
68
+ @path = path
57
69
  @reflections_file = REFLECTIONS_PATH
58
70
  @clean = clean
71
+ @single = single
72
+ @step = step
73
+ @root = Parser.parse(conn, path, single: single)
74
+ @pool = nil # Initialized by #load_pool
75
+ @batches = nil # Initialized by #create_batches
76
+ self.load_pool if load_pool
77
+ end
78
+
79
+ def load_pool
59
80
  @pool = NodePool.new
60
- @root = Parser.parse(conn, dir)
61
- load_pool(@root) # Collect nodes into pool
62
- @batches = nil # Initialized by #group
81
+ load_pool_impl(@root)
63
82
  end
64
83
 
65
84
  # Group sources into batches
66
- def group
85
+ def create_batches
67
86
  @batches = []
68
87
  kind = nil
69
88
  batch = nil
@@ -78,8 +97,11 @@ module Prick
78
97
  when :exe # Exe sources always create a new batch
79
98
  @batches << batch if batch
80
99
  batch = SqlBatch.new(self)
81
- when batch&.kind
82
- ;
100
+ when batch&.kind # Same kind as current batch
101
+ if node.kind == :sql && step
102
+ @batches << batch if batch
103
+ batch = SqlBatch.new(self)
104
+ end
83
105
  when :sql || node.kind == :inline
84
106
  if batch&.kind != :exe
85
107
  @batches << batch if batch
@@ -98,22 +120,30 @@ module Prick
98
120
  end
99
121
  batch.nodes << node
100
122
  end
101
-
102
123
  @batches << batch if batch
124
+
125
+ @batches
103
126
  end
104
127
 
105
128
  def execute(conn, create_schemas: schemas)
129
+ # Load pool
130
+ load_pool if pool.nil?
131
+
106
132
  # Group batches
107
- group if batches.nil?
133
+ create_batches if batches.nil?
108
134
 
109
135
  # Register build in database
110
136
  Prick.state.save_build_begin
111
137
 
112
138
  # Create schemas
113
- conn.exec create_schemas.map { |schema| "create schema #{schema}" }
139
+ conn.exec create_schemas.map { |schema| "create schema #{schema}" } if !single
114
140
 
115
141
  # Execute batch groups
116
142
  t0 = Time.now
143
+ # for batch in batches
144
+ # puts "Executing #{batch.class} batch"
145
+ # batch.execute
146
+ # end
117
147
  batches.each(&:execute)
118
148
  t1 = Time.now
119
149
 
@@ -123,15 +153,16 @@ module Prick
123
153
  end
124
154
 
125
155
  def dump
156
+ load_pool if pool.nil?
126
157
  batches ? batches.each(&:dump) : pool.dump
127
158
  end
128
159
 
129
160
  private
130
- def load_pool(build_node)
161
+ def load_pool_impl(build_node)
131
162
  pool.add(build_node.init_nodes)
132
163
  build_node.decl_nodes.each { |node|
133
164
  pool.add node
134
- load_pool(node) if node.kind == :yml
165
+ load_pool_impl(node) if node.kind == :yml
135
166
  }
136
167
  pool.add(build_node.seed_nodes)
137
168
  pool.add(build_node.term_nodes)
@@ -10,6 +10,8 @@ module Prick
10
10
 
11
11
  def name() @name = File.basename(path) end
12
12
 
13
+ # Note that schema defaults to 'public' which may not be what you want in
14
+ # some cases
13
15
  def schema() @schema ||= parent&.schema || "public" end
14
16
  def schema=(s) @schema = s end
15
17
 
@@ -36,6 +38,7 @@ module Prick
36
38
  constrain path, String, NilClass
37
39
  @parent, @phase, @kind, @path = parent, phase, kind, path
38
40
  @args = args&.empty? ? nil : args
41
+ @has_schema = false
39
42
  @schema = nil
40
43
  @source = nil
41
44
  @source_lines = nil
@@ -43,7 +46,7 @@ module Prick
43
46
 
44
47
  def to_s() @to_s ||= [path, args].compact.join(" ") end
45
48
  def inspect() to_s end
46
- def dump() puts "#{inspect} (#{schema})" end
49
+ def dump() puts "#{inspect} (#{@schema || 'nil'})" end
47
50
 
48
51
  protected
49
52
  def read_source
@@ -162,6 +165,9 @@ module Prick
162
165
 
163
166
  # A build.yml file node
164
167
  class BuildNode < Node
168
+ # True if the build file contains a 'schema' attribute
169
+ attr_accessor :has_schema
170
+
165
171
  def nodes() @nodes ||= init_nodes + decl_nodes + seed_nodes + term_nodes end
166
172
 
167
173
  attr_reader :decl_nodes
@@ -187,7 +193,8 @@ module Prick
187
193
  def dump
188
194
  puts "BuildNode #{path}"
189
195
  indent {
190
- puts "schema: #{schema}" if schema
196
+ puts "has_schema: #{has_schema}"
197
+ puts "schema: #{@schema || 'nil'}"
191
198
  puts "refresh: #{refresh_schema.to_s}"
192
199
  puts "pg_graph_ignore_schema: #{pg_graph_ignore_schema}"
193
200
  decl_nodes.each(&:dump)
@@ -1,30 +1,30 @@
1
1
  module Prick
2
2
  module Build
3
3
  class Parser
4
- def self.parse(conn, dir)
5
- Parser.new(conn).parse(dir).unit
6
- # [parser.unit, parser.schemas]
4
+ def self.parse(conn, path, single: true)
5
+ Parser.new(conn).parse(path, single: single).unit
7
6
  end
8
7
 
9
8
  attr_reader :conn
10
- attr_reader :dir
11
9
  attr_reader :unit # The singular RootBuildNode object
12
- # attr_reader :schemas
13
10
 
14
11
  def initialize(conn)
15
12
  @conn = conn
16
13
  @unit = nil
17
14
  end
18
15
 
19
- def parse(dir)
20
- @dir = dir
21
- # @schemas = {}
22
- parse_directory(nil, dir)
16
+ # Return a RootBuildNode object. #path can be a file or a directory
17
+ def parse(path, single: false)
18
+ File.exist?(path) or raise Error, "Can't find #{path}"
19
+ if single
20
+ parse_path(path)
21
+ else
22
+ parse_directory(nil, path)
23
+ end
23
24
  self
24
25
  end
25
26
 
26
27
  private
27
-
28
28
  # First built unit is a RootBuildNode, the rest are regular BuildNode objects
29
29
  def make_build_unit(parent, path)
30
30
  if @unit
@@ -34,47 +34,14 @@ module Prick
34
34
  end
35
35
  end
36
36
 
37
- # Search for an executable in path. Return nil if not found
38
- def find_executable(filename) # ChatGPT
39
- Prick.state.executable_search_path.split(File::PATH_SEPARATOR).each do |directory|
40
- path = File.join(directory, filename)
41
- return path if File.executable?(path)
42
- end
43
- nil
44
- end
45
-
46
- # Expand environments variables file name. Iterates through inherited
47
- # environments if the file name contain the $ENVIRONMENT variable. Return
48
- # nil if not found
49
- #
50
- # The hierarchy of environments is defined in the PRICK_ENVIRONMENT_FILE
51
- #
52
- def expand_filename(dir, filename)
53
- envs = Prick.state.environments
54
- env = envs[Prick.state.environment]
55
- bash_vars = Prick.state.bash_environment
56
-
57
- last = nil
58
- for env in [env] + env.ancestors.reverse
59
- bash_vars["ENVIRONMENT"] = env.name
60
- file = expand_variables(filename, bash_vars)
61
- last ||= (file != last and file) or return nil # return if no ENVIRONMENT substitution
62
- path = (file.start_with?("/") ? file : File.join(dir, file))
63
-
64
- # Check for file (may be executable)
65
- return path if File.exist?(path)
66
-
67
- # Check for executable in search path
68
- path = find_executable(file) and return path if file !~ /\//
69
- end
70
-
71
- # Return nil if not found
72
- return nil
73
- end
74
-
75
- # Expand $ENVIRONMENT variable
76
- def expand_string(string)
77
- expand_variables(string, Prick.state.bash_environment)
37
+ def parse_path(path, schema: nil)
38
+ File.exist?(path) or raise Error, "Can't find #{file}"
39
+ dir = File.dirname(path)
40
+ file = File.basename(path)
41
+ unit = make_build_unit(nil, nil)
42
+ unit.schema = schema if schema
43
+ entry = parse_build_entry(unit, dir, file)
44
+ unit
78
45
  end
79
46
 
80
47
  def parse_directory(parent, dir)
@@ -82,7 +49,7 @@ module Prick
82
49
  if File.exist? build_file
83
50
  parse_build_file(parent, dir, build_file)
84
51
  else
85
- raise Error, "Can't find build.yml in #{dir}"
52
+ raise Error, "Can't find build.yml in #{dir} while parsing #{parent}"
86
53
  end
87
54
  end
88
55
 
@@ -94,6 +61,7 @@ module Prick
94
61
  entry.each { |key, value|
95
62
  if key == "schema"
96
63
  unit.schema = value
64
+ unit.has_schema = true
97
65
  elsif key == "standard"
98
66
  unit.pg_graph_ignore_schema = !value
99
67
  elsif key == "refresh"
@@ -109,17 +77,22 @@ module Prick
109
77
  end
110
78
  }
111
79
  else
112
- node = parse_entry(unit, :decl, dir, entry) or next
113
- if node.kind == :fox
114
- unit.seed_nodes << node
115
- else
116
- unit.decl_nodes << node
117
- end
80
+ parse_build_entry(unit, dir, entry)
118
81
  end
119
82
  }
120
83
  unit
121
84
  end
122
85
 
86
+ def parse_build_entry(unit, dir, file)
87
+ node = parse_entry(unit, :decl, dir, file) or return nil
88
+ if node.kind == :fox
89
+ unit.seed_nodes << node
90
+ else
91
+ unit.decl_nodes << node
92
+ end
93
+ node
94
+ end
95
+
123
96
  # Returns path, filename, and an array of arguments. It is an error if
124
97
  # the file can't be found unless #optional is true. In that case a nil
125
98
  # value is returned
@@ -132,7 +105,7 @@ module Prick
132
105
  args = expand_string(rest || '').split
133
106
  path = expand_filename(dir, command)
134
107
  path || optional or
135
- raise Error, "Can't find file\n #{command}\n #{path}\n in #{dir}/\n from #{unit}"
108
+ raise Error, "Can't find file #{command} #{path} in #{dir}/ from #{unit}"
136
109
  !path.nil? or return nil
137
110
  else
138
111
  raise Error, "Not a file name: '#{entry}'"
@@ -141,6 +114,7 @@ module Prick
141
114
  end
142
115
 
143
116
  def parse_entry(unit, phase, dir, entry)
117
+ # puts "#parse_entry(#{unit.inspect}, #{phase.inspect}, #{dir.inspect}, #{entry.inspect})"
144
118
  if entry.is_a?(Hash)
145
119
  entry.size == 1 or raise Error, "sql and module are single-line values"
146
120
  key, value = entry.first
@@ -175,7 +149,9 @@ module Prick
175
149
  SqlNode.new(unit, phase, path)
176
150
  when /\.fox$/
177
151
  FoxNode.new(unit, :seed, path)
178
- when /build-.*\.yml$/
152
+ when /(?:^|\/)build-.*\.yml$/
153
+ parse_build_file(unit, dir, path)
154
+ when /(?:^|\/)build.yml$/ # Only used when building a single file
179
155
  parse_build_file(unit, dir, path)
180
156
  else
181
157
  raise Error, "Expected executable, fox, or sql file: #{File.basename(path)} in #{dir}"
@@ -185,6 +161,56 @@ module Prick
185
161
  end
186
162
  end
187
163
  end
164
+
165
+ # Search for an executable in path. Return nil if not found
166
+ #
167
+ # Note that "." is ignored in the search path
168
+ def find_executable(filename) # ChatGPT
169
+ Prick.state.executable_search_path.split(File::PATH_SEPARATOR).each do |directory|
170
+ next if directory == "."
171
+ path = File.join(directory, filename)
172
+ return path if File.file?(path) && File.executable?(path)
173
+ end
174
+ nil
175
+ end
176
+
177
+ # Expand environment variables in the given file name
178
+ #
179
+ # #expend_filename substitute '$<variable>' expressions in the filename
180
+ # with the corresponding value in the current environment. If the file
181
+ # was not found, inherited environments are processed hierarchly with the
182
+ # special environment variable ENVIRONMENT set to each PRICK_ENVIRONMENT
183
+ # value in the inherited environments
184
+ #
185
+ # Return the resulting path to the file and nil if not found
186
+ #
187
+ def expand_filename(dir, filename)
188
+ envs = Prick.state.environments
189
+ env = envs[Prick.state.environment]
190
+ bash_vars = Prick.state.bash_environment.dup
191
+
192
+ last = nil
193
+ for env in [env] + env.ancestors.reverse
194
+ bash_vars["ENVIRONMENT"] = env.name
195
+ file = expand_variables(filename, bash_vars)
196
+ # last ||= (file != last and file) or return nil # return if no ENVIRONMENT substitution
197
+ path = (file.start_with?("/") ? file : File.join(dir, file))
198
+
199
+ # Check for file (may be executable)
200
+ return path if File.exist?(path)
201
+
202
+ # Check for executable in search path if file doesn't contain a '/'
203
+ path = find_executable(file) and return path if file !~ /\//
204
+ end
205
+
206
+ # Return nil if not found
207
+ return nil
208
+ end
209
+
210
+ # Expand $ENVIRONMENT variable
211
+ def expand_string(string)
212
+ expand_variables(string, Prick.state.bash_environment)
213
+ end
188
214
  end
189
215
  end
190
216
  end
@@ -245,13 +245,12 @@ module Prick
245
245
  case types[ident]
246
246
  when "BOOLEAN"
247
247
  [TrueClass, FalseClass].include?(value.class) or raise "Illegal value for #{ident}: #{value}"
248
- ;
249
248
  when "STRING"
250
249
  ; # nop
251
250
  when "LIST"
252
251
  value = value&.split || []
253
252
  when "TEXT"
254
- value = value.chomp
253
+ value = (value == false ? "false" : value.chomp)
255
254
  when nil
256
255
  ShellOpts.error "Unknown variable '#{ident}'"
257
256
  else
data/lib/prick/state.rb CHANGED
@@ -14,6 +14,9 @@ module Prick
14
14
  # directory through the -C option or the 'init' command
15
15
  def prick_dir() @prick_dir ||= Dir.getwd end
16
16
 
17
+ # Prick schema dir
18
+ def schema_dir() @schema_dir ||= File.join(prick_dir, SCHEMA_DIR) end
19
+
17
20
  # Project file. Default 'prick.yml'
18
21
  attr_reader :project_file
19
22
 
@@ -186,7 +189,7 @@ module Prick
186
189
  hash.merge!({
187
190
  "DATABASE" => Prick.state.database, # FIXME: Yt
188
191
  "USERNAME" => Prick.state.username, # FIXME: Yt
189
- "ENVIRONMENT" => Prick.state.environment.to_s, # FIXME: Yt
192
+ "ENVIRONMENT" => Prick.state.environment.to_s, # FIXME: Yt except in build.yml parser
190
193
  "PRICK_NAME" => Prick.state.name,
191
194
  "PRICK_TITLE" => Prick.state.title,
192
195
  "PRICK_VERSION" => Prick.state.version,
@@ -5,8 +5,9 @@ require_relative '../builder/builder.rb'
5
5
  module Prick::SubCommand
6
6
  def self.build(
7
7
  database, username, schema,
8
- builddir: "schema", force: false,
9
- timer: nil, dump: nil)
8
+ builddir: Prick.state.schema_dir,
9
+ force: false, # Build all schemas
10
+ step: false, timer: nil, dump: nil)
10
11
 
11
12
  Timer.on! if timer
12
13
 
@@ -29,7 +30,7 @@ module Prick::SubCommand
29
30
  end
30
31
  conn = Prick.state.connection
31
32
 
32
- builder = Prick::Build::Builder.new(conn, builddir)
33
+ builder = Prick::Build::Builder.new(conn, builddir, step: step)
33
34
 
34
35
  if exist # Empty (part of) the database
35
36
  if force
@@ -49,8 +50,8 @@ module Prick::SubCommand
49
50
  # Remove keep-schemas from list of schemas
50
51
  refresh_schemas -= keep_schemas
51
52
 
52
- # Also remove keep-schemas from the build pool. Why don't we use
53
- # the pool tracker's list of keep schemas?
53
+ # Also remove keep-schemas from the build pool. TODO Why don't we
54
+ # use the pool tracker's list of keep schemas?
54
55
  builder.pool.delete_schema(keep_schemas)
55
56
 
56
57
  # Drop refresh schemes
@@ -3,9 +3,9 @@
3
3
  require_relative '../builder/builder.rb'
4
4
 
5
5
  module Prick::SubCommand
6
- def self.make(database, username, schema, timer: nil, dump: nil)
6
+ def self.make(database, username, schema, step: false, timer: nil, dump: nil)
7
7
  Timer.on! if timer
8
- time "Prick::Command#make" do
8
+ Timer.time "Prick::Command#make" do
9
9
  begin
10
10
  super_conn = State.connection
11
11
  conn = nil
@@ -14,7 +14,7 @@ module Prick::SubCommand
14
14
  clean = false
15
15
  create_schemas = []
16
16
 
17
- time "Load build object" do
17
+ Timer.time "Load build object" do
18
18
  if super_conn.rdbms.exist? database
19
19
  conn = Prick.state.connection
20
20
  if conn.schema.exist_relation?("prick", "versions") && !conn.empty?("prick.versions")
@@ -26,7 +26,7 @@ module Prick::SubCommand
26
26
  clean = true
27
27
  end
28
28
 
29
- builder = Prick::Build::Builder.new(conn, "schema", clean)
29
+ builder = Prick::Build::Builder.new(conn, "schema", clean, step: step)
30
30
 
31
31
  if schema
32
32
  after_schemas = builder.pool.after_schema(schema)
@@ -43,7 +43,7 @@ module Prick::SubCommand
43
43
  after_schemas.each { |delete_schema| builder.pool.delete_schema(delete_schema) }
44
44
  end
45
45
 
46
- touched_nodes = builder.nodes.select { |node| File.mtime(node.path) > last_built_at }
46
+ touched_nodes = builder.nodes.select { |node| last_built_at.nil? || File.mtime(node.path) > last_built_at }
47
47
  touched_phases = touched_nodes.map(&:phase).uniq.compact
48
48
  touched_kinds = touched_nodes.map(&:kind).uniq.compact
49
49
  touched_schema = touched_nodes.first&.schema
@@ -78,7 +78,7 @@ module Prick::SubCommand
78
78
  end
79
79
  exit if dump
80
80
 
81
- time "Execute build object" do
81
+ Timer.time "Execute build object" do
82
82
  builder.execute(conn, create_schemas: create_schemas)
83
83
  end
84
84
 
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../builder/builder.rb'
4
+
5
+ module Prick::SubCommand
6
+ def self.run(database, username, path, step: false, timer: nil, dump: nil, schema: nil)
7
+
8
+ Timer.on! if timer
9
+
10
+ Timer.time "Prick::Command#build" do
11
+ begin
12
+ super_conn = State.connection # Used to create new databases (doesn't make a
13
+ # difference right now as the database user is
14
+ # a superuser anyway
15
+ conn = nil
16
+ builder = nil
17
+
18
+ constrain super_conn.rdbms.exist?(database), true # FIXME Same problem as below. Also in other commands
19
+
20
+ Timer.time "Load build object" do
21
+ if super_conn.rdbms.exist? database # FIXME Why create database? Setup should have done this
22
+ exist = true
23
+ else
24
+ super_conn.rdbms.create database, owner: username
25
+ exist = false
26
+ end
27
+ conn = Prick.state.connection
28
+
29
+ # Parse
30
+ builder = Prick::Build::Builder.new(conn, path, single: true, load_pool: false, step: step)
31
+
32
+ # Register if a build file is referenced and normalize path to
33
+ # include build.yml of directories
34
+ if File.directory?(path)
35
+ path = File.join(path, "build.yml")
36
+ is_build_file = true
37
+ elsif File.basename(path) == "build.yml"
38
+ is_build_file = true
39
+ else
40
+ is_build_file = false
41
+ end
42
+
43
+ # Read schema from build file if possible and decide if schema should
44
+ # be dropped beforehand
45
+ if is_build_file
46
+ if builder.root.has_schema
47
+ !schema or Prick.error "Can't use --schema when doing a schema build"
48
+ is_schema_rebuild = true
49
+ schema = build_node.schema
50
+ else
51
+ is_schema_rebuild = false
52
+ end
53
+ else
54
+ is_schema_rebuild = false
55
+ end
56
+
57
+ # Infer schema from path
58
+ if !schema
59
+ abspath = File.realpath(path)
60
+ schemapath = File.realpath(Prick.state.schema_dir)
61
+ if abspath =~ /^#{schemapath}\/([^\/]+)(?:\/.*)$/
62
+ schema = $1
63
+ else
64
+ Prick.error "Can't find schema" # No default schema to avoid unintended runs
65
+ end
66
+ end
67
+
68
+ # Write-back schema to builder
69
+ builder.root.schema = schema
70
+
71
+ # Drop schema if needed
72
+ if is_schema_rebuild
73
+ conn.schema.drop schema, cascade: true
74
+ end
75
+
76
+ # Create schema if absent
77
+ if !conn.schema.exist?(schema)
78
+ conn.schema.create(schema)
79
+ end
80
+ end
81
+
82
+ if dump
83
+ builder.load_pool
84
+ case dump
85
+ when :nodes; builder.nodes.reject { |node| node.is_a?(Build::BuildNode) }.map &:dump
86
+ when :allnodes; builder.nodes.map &:dump
87
+ when :batches; builder.dump
88
+ else
89
+ Prick.error "Illegal dump type: #{dump.inspect}"
90
+ end
91
+ else
92
+ Timer.time "Execute build object" do
93
+ builder.execute conn
94
+ end
95
+ end
96
+
97
+ # FIXME
98
+ # rescue Prick::Error => ex
99
+ # $stderr.puts ex.message
100
+ # exit 1
101
+ #
102
+ # rescue ::Command::Error => ex
103
+ # $stderr.puts ex.message
104
+ # exit 1
105
+
106
+ ensure
107
+ super_conn&.terminate
108
+ conn&.terminate
109
+ end
110
+ end
111
+ end
112
+ end
113
+
data/lib/prick/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Prick
4
- VERSION = "0.33.0"
4
+ VERSION = "0.35.0"
5
5
  end
data/lib/prick.rb CHANGED
@@ -50,6 +50,7 @@ require_relative 'prick/subcommand/prick-list.rb'
50
50
  require_relative 'prick/subcommand/prick-make.rb'
51
51
  require_relative 'prick/subcommand/prick-migrate.rb'
52
52
  require_relative 'prick/subcommand/prick-release.rb'
53
+ require_relative 'prick/subcommand/prick-run.rb'
53
54
  require_relative 'prick/subcommand/prick-set.rb'
54
55
  require_relative 'prick/subcommand/prick-setup.rb'
55
56
  require_relative 'prick/subcommand/prick-teardown.rb'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prick
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.33.0
4
+ version: 0.35.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Claus Rasmussen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-04-23 00:00:00.000000000 Z
11
+ date: 2024-04-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: semantic
@@ -230,6 +230,7 @@ files:
230
230
  - lib/prick/subcommand/prick-make.rb
231
231
  - lib/prick/subcommand/prick-migrate.rb
232
232
  - lib/prick/subcommand/prick-release.rb
233
+ - lib/prick/subcommand/prick-run.rb
233
234
  - lib/prick/subcommand/prick-set.rb
234
235
  - lib/prick/subcommand/prick-setup.rb
235
236
  - lib/prick/subcommand/prick-teardown.rb