prick 0.18.0 → 0.19.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: 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