prick 0.18.0 → 0.20.2

Sign up to get free protection for your applications and to get access to all the features.
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
-