prick 0.29.2 → 0.30.0

Sign up to get free protection for your applications and to get access to all the features.
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
data/exe/prick CHANGED
@@ -10,16 +10,14 @@ begin
10
10
  compile_cache_iseq: true, # Compile Ruby code into ISeq cache, breaks coverage reporting.
11
11
  compile_cache_yaml: true # Compile YAML into a cache
12
12
  )
13
- # Bootsnap.instrumentation = ->(event, path) { puts "#{event} #{path}" }
13
+ # Bootsnap.instrumentation = ->(event, path) { puts "#{event} #{path}" }
14
14
  end
15
15
 
16
16
  require 'shellopts'
17
- require_relative '../lib/prick.rb'
18
-
19
- include ShellOpts
20
- include Prick
21
17
 
22
- TIME = false
18
+ # Start time of prick. Used in make and build to compute duration of the whole
19
+ # build process
20
+ TIME = Time.now
23
21
 
24
22
  SPEC = %(
25
23
  @ Prick project command
@@ -33,63 +31,91 @@ SPEC = %(
33
31
  -C,directory=EDIR
34
32
  Change to directory DIR before doing anything else
35
33
 
36
- -d,database=DATABASE
37
- Override database name. Default is read from .prick.context
34
+ -p,project-file=PRICK-FILE
35
+ Override project file. Default is 'prick.yml'
38
36
 
39
- -U,username=USERNAME
40
- Override username. Default is read from .prick.context
37
+ -e,environment-file=ENVIRONMENT-FILE
38
+ Override the environment file. Default is 'prick.environment.yml'
41
39
 
42
- -e,environment=ENVIRONMENT
43
- Override environment. Default is read from from .prick.context
40
+ -s,state-file=STATE-FILE
41
+ Override state file. Default is '.prick-state.yml'
44
42
 
45
- -p,project=PRICK-FILE
46
- Override default environment file ('prick.yml')
43
+ init! -n,name=NAME -t,title=TITLE DIRECTORY #@ Initialize new Prick project directory
44
+ Initializes a prick project and checks it into git. If a directory is
45
+ given the directory will be created and the project initialized in it.
46
+ Default name and title is derived from the directory name
47
47
 
48
- -c,context=CONTEXT-FILE
49
- Override default context file ('.prick.context')
48
+ setup! -- [OWNER@]DATABASE [ENVIRONMENT] @ Create and set current database
49
+ Create database and owner and set the current database
50
50
 
51
- version!
52
- Print project version
51
+ teardown! -- [DATABASE...] @ Remove database and owner
52
+ Drop database, database users, and database owner if possible and not the
53
+ current user. DATABASE defaults to the current database in which case the
54
+ state file is also removed
53
55
 
54
- init! -n,name=NAME -t,title=TITLE [DIRECTORY]
55
- Initializes a prick project
56
+ clean! -- [DATABASE] @ Empty database and remove users
57
+ Empty the database and drop related users except the database owner and
58
+ the prick schema. The public schema is recreated automatically
56
59
 
57
- env! ENVIRONMENT
58
- Set build environment in the prick context file. The environment is
59
- accessible as $ENVIRONMENT in build.yml files and can be used to do
60
- conditional builds. There are no built-in values for the environment but
61
- 'production' and 'development' will be typical choices. Defaults to
62
- 'development'
60
+ get.database!
61
+ Print the name of the current database
63
62
 
64
- setup!
65
- Create the database user (if necessary) and an empty database
63
+ get.username!
64
+ Print the name of the current database owner
66
65
 
67
- teardown!
68
- Drop the database and the database user. TODO: Also run teardown scripts
66
+ get.environment!
67
+ Print the current environment
69
68
 
70
- clean!
71
- Empties the database and drops related users except the database user
69
+ set! -- VARIABLE [VALUE [OPT]] @ Switch database/environment
70
+ Switch database and/or environment or assign a value to the corresponding
71
+ database variable Currently only 'database', 'environment', and
72
+ 'duration' can be used as arguments. 'duration' not meant for the
73
+ end-user but for make scripts that enclose the prick command and that
74
+ would like to record the total time used. Prints the value of the
75
+ variable if VALUE is absent
72
76
 
73
- create.data!
74
- create.schema!
75
- create.database!
76
- create.users!
77
- create.all!
78
- Create an object. Fails if migration exist unless the --force flag is given
77
+ create.database! -- [[OWNER@]DATABASE [ENVIRONMENT]] @ Create database
78
+ Create database and owner if needed. OWNER defaults to the database
79
+ name and DATABASE defaults to the project name. ENVIRONMENT defaults to
80
+ the current environment or to the prick default environment if there is
81
+ no current environment
79
82
 
80
- create.migration! -f,force -o,file=FILE -- VERSION
83
+ It is an error if the database exists but not if the owner exists. Note
84
+ that you can have multiple databases and switch between them using the
85
+ 'set database' subcommand
86
+
87
+ create.migration! -f,force -o,file=FILE -- VERSION @ Create migration
81
88
  Create a migration from VERSION to the current and write it to
82
89
  migration/VERSION. Fails if migration exist unless the --force flag is
83
90
  given. If --file is given, the migration is written to FILE instead of
84
- the migration directory. This doesn't require you to be on a release
85
- branch and can be used to create ad-hoc migration scripts
91
+ the migration directory
92
+
93
+ create.users!
94
+ create.schema!
95
+ create.data!
96
+ create.all!
97
+ TODO
98
+
99
+ drop.schema! -- [SCHEMA...]
100
+ @ Drop schemas
101
+
102
+ Drops the given schemas or all schemas if called without arguments
103
+
104
+ drop.users!
105
+ @ Drop database users
106
+
107
+ Drops all database users except the database owner
108
+
109
+ drop.data!
110
+ @ Drop data
111
+
112
+ TODO
86
113
 
87
- drop! -- [KIND]
88
- @ Drop objects
114
+ drop.owner!
115
+ Drop database owner
89
116
 
90
- Kind can be 'users', 'data', 'schema', 'user', 'database' (the default),
91
- or 'all'. It is not an error if the object doesn't exist. TODO 'data' and
92
- 'schema' is not implemented
117
+ drop.database!
118
+ Drop database
93
119
 
94
120
  build! -f,force -t,time --dump=KIND? -- [SCHEMA]
95
121
  Build the project. If SCHEMA is defined, later schemas are excluded.
@@ -112,6 +138,9 @@ SPEC = %(
112
138
 
113
139
  # TODO: A --clean option that resets data
114
140
 
141
+ version!
142
+ Print project version
143
+
115
144
  release! -- KIND
116
145
  Create a release of the given kind. KIND can be 'major', 'minor', or
117
146
  'patch'. Release checks that the current repo is clean and up to date
@@ -120,146 +149,277 @@ SPEC = %(
120
149
  migrate! -f,file=FILE
121
150
  Execute a migration
122
151
 
123
- dump.type!
124
- dump.data!
125
- dump.schema!
126
- dump.database!
127
- dump.environment!
128
- TODO
152
+ list.environments! -l,long
153
+ List available environments (environments with a comment field)
154
+
155
+ list.databases! -l,long
156
+ List Prick databases. The --long option creates a table-like output
157
+
158
+ list.users!
159
+ List database users in the current environment
160
+
161
+ list.owners! -l,long
162
+ List database owners
163
+
164
+ list.variables! -l,long -a,all
165
+ List variables for the current environment
129
166
 
130
167
  dump.migration! --force -- VERSION
168
+
169
+ dump.type!
170
+ Dumps a PgGraph object
171
+
172
+ dump.variable! -x,export -l,local -- [VARIABLE...]
173
+ Dumps a bash source snippets that sets and optionally exports values from
174
+ the configuration, environment, and state. Environment is only dumped if
175
+ the current environment is defined in the state file. The state file may
176
+ be absent in which case the related variables are also left undefined
177
+
178
+ dump.value! -- VARIABLE...
179
+ Dumps values of the given variables. Multiple variables can be read into bash
180
+ variables using read:
181
+
182
+ read name title <<< $(prick dump value PRICK_NAME PRICK_TITLE)
183
+
184
+ dump.node!
185
+ dump.build!
186
+ dump.data! @ TODO
187
+ dump.schema! @ TODO
188
+ dump.database! @ TODO
189
+ TODO
131
190
  )
132
191
 
133
- opts, args = ShellOpts.process(SPEC, ARGV, exception: true)
192
+ def require_db(database = Prick.state&.database, exist: true)
193
+ database or raise ArgumentError
194
+ dba = State.connection
195
+ if exist
196
+ dba.rdbms.exist?(database) or Prick.error "Can't find database '#{database}'"
197
+ if Prick.state&.conn&.name == database
198
+ close_conn = false
199
+ conn = Prick.state.conn
200
+ else
201
+ close_conn = true
202
+ conn = PgConn.new(database)
203
+ end
204
+ conn.schema.exist?("prick") or Prick.error "Database '#{database}' is not a Prick database"
205
+ conn.close if close_conn # Close session explicitly so we can drop database if required
206
+ else
207
+ !dba.rdbms.exist?(database) or Prick.error "Database '#{database}' exists"
208
+ end
209
+ end
210
+
211
+ def parse_database_args(state, args)
212
+ arg, environment = args.expect(0..2)
213
+ if arg
214
+ if arg =~ /^(.*)@(.*)$/
215
+ username, database = $1, $2
216
+ else
217
+ database = arg
218
+ username = database
219
+ end
220
+ else
221
+ database = state.name
222
+ username = database
223
+ end
224
+ database or Prick.error "Database is undefined"
225
+ [username, database, environment]
226
+ end
227
+
228
+ begin
229
+ # Parse command line
230
+ opts, args = ShellOpts.process(SPEC, ARGV, exception: true)
231
+
232
+ # Honor -C option
233
+ begin
234
+ Dir.chdir(opts.directory) if opts.directory?
235
+ rescue Errno::ENOENT
236
+ raise ShellOpts::Error, "Can't cd to '#{opts.directory}'"
237
+ end
238
+ rescue ShellOpts::Error => ex
239
+ ShellOpts.error(ex.message)
240
+ end
241
+
242
+ # Require prick only after -C directory option because some constants depends
243
+ # on the current directory
244
+ require_relative '../lib/prick.rb'
245
+ include Prick
134
246
 
135
247
  begin
136
248
  # Handle verbose and quiet
137
249
  $verbose = opts.verbose?
138
250
  $quiet = opts.quiet?
139
251
 
140
- # Honor -C option
141
- if opts.directory?
142
- if File.exist?(opts.directory)
143
- begin
144
- Dir.chdir(opts.directory)
145
- rescue Errno::ENOENT
146
- raise Prick::Error, "Can't cd to '#{opts.directory}'"
147
- end
148
- else
149
- raise Prick::Error, "Can't find directory: #{opts.directory}"
150
- end
151
- end
252
+ # Expect a sub-command. TODO: Make this a built-in in ShellOpts#subcommand!
253
+ cmd = opts.subcommand! or Prick.error "Subcomand expected"
152
254
 
153
- # Get subcommand
154
- cmd = opts.subcommand!
255
+ # Handle -p, -e, and -c. TODO: Take -C into account for relative paths. Low-hanging fruit
256
+ project_file = opts.project_file || PRICK_PROJECT_PATH
257
+ environment_file = opts.environment_file || PRICK_ENVIRONMENT_PATH
258
+ state_file = opts.state_file || PRICK_STATE_PATH
155
259
 
156
- # Process init command
157
- if opts.subcommand == :init
158
- dir, state = Prick::SubCommand.init(args.expect(0..1), cmd.name, cmd.title, opts.database, opts.username)
159
- puts "Initialized prick project '#{state.name}' in #{dir}"
160
- if opts.database.nil? || opts.username.nil?
161
- puts
162
- puts "Please check database/username in #{PRICK_CONTEXT_FILE}"
163
- end
260
+ # Process init command and exit
261
+ if opts.subcommand == :init!
262
+ dir, name = Prick::SubCommand.init(project_file, args.expect(0..1), cmd.name, cmd.title)
263
+ Prick.mesg "Initialized Prick project '#{name}' in #{File.absolute_path(dir)}/"
164
264
  exit
165
265
  end
166
266
 
167
- # Check state
168
- File.exist?(PRICK_PROJECT_FILE) or raise Prick::Error, "Not in a prick project directory"
169
-
170
- # Handle -p and -c
171
- project_file = opts.project || PRICK_PROJECT_PATH
172
- context_file = opts.context || PRICK_CONTEXT_PATH
267
+ # Check for prick project
268
+ if ![:teardown!, :clean!].include?(opts.subcommand) || args.size == 0
269
+ # We test for the presense of the schema directory to verify we're in a
270
+ # prick directory. Checking for a configuration file doesn't work because
271
+ # they can be placed elsewhere. TODO: This require us to check for project file manually
272
+ # File.directory? "schema" or Prick.error "Not in a prick project directory"
273
+ File.directory?(SCHEMA_DIR) or Prick.error "Not in a prick project directory"
274
+ File.exist?(project_file) or Prick.error "Can't find project file '#{project_file}'"
275
+ end
173
276
 
174
277
  # Load state
175
- state = Prick.state = State.load(project_file, context_file)
176
-
177
- # Set database, username and environment
178
- database = state.database = opts.database || state.database
179
- username = state.username = opts.username || state.username
180
- environment = state.environment = opts.environment || state.environment
278
+ state = Prick.state = State.new(project_file, environment_file, state_file)
181
279
 
182
- # Expect a sub-command
183
- cmd = opts.subcommand! or raise Prick::Error, "Subcomand expected"
280
+ # Lazyness
281
+ database = state.database
282
+ username = state.username
283
+ environment = state.environment
184
284
 
185
285
  # Process subcommands
186
286
  case opts.subcommand
187
287
  when :version!
188
288
  puts "#{Prick.state.name}-#{Prick.state.version}"
189
289
 
190
- when :env!
191
- env = args.expect(1)
192
- Prick.state.environment = env
193
- Prick.state.save
194
-
195
290
  when :setup!
196
- Prick::SubCommand.setup(database, username)
291
+ state.project_loaded? or Prick.error "No #{project_file} found"
292
+ username, database, environment = parse_database_args(state, args)
293
+ require_db(database, exist: false)
294
+ Prick::SubCommand.setup(database, username, environment)
197
295
 
296
+ # FIXME Ensure that we never drop the current user
198
297
  when :teardown!
199
- Prick::SubCommand.teardown(database, username)
298
+ if args.empty?
299
+ Prick::SubCommand.teardown(database, remove_state_file: true)
300
+ else
301
+ Prick::SubCommand.teardown(args)
302
+ end
303
+
304
+ when :get!
305
+ case cmd.subcommand
306
+ when :database!; puts database
307
+ when :username!; puts username
308
+ when :environment!; puts environment
309
+ else
310
+ raise ArgumentError
311
+ end
312
+
313
+ when :set!
314
+ variable, *args = args.expect(1..3)
315
+ require_db(database) if variable == "duration"
316
+ Prick::SubCommand.set(variable, *args) or error "Illegal variable name '#{variable}'"
200
317
 
201
318
  when :clean!
319
+ database = args.expect(0..1) || database
320
+ require_db(database)
202
321
  Prick::SubCommand.clean(database)
203
322
 
204
323
  when :create!
205
- create_command = opts.create!
324
+ create_command = opts.create! # Because we need easy access to subcommand options
206
325
  case create_command.subcommand
207
- when :migration
326
+ when :database!
327
+ database, username, environment = parse_database_args(state, args)
328
+ require_db(database, exist: false)
329
+ Prick::SubCommand.create_database(database, username, environment)
330
+ when :migration!
331
+ require_db
208
332
  arg = args.expect(1)
209
- version = PrickVersion.try(arg) or raise Prick::Error, "Illegal version: #{arg}"
333
+ version = PrickVersion.try(arg) or Prick.error "Illegal version: #{arg}"
210
334
  Prick::SubCommand.create_migration(
211
335
  username, version,
212
336
  force: create_command.subcommand!.force?,
213
337
  file: create_command.subcommand!.file)
338
+ when :users, :schema, :data, :all
339
+ raise NotImplementedError
214
340
  else
215
- raise NotImplementedError
341
+ raise ArgumentError
216
342
  end
217
343
 
218
344
  when :build!
345
+ require_db
219
346
  dump = cmd.dump? ? cmd.dump("batches")&.to_sym || :batches : nil
220
347
  # exclude = cmd.exclude? ? cmd.exclude.split(",") : []
221
348
  Prick::SubCommand.build(
222
349
  database, username, args.expect(0..1), force: cmd.force?, timer: cmd.time?, dump: dump)
223
350
 
224
351
  when :make!
352
+ require_db
225
353
  dump = cmd.dump? ? cmd.dump("batches")&.to_sym || :batches : nil
226
354
  Prick::SubCommand.make(database, username, args.expect(0..1), timer: cmd.time?, dump: dump)
227
355
 
228
356
  when :fox!
357
+ require_db
229
358
  Prick::SubCommand.fox(database, username, args)
230
359
 
231
360
  when :drop!
232
- case subject = args.expect(1).to_sym
233
- when :all
234
- Prick::SubCommand.drop_all(database)
235
- when :users
361
+ require_db if cmd.subcommand != :owner!
362
+ if cmd.subcommand == :schema!
363
+ schemas = args.to_a
364
+ else
365
+ args.expect(0)
366
+ end
367
+ case cmd.subcommand
368
+ when :all!
369
+ Prick::SubCommand.drop_all(database, username)
370
+ when :users!
236
371
  Prick::SubCommand.drop_users(database)
237
- when :user
238
- Prick::SubCommand.drop_user(username)
239
- when :database
372
+ when :owner!
373
+ Prick::SubCommand.drop_owner(username)
374
+ when :database!
240
375
  Prick::SubCommand.drop_database(database)
241
- when :data, :schema
376
+ when :data!
242
377
  raise NotImplementedError
378
+ when :schema!
379
+ Prick::SubCommand.drop_schema(database, schemas)
243
380
  else
244
- raise Prick::Error, "Unknown subject: #{subject}"
381
+ Prick.error "Unknown subject: #{subject}"
245
382
  end
246
383
 
247
384
  when :release!
248
385
  kind = args.expect(1).to_sym
249
386
  constrain? kind, :major, :minor, :patch or
250
- raise Prick::Fail, "Expected 'major', 'minor', or 'patch' argument, got '#{kind}'"
387
+ Prick.failure "Expected 'major', 'minor', or 'patch' argument, got '#{kind}'"
251
388
  Prick::SubCommand.release(kind)
252
389
 
253
390
  when :migrate!
391
+ require_db
254
392
  args.expect(0)
255
393
  Prick::SubCommand.migrate(database, username, file: cmd.file)
256
394
 
395
+ when :list!
396
+ format = (cmd.subcommand!.long? ? :long : :short) if cmd.subcommand != :users!
397
+ case cmd.subcommand
398
+ when :environments!; Prick::SubCommand.list_environments(format: format)
399
+ when :databases!; Prick::SubCommand.list_databases(format: format)
400
+ when :variables!;
401
+ all = cmd.subcommand!.all?
402
+ Prick::SubCommand.list_variables(format: format, all: all)
403
+ when :users!; Prick::SubCommand.list_users
404
+ when :owners!; Prick::SubCommand.list_owners(format: format)
405
+ else
406
+ Prick.error "Unknown subcommand: #{cmd.subcommand}"
407
+ end
408
+
257
409
  when :dump!
258
410
  subject = cmd.subcommand!
259
411
  case cmd.subcommand
412
+ when :node!
413
+ conn = PgConn.new(database, username)
414
+ builder = Prick::Build::Builder.new(conn, Prick::SCHEMA_DIR)
415
+ builder.root.dump
416
+ when :build!
417
+ conn = PgConn.new(database, username)
418
+ builder = Prick::Build::Builder.new(conn, Prick::SCHEMA_DIR)
419
+ # FIXME Nothing happens here
260
420
  when :migration!
261
421
  arg = args.expect(1)
262
- version = PrickVersion.try(arg) or raise "Illegal version number: #{arg}"
422
+ version = PrickVersion.try(arg) or Prick.error "Illegal version number: #{arg}"
263
423
  Prick::SubCommand.create_migration(username, version, force: subject.force?, file: "/dev/stdout")
264
424
  when :type!
265
425
  conn = PgConn.new(database, username)
@@ -269,15 +429,25 @@ begin
269
429
  graph.dump
270
430
  when :data!, :schema!, :database!
271
431
  raise NotImplementedError
272
- when :environment!
273
- puts state.bash_source
432
+ when :variable!
433
+ scope =
434
+ case [subject.export?, subject.local?]
435
+ in [true, false]; :global
436
+ in [false, true]; :local
437
+ in [false, false]; nil
438
+ else
439
+ Prick.error "Conflicting options - --export and --local"
440
+ end
441
+ puts state.bash_source(args.first ? args : nil, scope: scope)
442
+ exit
443
+ when :value!
444
+ puts args.expect(1..).map { |var| Array(state.bash_environment[var]).join(' ') }
274
445
  else
275
- raise Prick::Error, "Unknown dump object: #{cmd.subcommand!.__name__}"
446
+ object = args.extract(1) # Fails if object is absent
447
+ Prick.error "Unknown dump object: #{object}"
276
448
  end
277
-
278
-
279
449
  else
280
- raise Prick::Fail, "Internal error: Unhandled command - #{opts.subcommand.inspect}"
450
+ Prick.failure "Internal error: Unhandled command - #{opts.subcommand.inspect}"
281
451
  end
282
452
 
283
453
  rescue Prick::Build::PostgresError => ex
@@ -295,409 +465,11 @@ rescue Prick::Build::PostgresError => ex
295
465
  end
296
466
  exit 1
297
467
 
298
- rescue RuntimeError, IOError, ShellOpts::Failure, Prick::Fail, Prick::Build::PostgresError => ex
299
- ShellOpts.failure(ex.message)
300
-
301
468
  rescue ShellOpts::Error, Prick::Error => ex
469
+ raise
302
470
  ShellOpts.error(ex.message)
303
- end
304
-
305
-
306
- __END__
307
-
308
- -n,name=NAME
309
- Name of project. Defauls to the environment variable `PRICK_PROJECT` if
310
- set and else the name of the current directory
311
-
312
- init! -u,user=USER [NAME]
313
- Initialize a project in the given directory. The USER is the postgres
314
- user and defaults to the project name
315
-
316
- info!
317
- Print project information
318
-
319
- list.releases! -m,migrations -c,cancelled
320
- List releases. Include migration releases if the --migration option is
321
- present and also include cancelled releases if the --cancelled option is
322
- present
323
-
324
- list.migrations!
325
- List migrations
326
-
327
- list.upgrades! [FROM [TO]]
328
- List available upgrades
329
-
330
- list.cache!
331
- List cache files
332
-
333
- build! -d,database=DATABASE -s,state=FILE -C,no-cache [TAG]
334
- Drop all users associated with the database before building the current
335
- database from the content in the schemas/ directory. With a tag the
336
- version is built into the associated versioned database and the result is
337
- saved to cache unless the -C option is given. The -d option overrides the
338
- default database and the -s option overrides the default state file
339
- (fox.state)
340
-
341
- make! -d,database=DATABASE -C,no-cache [TAG]
342
- Build the current database from the content in the schemas/ directory.
343
- With a tag the associated versioned database is loaded from cache if
344
- present. The -C option ignores the cache and the -d option overrides
345
- the default database
346
-
347
- make.clean! -a,all
348
- Drop versioned databases and remove cached and other temporary files.
349
- Also drop the project database if the -a option is given
350
-
351
- load! -d,database=DATABASE VERSION|FILE
352
- Load the cached version or the file into the associated versioned
353
- database. It is an error if the version hasn't been cached. The --database
354
- argument overrides the database
355
-
356
- save! VERSION [FILE]
357
- Save the versioned database associated with version to the cache or the
358
- given file
359
-
360
- drop! -a,all [DATABASE]
361
- Drop the given database or all versioned databases. Users with a username
362
- on the form <database>__<username> are also dropped. The --all option
363
- also drops the project database
364
-
365
- drop.users! [DATABASE]
366
- Drop users with a username on the form <database>__<username>
367
-
368
- diff! -m,mark -t,tables -T,notables
369
- diff [FROM-DATABASE|FROM-VERSION [TO-DATABASE|TO-VERSION]]
370
- Create a schema diff between the given databases or versions. Default
371
- to-version is the current schema and default from-version is the base
372
- version of this branch/tag
373
-
374
- migrate!
375
- Not yet implemented
376
-
377
- prepare!
378
- Prepare a release. Just a shorthand for 'prick prepare release'
379
-
380
- prepare.release! [FORK]
381
- Populate the current migration directory with migration files
382
-
383
- prepare.feature! NAME
384
- Create and populate a feature as a subdirectory of the current directory.
385
- Also prepares the current release directory
386
471
 
387
- prepare.migration! [FROM]
388
- Create and populate a migration directory
389
-
390
- prepare.schema! NAME
391
- Create and populate a new schema directory. Existing files and
392
- directories are kept
393
-
394
- prepare.diff! [VERSION]
395
- Not yet implemented
396
-
397
- include.feature! FEATURE
398
- Include the given feature in the current pre-release
399
-
400
- check!
401
- Check that the current migration applied to the base version yields the
402
- same result as loading the current schema
403
-
404
- create.release! [RELEASE]
405
- Prepare a release and create release directory and migration file before
406
- tagging and branching to a release branch. The RELEASE argument can be
407
- left out if the current branch is a prerelease branch
408
-
409
- create.prerelease! RELEASE
410
- Prepare a release and create release directory and migration file before
411
- branching to a prerelease branch
412
-
413
- create.feature! NAME
414
- Prepare a feature before branching to a feature branch
415
-
416
- cancel!
417
- Cancel a release. Just a shorthand for 'prick cancel release'
418
-
419
- cancel.release!
420
- Cancel a release. Since tags are immutable, the release is cancelled by
421
- added a special cancel-tag to the release that makes prick ignore it
422
-
423
- generate.migration!
424
- Create a script to migrate the database
425
-
426
- generate.schema!
427
- Create a script to create the database
428
-
429
- upgrade!
430
- Migrate the database to match the current schema
431
-
432
- backup! [FILE]
433
- Saves a backup of the database to the given file or to the var/spool
434
- directory
435
-
436
- restore! [FILE]
437
- Restore the database from the given backup file or from the latest backup
438
- in the var/spool directory
439
- )
440
-
441
- __END__
442
-
443
-
444
-
445
-
446
-
447
-
448
- DEFAULT_STATE_FILE = "fox.state"
449
-
450
- opts, args = ShellOpts.process(SPEC, ARGV)
451
-
452
- # Handle --help
453
- if opts.help?
454
- ShellOpts.help
455
- exit
456
- end
457
-
458
- # Handle --version
459
- if opts.version?
460
- puts "prick-#{VERSION}"
461
- exit
462
- end
463
-
464
- begin
465
- # Honor -C option
466
- if opts.directory?
467
- if File.exist?(opts.directory)
468
- begin
469
- Dir.chdir(opts.directory)
470
- rescue Errno::ENOENT
471
- raise Prick::Error, "Can't cd to '#{opts.directory}'"
472
- end
473
- else
474
- raise Prick::Error, "Can't find directory: #{opts.directory}"
475
- end
476
- end
477
-
478
- # Create program object
479
- program = Program.new(quiet: opts.quiet?, verbose: opts.verbose?)
480
- $verbose = opts.verbose? ? opts.verbose : nil
481
-
482
- # Handle init command
483
- if opts.subcommand == :init
484
- directory = args.expect(0..1)
485
- name = opts.name || (directory && File.basename(directory)) || File.basename(Dir.getwd)
486
- user = opts.init!.user || name
487
- program.init(name, user, directory || ".")
488
- exit 0
489
- end
490
-
491
- # Change to parent directory containing the Prick version file if not found
492
- # in the current directory
493
- program.current_directory = Dir.getwd
494
- while Dir.getwd != "/" && !File.exist?(PRICK_VERSION_FILE)
495
- Dir.chdir("..")
496
- end
497
-
498
- # Check prick version
499
- file = PrickVersion.new
500
- file.exist? or raise Prick::Error, "Can't find prick version file '#{file.path}'"
501
- VERSION == file.read.to_s or
502
- raise Prick::Fail, ".prick-version required prick-#{file.read} but you're using prick-#{VERSION}"
503
-
504
- # TODO: Check for dirty detached head
505
-
506
- # Expect a sub-command
507
- opts.subcommand or raise Prick::Error, "Subcomand expected"
508
-
509
- case opts.subcommand
510
- when :info
511
- args.expect(0)
512
- program.info
513
-
514
- when :list
515
- command = opts.list!
516
- case command.subcommand
517
- when :releases;
518
- obj = command.releases!
519
- program.list_releases(migrations: obj.migrations?, cancelled: obj.cancelled?)
520
- when :migrations; program.list_migrations
521
- when :upgrades; program.list_upgrades(*args.expect(0..2).compact)
522
- when :cache;
523
- args.expect(0)
524
- program.list_cache
525
- when NilClass; raise Prick::Error, "list requires a releases|migrations|upgrades sub-command"
526
- else
527
- raise Prick::Internal, "Subcommand #{opts.subcommand}.#{command.subcommand} is not matched"
528
- end
529
-
530
- when :build
531
- version = args.expect(0..1)
532
- state_file = File.expand_path(opts.build!.state || DEFAULT_STATE_FILE)
533
- FileUtils.rm_f(state_file)
534
- program.build(opts.build!.database, version, state_file, opts.build!.no_cache?)
535
-
536
- when :make
537
- command = opts.make!
538
- case command.subcommand
539
- when :clean
540
- args.expect(0)
541
- program.make_clean(command.clean!.all?)
542
- else
543
- version = args.expect(0..1)
544
- program.make(opts.make!.database, version, opts.make!.no_cache?)
545
- end
546
-
547
- when :load
548
- version_or_file = args.expect(1)
549
- program.load(opts.load!.database, version_or_file)
550
-
551
- when :save
552
- version, file = args.expect(1..2)
553
- program.save(version, file)
554
-
555
- when :drop
556
- command = opts.drop!
557
- case command.subcommand
558
- when :users
559
- database = args.extract(0..1) || program.project.database.name
560
- args.expect(0)
561
- program.drop_users(database)
562
- else
563
- program.drop(args.expect(0..1), opts.drop!.all?)
564
- end
565
-
566
- when :diff
567
- mark = opts.diff!.mark
568
- tables = opts.diff!.tables
569
- no_tables = opts.diff!.notables
570
- tables.nil? && no_tables.nil? || tables ^ no_tables or
571
- raise Error, "--tables and --no-tables options are exclusive"
572
- select = tables ? :tables : (no_tables ? :no_tables : :all)
573
- from, to = args.expect(0..2)
574
- program.diff(from, to, mark, select)
575
-
576
- when :migrate
577
- raise NotYet
578
-
579
- when :prepare
580
- cmd = opts.prepare!.subcommand || :release
581
- case cmd
582
- when :release; program.prepare_release(args.expect(0..1))
583
- when :feature; program.prepare_feature(args.expect(1))
584
- when :migration; program.prepare_migration(args.expect(0..1))
585
- when :schema; program.prepare_schema(args.expect(1))
586
- when :diff; program.prepare_diff(args.expect(0..1))
587
- else
588
- raise Prick::Internal, "Subcommand #{opts.subcommand}.#{cmd} is not matched"
589
- end
590
-
591
- when :include
592
- cmd = opts.include!.subcommand || :feature
593
- case cmd
594
- when :feature; program.include_feature(args.expect(1))
595
- else
596
- raise Prick::Internal, "Subcommand #{opts.subcommand}.#{cmd} is not matched"
597
- end
598
-
599
- when :check
600
- args.expect(0)
601
- program.check
602
-
603
- when :create
604
- cmd = opts.create!.subcommand || :release
605
- case cmd
606
- when :release; program.create_release(args.expect(0..1))
607
- when :prerelease; program.create_prerelease(args.expect(0..1))
608
- when :feature; program.create_feature(args.expect(1))
609
- else
610
- raise Prick::Internal, "Subcommand #{opts.subcommand}.#{cmd} is not matched"
611
- end
612
-
613
- when :cancel
614
- cmd = opts.cancel!.subcommand
615
- case cmd
616
- when :release; program.cancel_release(args.expect(1))
617
- when nil; raise Prick::Error, "'cancel' subcommand requires a release argument"
618
- else
619
- raise Prick::Internal, "Subcommand #{opts.subcommand}.#{cmd} is not matched"
620
- end
621
-
622
- when :generate
623
- cmd = opts.generate!.subcommand
624
- case cmd
625
- when :schema; program.generate_schema
626
- when :migration; program.generate_migration
627
- when nil; raise Prick::Error, "'generate' subcommand requires a 'schema' or 'migration' argument"
628
- else
629
- raise Prick::Internal, "Subcommand #{opts.subcommand}.#{cmd} is not matched"
630
- end
631
-
632
- when :upgrade
633
- args.expect(0)
634
- program.upgrade
635
-
636
- when :backup
637
- program.backup(args.expect(0..1))
638
-
639
- when :restore
640
- program.restore(args.expect(0..1))
641
- else
642
- raise Prick::Internal, "Subcommand #{opts.subcommand} is not matched"
643
- end
644
-
645
- rescue Prick::Fail => ex # Handling of Fail has to come first because Fail < Error
646
- ShellOpts.fail(ex.message)
647
- rescue Prick::Error => ex
648
- ShellOpts.error(ex.message)
472
+ rescue RuntimeError, IOError, ShellOpts::Failure, Prick::Failure, Prick::Build::PostgresError => ex
473
+ ShellOpts.failure(ex.message)
649
474
  end
650
475
 
651
- __END__
652
-
653
- # Awaits support for sections in ShellOpts
654
- HELP = %(
655
- OPTIONS
656
- -n, --name=NAME
657
- -C, --directory=DIR
658
- -h, --help
659
- -v, --verbose
660
- --version
661
-
662
- COMMANDS
663
- INITIALIZATION
664
- init --user=USER [DIR]
665
-
666
- INFO COMMANDS
667
- info
668
- list releases --migrations --cancelled
669
- list migrations
670
- list upgrades --all
671
-
672
- BUILDING
673
- build -d DATABASE -C --nocache [TAG]
674
- make -d DATABASE -C --nocache [TAG]
675
- make clean -a
676
- load -d DATABASE VERSION|FILE
677
- save VERSION [FILE]
678
- drop --all [DATABASE]
679
- diff [FROM-DATABASE|FROM-VERSION [TO-DATABASE|TO-VERSION]]
680
- migrate
681
-
682
- PREPARING RELEASES
683
- prepare release [FORK]
684
- prepare feature NAME
685
- prepare migration FROM
686
- prepare schema NAME
687
- prepare diff [VERSION]
688
- include feature FEATURE
689
- check
690
-
691
- CREATING RELEASES
692
- create release [RELEASE]
693
- create prerelease RELEASE
694
- create feature NAME
695
- cancel release RELEASE
696
-
697
- DEPLOYING RELEASES
698
- generate migration
699
- generate schema
700
- upgrade
701
- backup [FILE]
702
- restore [FILE]
703
- )