prick 0.18.0 → 0.20.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +10 -4
  3. data/README.md +7 -7
  4. data/Rakefile +3 -1
  5. data/TODO +13 -11
  6. data/bin/console +2 -1
  7. data/doc/build-yml.txt +14 -0
  8. data/exe/prick +264 -28
  9. data/lib/builder/batch.rb +147 -0
  10. data/lib/builder/builder.rb +122 -0
  11. data/lib/builder/node.rb +189 -0
  12. data/lib/builder/node_pool.rb +105 -0
  13. data/lib/builder/parser.rb +120 -0
  14. data/lib/local/command.rb +193 -0
  15. data/lib/{prick → local}/git.rb +148 -22
  16. data/lib/local/timer.rb +98 -0
  17. data/lib/prick/constants.rb +54 -66
  18. data/lib/prick/diff.rb +28 -18
  19. data/lib/prick/prick_version.rb +161 -0
  20. data/lib/prick/state.rb +80 -165
  21. data/lib/prick/version.rb +2 -163
  22. data/lib/prick.rb +43 -27
  23. data/lib/share/init/.gitignore +10 -0
  24. data/lib/share/init/.prick-context +2 -0
  25. data/lib/share/init/.rspec +3 -0
  26. data/{share/schema/schema/public → lib/share/init/migration}/.keep +0 -0
  27. data/lib/share/init/prick.yml +6 -0
  28. data/lib/share/init/schema/.keep +0 -0
  29. data/lib/share/init/schema/build.yml +2 -0
  30. data/lib/share/init/schema/prick/.keep +0 -0
  31. data/lib/share/init/schema/prick/build.yml +5 -0
  32. data/lib/share/init/schema/prick/data.sql +6 -0
  33. data/{share/schema → lib/share/init}/schema/prick/tables.sql +2 -3
  34. data/lib/share/init/schema/public/.keep +0 -0
  35. data/lib/share/init/spec/prick_helper.rb +1 -0
  36. data/lib/share/init/spec/prick_spec.rb +6 -0
  37. data/lib/share/init/spec/spec_helper.rb +50 -0
  38. data/lib/share/migrate/migration/build.yml +4 -0
  39. data/lib/share/migrate/migration/diff.after-tables.sql +0 -0
  40. data/lib/share/migrate/migration/diff.before-tables.sql +0 -0
  41. data/lib/share/migrate/migration/diff.tables.sql +0 -0
  42. data/lib/subcommand/prick-build.rb +55 -0
  43. data/lib/subcommand/prick-create.rb +78 -0
  44. data/lib/subcommand/prick-drop.rb +25 -0
  45. data/lib/subcommand/prick-fox.rb +62 -0
  46. data/lib/subcommand/prick-init.rb +46 -0
  47. data/lib/subcommand/prick-make.rb +202 -0
  48. data/lib/subcommand/prick-migrate.rb +37 -0
  49. data/lib/subcommand/prick-release.rb +23 -0
  50. data/lib/subcommand/prick-setup.rb +20 -0
  51. data/lib/subcommand/prick-teardown.rb +18 -0
  52. data/prick.gemspec +43 -16
  53. metadata +161 -72
  54. data/.gitignore +0 -29
  55. data/.travis.yml +0 -7
  56. data/doc/create_release.txt +0 -17
  57. data/doc/flow.txt +0 -98
  58. data/doc/migra +0 -1
  59. data/doc/migrations.txt +0 -172
  60. data/doc/notes.txt +0 -116
  61. data/doc/prick.txt +0 -114
  62. data/doc/sh.prick +0 -316
  63. data/lib/ext/algorithm.rb +0 -14
  64. data/lib/ext/fileutils.rb +0 -26
  65. data/lib/ext/forward_method.rb +0 -18
  66. data/lib/ext/pg.rb +0 -18
  67. data/lib/ext/shortest_path.rb +0 -44
  68. data/lib/prick/archive.rb +0 -124
  69. data/lib/prick/branch.rb +0 -254
  70. data/lib/prick/builder.rb +0 -205
  71. data/lib/prick/cache.rb +0 -34
  72. data/lib/prick/command.rb +0 -102
  73. data/lib/prick/database.rb +0 -82
  74. data/lib/prick/dsort.rb +0 -151
  75. data/lib/prick/ensure.rb +0 -119
  76. data/lib/prick/exceptions.rb +0 -25
  77. data/lib/prick/head.rb +0 -183
  78. data/lib/prick/migration.rb +0 -70
  79. data/lib/prick/program.rb +0 -506
  80. data/lib/prick/project.rb +0 -626
  81. data/lib/prick/rdbms.rb +0 -137
  82. data/lib/prick/schema.rb +0 -27
  83. data/lib/prick/share.rb +0 -64
  84. data/libexec/strip-comments +0 -33
  85. data/make_releases +0 -72
  86. data/make_schema +0 -10
  87. data/share/diff/diff.after-tables.sql +0 -4
  88. data/share/diff/diff.before-tables.sql +0 -4
  89. data/share/diff/diff.tables.sql +0 -8
  90. data/share/features/diff.sql +0 -2
  91. data/share/features/feature/diff.sql +0 -2
  92. data/share/features/feature/migrate.sql +0 -2
  93. data/share/features/features.sql +0 -2
  94. data/share/features/features.yml +0 -2
  95. data/share/features/migrations.sql +0 -4
  96. data/share/gitignore +0 -2
  97. data/share/migration/diff.tables.sql +0 -8
  98. data/share/migration/features.yml +0 -6
  99. data/share/migration/migrate.sql +0 -3
  100. data/share/migration/migrate.yml +0 -8
  101. data/share/migration/tables.sql +0 -3
  102. data/share/schema/build.yml +0 -14
  103. data/share/schema/schema/build.yml +0 -3
  104. data/share/schema/schema/prick/build.yml +0 -14
  105. data/share/schema/schema/prick/data.sql +0 -7
  106. data/share/schema/schema/prick/schema.sql +0 -3
  107. data/share/schema/schema/public/build.yml +0 -13
  108. data/share/schema/schema.sql +0 -3
  109. data/test_assorted +0 -192
  110. data/test_feature +0 -112
  111. data/test_refactor +0 -34
  112. data/test_single_dev +0 -83
