prick 0.18.0 → 0.19.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 22580f7a2f37e4ad59c6354e3b6ac1d7bb6f5eb7fe8f44eddb941ba715f8fa39
4
- data.tar.gz: b0b5bf43389a0e35c6a739b92b4e50b043cb75ab1e215aa109a9a68e4f17e1e3
3
+ metadata.gz: 75523a625d7139830b419f2624f96af3c029dc1ad89b0cb40dec289f4b94b522
4
+ data.tar.gz: 450c53de9ef6b3c8627df7471076b87c559f367d7aef30e009a846bffa98390c
5
5
  SHA512:
6
- metadata.gz: 7768a47145ae07f6ae99e808ad513107ccd98327fc009311cd0bfde1f1dbd3a52a3d9f5061c6bb3918b12da6850b0cf4e5242efade679d950a603047c8dd9cfc
7
- data.tar.gz: e2709800fe62d599bba1ea64960b4a09e8a97a87da3d60731e8293f4957c9ac35147122dea16220481b9c49b17d3cf31377663f1328b99608c0fc3cc84ca4ad9
6
+ metadata.gz: 98b24c53c2ae54007c46cb4157963ba049327e6ea9b73c5b6b8502367e58d9d018acdb74c9896394bd90a0335359719c0e02523f1e2965de1ed31c023285eeb9
7
+ data.tar.gz: 25b7425c7f8547bdd0be1ee0a570b1b6115f08ff2ba3bd8c8284cced0ffc5da1ecbc0670e57bb21d2b9a45276df03d0f2f3210b83712ff50f55f811991ba11e3
data/exe/prick CHANGED
@@ -10,6 +10,7 @@ require 'tempfile'
10
10
  include ShellOpts
11
11
  include Prick
12
12
 
