prick 0.29.2 → 0.30.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/TODO +2 -0
- data/exe/prick +290 -518
- data/lib/prick/builder/batch.rb +1 -4
- data/lib/prick/builder/builder.rb +15 -9
- data/lib/prick/builder/node.rb +3 -2
- data/lib/prick/builder/node_pool.rb +3 -1
- data/lib/prick/builder/parser.rb +2 -1
- data/lib/prick/constants.rb +12 -12
- data/lib/prick/diff.rb +2 -2
- data/lib/prick/environment.rb +23 -10
- data/lib/prick/local/command.rb +8 -2
- data/lib/prick/local/fmt.rb +56 -0
- data/lib/prick/prick_version.rb +1 -1
- data/lib/prick/share/init/{.gitignore → dot.gitignore} +1 -1
- data/lib/prick/share/init/prick.environment.yml +16 -0
- data/lib/prick/share/init/prick.yml +3 -3
- data/lib/prick/share/init/schema/prick/build.yml +11 -2
- data/lib/prick/share/init/schema/prick/tables.sql +30 -9
- data/lib/prick/share/init/schema/prick/views.sql +6 -0
- data/lib/prick/state.rb +297 -95
- data/lib/prick/subcommand/prick-build.rb +26 -20
- data/lib/prick/subcommand/prick-clean.rb +5 -5
- data/lib/prick/subcommand/prick-create.rb +41 -6
- data/lib/prick/subcommand/prick-drop.rb +57 -14
- data/lib/prick/subcommand/prick-fox.rb +1 -1
- data/lib/prick/subcommand/prick-init.rb +25 -18
- data/lib/prick/subcommand/prick-list.rb +99 -0
- data/lib/prick/subcommand/prick-make.rb +8 -8
- data/lib/prick/subcommand/prick-migrate.rb +8 -7
- data/lib/prick/subcommand/prick-release.rb +4 -2
- data/lib/prick/subcommand/prick-set.rb +52 -0
- data/lib/prick/subcommand/prick-setup.rb +3 -13
- data/lib/prick/subcommand/prick-teardown.rb +13 -9
- data/lib/prick/subcommand/subcommand.rb +12 -0
- data/lib/prick/version.rb +1 -1
- data/lib/prick.rb +54 -15
- metadata +9 -5
- data/lib/prick/share/init/schema/prick/data.sql +0 -6
- 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
|
-
|
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
|
-
-
|
37
|
-
Override
|
34
|
+
-p,project-file=PRICK-FILE
|
35
|
+
Override project file. Default is 'prick.yml'
|
38
36
|
|
39
|
-
-
|
40
|
-
Override
|
37
|
+
-e,environment-file=ENVIRONMENT-FILE
|
38
|
+
Override the environment file. Default is 'prick.environment.yml'
|
41
39
|
|
42
|
-
-
|
43
|
-
Override
|
40
|
+
-s,state-file=STATE-FILE
|
41
|
+
Override state file. Default is '.prick-state.yml'
|
44
42
|
|
45
|
-
-
|
46
|
-
|
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
|
-
|
49
|
-
|
48
|
+
setup! -- [OWNER@]DATABASE [ENVIRONMENT] @ Create and set current database
|
49
|
+
Create database and owner and set the current database
|
50
50
|
|
51
|
-
|
52
|
-
|
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
|
-
|
55
|
-
|
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
|
-
|
58
|
-
|
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
|
-
|
65
|
-
|
63
|
+
get.username!
|
64
|
+
Print the name of the current database owner
|
66
65
|
|
67
|
-
|
68
|
-
|
66
|
+
get.environment!
|
67
|
+
Print the current environment
|
69
68
|
|
70
|
-
|
71
|
-
|
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.
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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
|
-
|
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
|
85
|
-
|
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!
|
88
|
-
|
114
|
+
drop.owner!
|
115
|
+
Drop database owner
|
89
116
|
|
90
|
-
|
91
|
-
|
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
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
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
|
-
|
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
|
-
#
|
141
|
-
|
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
|
-
#
|
154
|
-
|
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,
|
159
|
-
|
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
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
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.
|
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
|
-
#
|
183
|
-
|
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
|
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
|
-
|
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 :
|
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
|
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
|
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
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
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 :
|
238
|
-
Prick::SubCommand.
|
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
|
376
|
+
when :data!
|
242
377
|
raise NotImplementedError
|
378
|
+
when :schema!
|
379
|
+
Prick::SubCommand.drop_schema(database, schemas)
|
243
380
|
else
|
244
|
-
|
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
|
-
|
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
|
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 :
|
273
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
388
|
-
|
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
|
-
)
|