data/lib/prick/program.rb DELETED
@@ -1,506 +0,0 @@
1
-
2
- require "prick.rb"
3
-
4
- module Prick
5
- # Implements the command line commands
6
- class Program
7
- # Lazy-constructed because Project can only be initialized when the
8
- # directory structure is present
9
- def project() @project ||= Project.load end
10
-
11
- attr_accessor :quiet
12
- attr_accessor :verbose
13
- attr_accessor :current_directory # Path to the directory where prick was called from
14
-
15
- def initialize(current_directory = Dir.getwd, quiet: false, verbose: false)
16
- @current_directory = current_directory
17
- @quiet = quiet
18
- @verbose = verbose
19
- end
20
-
21
- # Check if the git repository is clean. Raise an error if not
22
- def check_clean()
23
- Git.clean? or raise Error, "Repository is dirty - please commit your changes first"
24
- end
25
-
26
- # Create project directory structure
27
- def init(name, user, directory)
28
- !Project.exist?(directory) or raise Error, "Directory #{directory} is already initialized"
29
- Project.create(name, user, directory)
30
- if name != directory
31
- mesg "Initialized project #{name} in #{directory}"
32
- else
33
- mesg "Initialized project #{name}"
34
- end
35
- end
36
-
37
- def info
38
- if project.tag?
39
- puts "At v#{project.version} tag"
40
- else
41
- puts "On branch #{project.head.name}, #{project.version}"
42
- end
43
- puts " Git is " + (Git.clean? ? "clean" : "dirty")
44
- bv = project.head.version
45
- dv = project.database.version
46
- sv = project.head.schema.version
47
- puts " Database version: #{dv}" + (dv != bv ? " (mismatch)" : "")
48
- puts " Schema version : #{sv}" + (sv != bv ? " (mismatch)" : "")
49
- end
50
-
51
- def list_releases(migrations: false, cancelled: false)
52
- raise NotYet
53
- end
54
-
55
- def list_migrations
56
- raise NotYet
57
- end
58
-
59
- def list_upgrades(from = nil, to = nil)
60
- raise NotYet
61
- end
62
-
63
- def list_cache
64
- project.cache.list.each { |l| puts l }
65
- end
66
-
67
- def build(database, version, nocache)
68
- into_mesg = database && "into #{database}"
69
- version_mesg = version ? "v#{version}" : "current schema"
70
- version &&= Version.new(version)
71
- version.nil? || Git.tag?(version) or raise Error, "Can't find tag v#{version}"
72
- database = database ? Database.new(database, project.user) : project.database(version)
73
- project.build(database, version: version)
74
- project.save(database) if version && !nocache
75
- mesg "Built", version_mesg, into_mesg
76
- end
77
-
78
- def make(database, version, nocache)
79
- version &&= Version.new(version)
80
- version.nil? || Git.tag?(version) or raise Error, "Can't find tag v#{version}"
81
- if !nocache && version && project.cache.exist?(version)
82
- load(database, version)
83
- else
84
- build(database, version, nocache)
85
- end
86
- end
87
-
88
- def make_clean(all)
89
- project.cache.clean.each { |file| mesg "Removed cache file #{File.basename(file)}" }
90
- drop(nil, all)
91
- end
92
-
93
- def load(database, file_or_version)
94
- check_owned(database) if database
95
- into_mesg = database && "into #{database}"
96
- if version = Version.try(file_or_version)
97
- database = database ? Database.new(database, project.user) : project.database(version)
98
- project.load(database, version: version)
99
- mesg "Loaded v#{version}", into_mesg, "from cache"
100
- else
101
- file = file_or_version
102
- project.load(database, file: norm_path(file))
103
- mesg "Loaded #{File.basename(file)}", into_mesg
104
- end
105
- end
106
-
107
- def save(version, file)
108
- database = project.database(version)
109
- database.exist? or raise "Can't find database '#{database}'"
110
- project.save(database, file: norm_path(file))
111
- mesg "Saved #{database} to #{file || 'cache'}"
112
- end
113
-
114
- def drop(database, all)
115
- database.nil? || !all or raise Error, "Can't use --all when database is given"
116
- if database
117
- check_owned(database)
118
- dbs = [database]
119
- else
120
- dbs = Rdbms.list_databases(Prick.database_re(project.name))
121
- dbs << project.name if all && project.database.exist?
122
- end
123
- dbs += Rdbms.list_databases(Prick.tmp_databases_re(project.name)) # FIXME: Only used in dev
124
- dbs.each { |db|
125
- Rdbms.drop_database(db)
126
- mesg "Dropped database #{db}"
127
- }
128
- end
129
-
130
- # `select` is a tri-state variable that can be :tables, :no_tables, or :all
131
- # (or any other value)
132
- def diff(from, to, mark, select)
133
- diff = project.diff(from && Version.new(from), to && Version.new(to))
134
- if !diff.same?
135
- if select != :tables && !diff.before_table_changes.empty?
136
- puts "-- BEFORE TABLE CHANGES" if mark
137
- puts diff.before_table_changes
138
- end
139
- if select != :no_tables && !diff.table_changes.empty?
140
- puts "-- TABLE CHANGES" if mark
141
- puts diff.table_changes
142
- end
143
- if select != :tables && !diff.after_table_changes.empty?
144
- puts "-- AFTER TABLE CHANGES" if mark
145
- puts diff.after_table_changes
146
- end
147
- end
148
- end
149
-
150
- def migrate
151
- raise NotYet
152
- end
153
-
154
- def prepare_release(fork)
155
- project.prepare_release(fork)
156
- end
157
-
158
- def prepare_feature(name)
159
- raise NotYet
160
- end
161
-
162
- def prepare_migration(from = nil)
163
- raise NotYet
164
- end
165
-
166
- def prepare_schema(name)
167
- project.prepare_schema(name)
168
- end
169
-
170
- def prepare_diff(version = nil)
171
- # Helpful check to ensure the user has built the current version
172
- # Diff.same?(to_db, database) or
173
- # raise Error, "Schema and project database are not synchronized"
174
-
175
- project.prepare_diff(version || project.version)
176
- if FileUtils.compare_file(TABLES_DIFF_PATH, TABLES_DIFF_SHARE_PATH)
177
- mesg "Created diff. No table changes found, no manual migration updates needed"
178
- else
179
- mesg "Created diff. Please inspect #{TABLES_DIFF_PATH} and incorporate the"
180
- mesg "changes in #{MIGRATION_DIR}/migrate.sql"
181
- end
182
- end
183
-
184
- def include(name)
185
- raise NotYet
186
- end
187
-
188
- def check
189
- version ||=
190
- if project.prerelease? || project.migration?
191
- project.branch.base_version
192
- else
193
- project.branch.version
194
- end
195
- project.check_migration(version)
196
- end
197
-
198
- def create_release(version = nil)
199
- if project.prerelease_branch?
200
- raise NotYet
201
- elsif project.release_branch?
202
- project.create_release(Version.new(version))
203
- else
204
- raise Error, "You need to be on a release or pre-release branch to create a new release"
205
- end
206
- mesg "Created release v#{project.head.version}"
207
- end
208
-
209
- def create_prerelease(version = nil)
210
- raise NotYet
211
- end
212
-
213
- def create_feature(name)
214
- raise NotYet
215
- end
216
-
217
- def cancel(version)
218
- raise NotYet
219
- end
220
-
221
- def generate_schema
222
- project.generate_schema
223
- end
224
-
225
- def generate_migration
226
- project.generate_migration
227
- end
228
-
229
- def upgrade
230
- raise NotYet
231
- end
232
-
233
- # TODO: Create a Backup class and a Project#backup_store object
234
- def backup(file = nil)
235
- path = norm_path(file) ||
236
- File.join(SPOOL_DIR, "#{project.name}-#{Time.now.utc.strftime("%Y%m%d-%H%M%S")}.sql.gz")
237
- project.save(file: path)
238
- mesg "Backed-up database to #{file}"
239
- end
240
-
241
- def restore(file = nil)
242
- path = norm_path(file) || Dir.glob(File.join(SPOOL_DIR, "#{name}-*.sql.gz")).sort.last
243
- File.exist?(path) or raise Error, "Can't find #{file || "any backup file"}"
244
- project.load(file: path)
245
- mesg "Restored database from #{file}"
246
- end
247
-
248
- protected
249
- def check_owned(database)
250
- database =~ ALL_DATABASES_RE or raise Error, "Not a prick database: #{database}"
251
- project_name = $1
252
- project_name == project.name or raise Error, "Database not owned by this prick project: #{database}"
253
- end
254
-
255
- # Expand relative path with respect to the directory where prick was called
256
- # from. Return nil if file is nil
257
- def norm_path(file)
258
- if file && !file.start_with?("/")
259
- File.join(current_directory, file)
260
- else
261
- file
262
- end
263
- end
264
-
265
- def mesg(*args) puts args.compact.grep(/\S/).join(' ') if !quiet end
266
- def verb(*args) puts args.compact.grep(/\S/).join(' ') if verbose end
267
- end
268
- end
269
-
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
-