13
+
13
14
  SPEC = %(
14
15
  -n,name=NAME
15
16
  Name of project. Defauls to the environment variable `PRICK_PROJECT` if
@@ -51,11 +52,13 @@ SPEC = %(
51
52
  list.cache!
52
53
  List cache files
53
54
 
54
- build! -d,database=DATABASE -C,no-cache [TAG]
55
- Build the current database from the content in the schemas/ directory.
56
- With a tag the version is built into the associated versioned database
57
- and the result is saved to cache unless the -C option is given. The -d
58
- option overrides the default database
55
+ build! -d,database=DATABASE -s,state=FILE -C,no-cache [TAG]
56
+ Drop all users associated with the database before building the current
57
+ database from the content in the schemas/ directory. With a tag the
58
+ version is built into the associated versioned database and the result is
59
+ saved to cache unless the -C option is given. The -d option overrides the
60
+ default database and the -s option overrides the default state file
61
+ (fox.state)
59
62
 
60
63
  make! -d,database=DATABASE -C,no-cache [TAG]
61
64
  Build the current database from the content in the schemas/ directory.
@@ -77,8 +80,12 @@ SPEC = %(
77
80
  given file
78
81
 
79
82
  drop! -a,all [DATABASE]
80
- Drop the given database or all versioned databases. The --all option also
81
- drops the project database
83
+ Drop the given database or all versioned databases. Users with a username
84
+ on the form <database>__<username> are also dropped. The --all option
85
+ also drops the project database
86
+
87
+ drop.users! [DATABASE]
88
+ Drop users with a username on the form <database>__<username>
82
89
 
83
90
  diff! -m,mark -t,tables -T,notables
84
91
  diff [FROM-DATABASE|FROM-VERSION [TO-DATABASE|TO-VERSION]]
@@ -153,7 +160,7 @@ SPEC = %(
153
160
  in the var/spool directory
154
161
  )
155
162
 
156
-
163
+ DEFAULT_STATE_FILE = "fox.state"
157
164
 
158
165
  opts, args = ShellOpts.process(SPEC, ARGV)
159
166
 
@@ -185,6 +192,7 @@ begin
185
192
 
186
193
  # Create program object
187
194
  program = Program.new(quiet: opts.quiet?, verbose: opts.verbose?)
195
+ $verbose = opts.verbose? ? opts.verbose : nil
188
196
 
189
197
  # Handle init command
190
198
  if opts.subcommand == :init
@@ -236,7 +244,9 @@ begin
236
244
 
237
245
  when :build
238
246
  version = args.expect(0..1)
239
- program.build(opts.build!.database, version, opts.build!.no_cache?)
247
+ state_file = File.expand_path(opts.build!.state || DEFAULT_STATE_FILE)
248
+ FileUtils.rm_f(state_file)
249
+ program.build(opts.build!.database, version, state_file, opts.build!.no_cache?)
240
250
 
241
251
  when :make
242
252
  command = opts.make!
@@ -258,7 +268,15 @@ begin
258
268
  program.save(version, file)
259
269
 
260
270
  when :drop
261
- program.drop(args.expect(0..1), opts.drop!.all?)
271
+ command = opts.drop!
272
+ case command.subcommand
273
+ when :users
274
+ database = args.extract(0..1) || program.project.database.name
275
+ args.expect(0)
276
+ program.drop_users(database)
277
+ else
278
+ program.drop(args.expect(0..1), opts.drop!.all?)
279
+ end
262
280
 
263
281
  when :diff
264
282
  mark = opts.diff!.mark
data/lib/prick/branch.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  require "prick/state.rb"
2
2
 
3
+ # FIXME FIXME FIXME Not used!
4
+
5
+
3
6
  module Prick
4
7
  class Branch
5
8
  # Branch name. It is usually equal to the version but migrations use a
@@ -116,6 +119,14 @@ module Prick
116
119
  end
117
120
  end
118
121
 
122
+ # A user defined branch. User defined branches have no version and only the
123
+ # #build method is defined TODO: Make all methods but #build private
124
+ class UserBranch < Branch
125
+ def initialize(name)
126
+ super(name, nil, nil, nil, nil)
127
+ end
128
+ end
129
+
119
130
  class AbstractRelease < Branch
120
131
  def create(schema_version = self.version)
121
132
  super()
data/lib/prick/builder.rb CHANGED
@@ -1,20 +1,23 @@
1
1
  require "prick/state.rb"
2
2
 
3
+ require 'indented_io'
4
+
3
5
  module Prick
4
6
  # Builder is a procedural object for building schemas and executing
5
7
  # migrations. Builder use resources that can be executables, SQL files, YAML
6
- # files, or directories. A resource is identified by a name (eg. 'my-tables')
7
- # and is used to match a build file. Build files are looked up in the
8
- # following order:
8
+ # files, FOX files, or directories. A resource is identified by a name (eg.
9
+ # 'my-tables') and is used to match a build file. Build files are looked up
10
+ # in the following order:
9
11
  #
10
12
  # #{name} executable
11
13
  # #{name}.* executable
12
14
  # #{name}.yml
13
15
  # #{name}.sql
16
+ # #{name}.fox
14
17
  # #{name}/
15
18
  #
16
19
  # The output from executable objects is expected to be SQL statements that
17
- # are fed into postgres
20
+ # are then fed into postgres
18
21
  #
19
22
  # When a resource match a directory, the directory can contain a special
20
23
  # default resource ('build' or 'migrate') that takes over the rest of the
@@ -23,8 +26,8 @@ module Prick
23
26
  # directory doesn't contain a build resource, the resources in the directory
24
27
  # are built in alphabetic order
25
28
  #
26
- # Build (but not migration) SQL scripts and executables are executed with
27
- # search path set to containing schema
29
+ # Build SQL scripts and executables are executed with search path set to
30
+ # containing schema. This doesn't include migration script or executable
28
31
  #
29
32
  class Builder
30
33
  attr_reader :database
@@ -32,6 +35,11 @@ module Prick
32
35
  attr_reader :default # either "build" or "migrate"
33
36
  attr_reader :lines
34
37
 
38
+ def state_file() self.class.state_file end
39
+ def state_file=(file) self.class.state_file = file end
40
+ def self.state_file() @@state_file end
41
+ def self.state_file=(file) @@state_file = file end
42
+
35
43
  def initialize(database, directory, default)
36
44
  @database = database
37
45
  @directory = directory
@@ -42,9 +50,9 @@ module Prick
42
50
  end
43
51
 
44
52
  def build(subject = default, execute: true)
53
+ puts "build(#{subject.inspect}, execute: #{execute.inspect})" if $verbose > 0
45
54
  @execute = execute
46
55
  @lines = []
47
- # puts "Building #{subject.inspect}"
48
56
  Dir.chdir(directory) {
49
57
  if subject
50
58
  build_subject(subject)
@@ -59,15 +67,23 @@ module Prick
59
67
  def self.yml_file(directory) raise NotThis end
60
68
 
61
69
  protected
62
- def do_dir(path, &block)
63
- # puts "do_dir(#{path.inspect})"
64
- dir, file = File.split(path)
65
- Dir.chdir(dir) { yield(file) }
70
+ def do_path(path, &block)
71
+ puts "do_path(#{path.inspect})" if $verbose >= 3
72
+ if File.directory?(path)
73
+ dir, file = path, nil
74
+ else
75
+ dir, file = File.split(path)
76
+ end
77
+ if $verbose >= 2
78
+ indent { Dir.chdir(dir) { yield(file) } }
79
+ else
80
+ Dir.chdir(dir) { yield(file) }
81
+ end
66
82
  end
67
83
 
68
84
  def do_sql(path, schema: nil)
69
- # puts "do_sql(#{path})"
70
- do_dir(path) { |file|
85
+ puts "do_sql(#{path})" if $verbose >= 2
86
+ do_path(path) { |file|
71
87
  if @execute
72
88
  begin
73
89
  Rdbms.exec_file(database.name, file, user: database.user, schema: schema)
@@ -83,11 +99,29 @@ module Prick
83
99
  true
84
100
  end
85
101
 
102
+ def do_fox(path, schema: nil)
103
+ puts "do_fox(#{path.inspect}, #{schema.inspect})" if $verbose >= 2
104
+ do_path(path) { |file|
105
+ lines = Command.command "fox --state=#{state_file} --write --delete=none #{database.name} #{file}"
106
+ if @execute
107
+ begin
108
+ Rdbms.exec_sql(database.name, lines.join("\n"), user: database.user, schema: schema)
109
+ rescue Command::Error => ex
110
+ $stderr.puts ex.stderr
111
+ $stderr.puts "from #{reldir}/#{file}"
112
+ exit 1
113
+ end
114
+ else
115
+ @lines += lines
116
+ end
117
+ }
118
+ end
119
+
86
120
  def do_exe(path, args = [], schema: nil)
87
- # puts "do_exe(#{path.inspect}, #{args.inspect})"
88
- do_dir(path) { |file|
121
+ puts "do_exe(#{path.inspect}, #{args.inspect})" if $verbose >= 2
122
+ do_path(path) { |file|
89
123
  cmd = (["./#{file}"] + args).join(" ")
90
- lines = Command.command cmd, stdin: [database.name, database.user]
124
+ lines = Command.command cmd, stdin: [database.name, database.user], stderr: nil
91
125
  if @execute
92
126
  begin
93
127
  Rdbms.exec_sql(database.name, lines.join("\n"), user: database.user, schema: schema)
@@ -104,14 +138,16 @@ module Prick
104
138
  end
105
139
 
106
140
  def do_yml(path)
107
- # puts "do_yml(#{path})"
108
- dir, file = File.split(path)
109
- YAML.load(File.read(path))&.each { |subject| build_subject(File.join(dir, subject)) }
141
+ puts "do_yml(#{path})" if $verbose >= 2
142
+ do_path(path) { |file|
143
+ YAML.load(File.read(file))&.each { |subject| build_subject(subject) }
144
+ }
110
145
  true
111
146
  end
112
147
 
113
- # A subject can be both an abstract subject or a concrete file (*.yml, *.sql)
148
+ # A subject can be both an abstract subject or a concrete file (*.yml, *.sql, or *.fox)
114
149
  def build_subject(subject)
150
+ puts "build_subject(#{subject.inspect}) in #{Dir.getwd}" if $verbose > 0
115
151
  cmd, *args = subject.split(/\s+/)
116
152
  if File.file?(cmd) && File.executable?(cmd)
117
153
  do_exe(cmd, args)
@@ -119,6 +155,8 @@ module Prick
119
155
  do_yml(subject)
120
156
  elsif File.file?(subject) && subject.end_with?(".sql")
121
157
  do_sql(subject)
158
+ elsif File.file?(subject) && subject.end_with?(".fox")
159
+ do_fox(subject)
122
160
  elsif File.exist?(yml_file = "#{subject}.yml")
123
161
  do_yml(yml_file)
124
162
  elsif File.exist?(sql_file = "#{subject}.sql")
@@ -131,16 +169,19 @@ module Prick
131
169
  end
132
170
 
133
171
  def build_directory(path)
134
- Dir.chdir(path) {
135
- build_subject(File.join(path, @default)) || begin
136
- if Dir["#{path}/#{default}", "#{path}/#{default}.yml", "#{path}/#{default}.sql"]
172
+ puts "build_directory(#{path.inspect}) in #{Dir.getwd}" if $verbose >= 2
173
+ do_path(path) { |_|
174
+ build_subject(@default) || begin
175
+ if !Dir["#{default}", "#{default}.yml", "#{default}.sql"].empty?
137
176
  subjects = [default]
138
177
  else
178
+ candidates = Dir["*"]
139
179
  exes = candidates.select { |file| File.file?(file) && File.executable?(file) }
140
180
  ymls = candidates.select { |file| file.end_with?(".yml") }.map { |f| f.sub(/\.yml$/, "") }
141
181
  sqls = candidates.select { |file| file.end_with?(".sql") }.map { |f| f.sub(/\.sql$/, "") }
182
+ foxs = candidates.select { |file| file.end_with?(".fox") }.map { |f| f.sub(/\.fox$/, "") }
142
183
  dirs = candidates.select { |file| File.directory?(file) }
143
- subjects = (exes + ymls + sqls + dirs).uniq.sort.reject { |f| f != "diff" }
184
+ subjects = (exes + ymls + sqls + foxs + dirs).uniq.sort #.reject { |f| f != "diff" } FIXME ??
144
185
  end
145
186
  subjects.inject(false) { |a, s| build_subject(s) || a }
146
187
  end
@@ -192,12 +233,12 @@ module Prick
192
233
 
193
234
  protected
194
235
  def do_sql(path)
195
- schema = Dir.getwd.sub(/^.*schema\/([^\/]+)(?:\/.*)?$/, '\1')
236
+ schema = Dir.getwd =~ /^.*schema\/([^\/]+)(?:\/.*)?$/ ? $1 : "public"
196
237
  super(path, schema: schema)
197
238
  end
198
239
 
199
240
  def do_exe(path, args = [])
200
- schema = Dir.getwd.sub(/^.*schema\/([^\/]+)(?:\/.*)?$/, '\1')
241
+ schema = Dir.getwd =~ /^.*schema\/([^\/]+)(?:\/.*)?$/ ? $1 : "public"
201
242
  super(path, args, schema: schema)
202
243
  end
203
244
  end
data/lib/prick/command.rb CHANGED
@@ -74,7 +74,9 @@ module Command
74
74
  case stderr
75
75
  when true; [out, err]
76
76
  when false; out
77
- when NilClass; $stderr.puts err
77
+ when NilClass;
78
+ $stderr.puts err
79
+ out
78
80
  else
79
81
  raise Internal, "Unexpected value for :stderr - #{stderr.inspect}"
80
82
  end
@@ -61,11 +61,11 @@ module Prick
61
61
 
62
62
  # Hollow-out a database without dropping it. This is useful compared to a
63
63
  # simple drop database since it wont block on other sessions wont block
64
- def clean()
64
+ def clean()
65
65
  if exist?
66
66
  schemas = Rdbms.select_values(
67
- "postgres",
68
- "select nspname from pg_namespace where nspowner != 10")
67
+ name,
68
+ "select nspname from pg_namespace where nspowner != 10 and nspname != 'prick'")
69
69
  for schema in schemas
70
70
  Rdbms.exec_sql(name, "drop schema \"#{schema}\" cascade")
71
71
  end
data/lib/prick/head.rb CHANGED
@@ -120,6 +120,12 @@ module Prick
120
120
  end
121
121
  end
122
122
 
123
+ class UserBranch < Branch
124
+ def initialize(name)
125
+ super(nil, nil, nil)
126
+ end
127
+ end
128
+
123
129
  class ReleaseBranch < Branch
124
130
  def release_branch?() true end
125
131
 
data/lib/prick/program.rb CHANGED
@@ -1,4 +1,5 @@
1
1
 
2
+ require "pg_conn"
2
3
  require "prick.rb"
3
4
 
4
5
  module Prick
@@ -64,12 +65,14 @@ module Prick
64
65
  project.cache.list.each { |l| puts l }
65
66
  end
66
67
 
67
- def build(database, version, nocache)
68
+ def build(database, version, state_file, nocache)
68
69
  into_mesg = database && "into #{database}"
69
70
  version_mesg = version ? "v#{version}" : "current schema"
70
71
  version &&= Version.new(version)
71
72
  version.nil? || Git.tag?(version) or raise Error, "Can't find tag v#{version}"
72
73
  database = database ? Database.new(database, project.user) : project.database(version)
74
+ drop_users(database.name)
75
+ Builder.state_file = state_file
73
76
  project.build(database, version: version)
74
77
  project.save(database) if version && !nocache
75
78
  mesg "Built", version_mesg, into_mesg
@@ -113,6 +116,7 @@ module Prick
113
116
 
114
117
  def drop(database, all)
115
118
  database.nil? || !all or raise Error, "Can't use --all when database is given"
119
+ return if !Rdbms.exist_database?(database)
116
120
  if database
117
121
  check_owned(database)
118
122
  dbs = [database]
@@ -123,10 +127,24 @@ module Prick
123
127
  dbs += Rdbms.list_databases(Prick.tmp_databases_re(project.name)) # FIXME: Only used in dev
124
128
  dbs.each { |db|
125
129
  Rdbms.drop_database(db)
130
+ drop_users db
126
131
  mesg "Dropped database #{db}"
127
132
  }
128
133
  end
129
134
 
135
+ # Drop all users that follows the per-database-user naming convention
136
+ # ("<database>__<username>")
137
+ def drop_users(database)
138
+ PgConn.new("postgres") { |postgres|
139
+ users = postgres.role.list.grep(/^#{database.sub(/-/, "_")}__/)
140
+ if postgres.rdbms.exist?(database)
141
+ PgConn.new(database) { |conn| conn.role.drop users, cascade: true }
142
+ else
143
+ postgres.role.drop users
144
+ end
145
+ }
146
+ end
147
+
130
148
  # `select` is a tri-state variable that can be :tables, :no_tables, or :all
131
149
  # (or any other value)
132
150
  def diff(from, to, mark, select)
@@ -267,240 +285,3 @@ module Prick
267
285
  end
268
286
  end
269
287
 
270
- __END__
271
-
272
-
273
- module Prick
274
- class Program
275
- def project() @project ||= Project.load end
276
-
277
- attr_accessor :quiet
278
- attr_accessor :verbose
279
-
280
- def initialize(quiet: false, verbose: false)
281
- @quiet = quiet
282
- @verbose = verbose
283
- end
284
-
285
- def mesg(*args) puts args.compact.grep(/\S/).join(' ') if !quiet end
286
- def verb(*args) puts args.compact.grep(/\S/).join(' ') if verbose end
287
- def check_clean() Git.clean? or raise Error, "Repository is dirty - please commit your changes first" end
288
-
289
- def initialize_directory(project_name, database_user, directory)
290
- !Project.initialized?(directory) or raise Error, "Directory #{directory} is already initialized"
291
- Project.initialize_directory(project_name, database_user, directory)
292
- if project_name != File.basename(directory)
293
- mesg "Initialized project #{project_name} in #{directory}"
294
- else
295
- mesg "Initialized project #{project_name}"
296
- end
297
- end
298
-
299
- def info
300
- if project.tag?
301
- puts "At v#{project.version} tag"
302
- else
303
- puts "On branch #{project.branch.name}"
304
- end
305
- puts " Git is " + (Git.clean? ? "clean" : "dirty")
306
- bv = project.branch.version
307
- dv = project.database.version
308
- sv = project.branch.schema.version
309
- puts " Database version: #{dv}" + (dv != bv ? " (mismatch)" : "")
310
- puts " Schema version : #{sv}" + (sv != bv ? " (mismatch)" : "")
311
- end
312
-
313
- # TODO: Move to project to take advantage of cache
314
- def build(database, version, no_cache)
315
- version = version && Version.new(version)
316
- into_mesg = database && "into #{database}"
317
- database = database ? Database.new(database, project.user) : project.database(version)
318
- if version
319
- Git.tag?(version) or raise Error, "Can't find tag v#{version}"
320
- cache_file = project.cache_file(version)
321
- if !no_cache && File.exist?(cache_file)
322
- project.load(cache_file, database: database)
323
- mesg "Loaded v#{version}", into_mesg, "from cache"
324
- else
325
- project.build(database: database, version: version)
326
- project.save(cache_file, database: database)
327
- mesg "Built v#{version}", into_mesg
328
- end
329
- else
330
- project.build(database: database)
331
- mesg "Built current schema", into_mesg
332
- end
333
- end
334
-
335
- def load(database, file_or_version)
336
- version = Version.try(file_or_version)
337
- into_mesg = database && "into #{database}"
338
- database = database ? Database.new(database, project.user) : project.database(version)
339
- if version
340
- file = project.cache_file(version)
341
- File.exist?(file) or raise Error, "Can't find #{file} - forgot to build?"
342
- project.load(file, database: database)
343
- mesg "Loaded v#{version}", into_mesg
344
- else
345
- file = file_or_version
346
- project.load(file, database: database)
347
- mesg "Loaded #{file}", into_mesg
348
- end
349
- end
350
-
351
- def save(database, file)
352
- file ||= "#{ENV['USER']}-#{name}-#{branch}.sql.gz"
353
- subject_mesg = database ? "database #{database}" : "current database"
354
- database = database ? Database.new(database, project.user) : project.database(version)
355
- project.save(file, database: database)
356
- mesg "Saved", subject_mesg, "to #{file}"
357
- end
358
-
359
- def make(subject)
360
- project.database.exist? or raise Error, "Project database is not present"
361
- project.make(project.database, subject)
362
- end
363
-
364
- def list_releases(migrations: false, cancelled: false)
365
- puts (project.list_releases(all: cancelled) + (migrations ? project.list_migrations : [])).sort.map(&:name)
366
- end
367
-
368
- def list_migrations
369
- puts project.list_migrations.sort.map(&:name)
370
- end
371
-
372
- def list_upgrades(from = nil, to = nil)
373
- from = from ? Version.new(from) : project.database.version
374
- to = to ? Version.new(to) : project.branch.version
375
- branches = project.list_upgrades(from, to)
376
- puts branches.map(&:name)
377
- end
378
-
379
- def prepare_schema(name)
380
- project.prepare_schema(name)
381
- mesg project.message
382
- end
383
-
384
- def prepare_diff(version = nil)
385
- version ||=
386
- if project.prerelease? || project.migration? || project.feature?
387
- project.branch.base_version
388
- else
389
- project.branch.version
390
- end
391
- project.prepare_diff(version)
392
- mesg "Remember to update the associated SQL migration files"
393
- end
394
-
395
- def prepare_release
396
- check_clean
397
- project.version.release? or raise Error, "You need to be on a release branch to prepare a release"
398
- project.prepare_release
399
- mesg project.message
400
- end
401
-
402
- def check
403
- version ||=
404
- if project.prerelease? || project.migration?
405
- project.branch.base_version
406
- else
407
- project.branch.version
408
- end
409
- project.check_migration(version)
410
- end
411
-
412
- # `arg` can be a version numer of a relative increase (eg. 'minor')
413
- def create_release(arg = nil)
414
- check_clean
415
- if project.release?
416
- arg or raise Error, "Need a version argument"
417
- version = compute_version(project.version, arg)
418
- project.create_release(Version.new(version))
419
- mesg project.message
420
- elsif project.prerelease?
421
- arg.nil? or raise Error, "Illegal number of arguments"
422
- project.create_release_from_prerelease
423
- mesg project.message
424
- else
425
- raise Error, "You need to be on a release or pre-release branch to create a new release"
426
- end
427
- end
428
-
429
- def cancel_release(arg)
430
- project.cancel_release(Version.new(arg))
431
- end
432
-
433
- def create_prerelease(arg)
434
- check_clean
435
- if project.release?
436
- version = %w(major minor patch).include?(arg) ? project.version.increment(arg.to_sym) : Version.new(arg)
437
- project.prepare_release(commit: false)
438
- prerelease = project.create_prerelease(version)
439
- mesg "Created pre-release #{prerelease.version}"
440
- elsif project.prerelease?
441
- arg.nil? or raise Error, "Illegal number of arguments"
442
- prerelease = project.increment_prerelease
443
- mesg "Created pre-release #{prerelease.prerelease_version}"
444
- else
445
- raise Error, "You need to be on a release branch to create a pre-release"
446
- end
447
- end
448
-
449
- def prepare_migration(arg)
450
- check_clean
451
- version = Version.new(arg)
452
- project.release? or raise "You need to be on a release or migration branch to prepare a migration"
453
- project.prepare_migration(version)
454
- mesg project.message
455
- end
456
-
457
- def create_feature(name)
458
- check_clean
459
- project.release? or raise "You ned to be on a release branch to create a feature"
460
- project.create_feature(name)
461
- mesg "Created feature '#{name}'"
462
- end
463
-
464
- def include_feature(name_or_version)
465
- check_clean
466
- project.prerelease? or raise Error, "You need to be on a pre-release branch to include a feature"
467
- version = Version.try(name_or_version) ||
468
- Version.new(project.branch.base_version, feature: name_or_version)
469
- Git.branch?(version.to_s) or raise Error, "Can't find feature #{version}"
470
- project.include_feature(version)
471
- mesg "Included feature '#{name_or_version}'"
472
- mesg "Please resolve eventual conflicts and then commit"
473
- end
474
-
475
- def upgrade
476
- # TODO: Shutdown connections
477
- project.database.version != project.version or raise Error, "Database already up to date"
478
- project.backup
479
- begin
480
- project.upgrade
481
- rescue RuntimeError
482
- project.restore
483
- raise Fail, "Failed upgrading database, rolled back to last version"
484
- end
485
- end
486
-
487
- def backup(file = nil) project.backup(file) end
488
-
489
- def restore(file = nil)
490
- file.nil? || File.exist?(file) or raise Error, "Can't find #{file}"
491
- project.restore(file)
492
- end
493
-
494
- private
495
- def compute_version(version, arg)
496
- if arg.nil?
497
- nil
498
- elsif %w(major minor patch).include?(arg)
499
- version.increment(arg.to_sym)
500
- else
501
- Prick::Version.new(arg)
502
- end
503
- end
504
- end
505
- end
506
-
data/lib/prick/project.rb CHANGED
@@ -92,7 +92,7 @@ module Prick
92
92
  begin
93
93
  branch = Head.load(name)
94
94
  rescue Version::FormatError
95
- raise Fail, "Illegal branch name: #{name}"
95
+ branch = Prick::UserBranch.new(name)
96
96
  end
97
97
  state = ProjectState.new.read
98
98
  Project.new(state.name, state.user, branch)
@@ -222,12 +222,12 @@ module Prick
222
222
  end
223
223
 
224
224
  def generate_schema
225
- build = SchemaBuilder.new(database, SCHEMA_DIR).build(execute: false)
225
+ build = SchemaBuilder.new(database, state_file, SCHEMA_DIR).build(execute: false)
226
226
  puts build.lines
227
227
  end
228
228
 
229
229
  def generate_migration
230
- build = MigrationBuilder.new(database, MIGRATION_DIR).build(execute: false)
230
+ build = MigrationBuilder.new(database, state_file, MIGRATION_DIR).build(execute: false)
231
231
  puts build.lines
232
232
  end
233
233
 
data/lib/prick/version.rb CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # Required by gem
6
6
  module Prick
7
- VERSION = "0.18.0"
7
+ VERSION = "0.19.0"
8
8
  end
9
9
 
10
10
  # Project related code starts here
@@ -95,7 +95,7 @@ module Prick
95
95
  # Parse a branch or tag name into a Version object. Return a [version, tag]
96
96
  # tuple where tag is true if name was a tag
97
97
  def self.parse(name)
98
- name =~ VERSION_RE or raise Version::FormatError, "Expected a version, got #{version.inspect}"
98
+ name =~ VERSION_RE or raise Version::FormatError, "Expected a version, got #{name.inspect}"
99
99
  fork, tag, semver, feature = $1, $2, $3, $4
100
100
  version = Version.new(semver, fork: fork, feature: feature)
101
101
  [version, tag]
data/lib/prick.rb CHANGED
@@ -27,5 +27,7 @@ require "prick/version.rb"
27
27
  require "ext/fileutils.rb"
28
28
  require "ext/shortest_path.rb"
29
29
 
30
+ $verbose = 0 if $verbose.nil?
31
+
30
32
  module Prick
31
33
  end
data/prick.gemspec CHANGED
@@ -34,4 +34,20 @@ Gem::Specification.new do |spec|
34
34
  spec.add_dependency "shellopts", "2.0.0.pre.14"
35
35
  spec.add_dependency "semantic"
36
36
  spec.add_dependency "indented_io"
37
+
38
+ # To be able to call fox in development mode (TODO: Remove)
39
+ spec.add_dependency "boolean"
40
+ spec.add_dependency "constrain"
41
+ spec.add_dependency "developer_exceptions"
42
+ spec.add_dependency "pg"
43
+ spec.add_dependency "dry-inflector"
44
+
45
+ # In development mode override load paths for gems whose source are located
46
+ # as siblings of this project directory
47
+ if File.directory?("#{__dir__}/.git")
48
+ local_projects = Dir["../*"].select { |path|
49
+ File.directory?(path) && File.exist?("#{path}/Gemfile")
50
+ }.map { |relpath| "#{File.absolute_path(relpath)}/lib" }
51
+ $LOAD_PATH.unshift *local_projects
52
+ end
37
53
  end
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.18.0
4
+ version: 0.19.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: 2021-07-21 00:00:00.000000000 Z
11
+ date: 2021-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: shellopts
@@ -52,6 +52,76 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: boolean
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: constrain
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: developer_exceptions
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pg
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: dry-inflector
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
55
125
  description: A release control and management system for postgresql
56
126
  email:
57
127
  - claus.l.rasmussen@gmail.com