prick 0.2.0 → 0.3.0

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -5
  3. data/Gemfile +4 -1
  4. data/TODO +3 -0
  5. data/doc/prick.txt +114 -0
  6. data/exe/prick +224 -370
  7. data/lib/ext/fileutils.rb +11 -0
  8. data/lib/ext/forward_method.rb +18 -0
  9. data/lib/ext/shortest_path.rb +44 -0
  10. data/lib/prick.rb +17 -9
  11. data/lib/prick/branch.rb +254 -0
  12. data/lib/prick/builder.rb +141 -0
  13. data/lib/prick/command.rb +19 -11
  14. data/lib/prick/constants.rb +42 -20
  15. data/lib/prick/database.rb +5 -3
  16. data/lib/prick/diff.rb +47 -0
  17. data/lib/prick/exceptions.rb +15 -3
  18. data/lib/prick/git.rb +46 -21
  19. data/lib/prick/migration.rb +165 -185
  20. data/lib/prick/program.rb +238 -0
  21. data/lib/prick/project.rb +266 -358
  22. data/lib/prick/rdbms.rb +2 -2
  23. data/lib/prick/schema.rb +19 -88
  24. data/lib/prick/share.rb +64 -0
  25. data/lib/prick/state.rb +137 -0
  26. data/lib/prick/version.rb +34 -14
  27. data/libexec/strip-comments +33 -0
  28. data/make_releases +48 -345
  29. data/make_schema +10 -0
  30. data/prick.gemspec +11 -22
  31. data/share/feature_migration/diff.sql +2 -0
  32. data/share/feature_migration/migrate.sql +2 -0
  33. data/share/release_migration/diff.sql +3 -0
  34. data/share/release_migration/features.yml +6 -0
  35. data/share/release_migration/migrate.sql +5 -0
  36. data/share/release_migration/migrate.yml +5 -0
  37. data/share/schema/build.yml +14 -0
  38. data/share/schema/schema.sql +5 -0
  39. data/share/schemas/build.yml +3 -0
  40. data/share/schemas/prick/build.yml +14 -0
  41. data/share/schemas/prick/data.sql +1 -2
  42. data/share/schemas/prick/schema.sql +0 -15
  43. data/share/schemas/prick/tables.sql +17 -0
  44. data/share/schemas/public/.keep +0 -0
  45. data/share/schemas/public/build.yml +14 -0
  46. data/share/schemas/public/schema.sql +3 -0
  47. data/test_assorted +192 -0
  48. data/test_feature +112 -0
  49. data/test_single_dev +83 -0
  50. metadata +34 -61
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7a41038c7beeb2bb1503ccb199cc45622d6fbe28e113003b98e8e78e10658a37
4
- data.tar.gz: 59cb5055863ce2cd63ad9db5a2adf9a0de33d4386bca210dd8e9f25f602bb5e1
3
+ metadata.gz: cb7c2d20ea8aa16ba957f5139e00b02eec90d92a16316d9a468b97df7f83bc93
4
+ data.tar.gz: 6c2a0acd245344a1bb302aede789bb964757462786aebdc5fec14ea33f43e42f
5
5
  SHA512:
6
- metadata.gz: 0b19d6f150e840101f60aa9337583257a0f72e36e2eb7a84b1403063b274099e7a27716aecd2ccaaaf09484a4f5d4b1f9da6eebde340fe9b69da8bab8342528e
7
- data.tar.gz: 7b71790136d8de6e2f3c77a58fb5d1e432bbbe6f0c910ada86608e05f759c8ea68d255f1cc038ce2b5efebfb7e379f0bb2f607a94cfd99b5f26cf3665f135130
6
+ metadata.gz: 4d350899a5591bc2c6b8d2b6f88948ddf39a6146a535411c1affccf3f5f32dcee4ccb8b30ea0e19060d7bc6a6d1c21064ae10dacf9f19aa3997d04fd2466c892
7
+ data.tar.gz: fad2bbb8a50f18c779160bc17308072a94fd4ca98b1db76c3c16724eafe1c4128c4df4b0485051a136a19cf0315daff9b19dd4035dfe54cdbf624376c7c3c4c4
data/.gitignore CHANGED
@@ -19,10 +19,8 @@
19
19
 
20
20
  # Put your personal ignore files in /home/clr/.config/git/ignore
21
21
 
22
- # Temporary ignores
23
- /releases/
24
- /migrations/
25
- /prick.sh
26
-
27
22
  # Ignore bundle binstubs
28
23
  /bin/prick
24
+
25
+ # Ignore development testing dir
26
+ /dir
data/Gemfile CHANGED
@@ -1,6 +1,9 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ git_source(:github) {|repo_name| "https://github.com/clrgit/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in prick.gemspec
6
6
  gemspec
7
+
8
+ gem "rake", "~> 12.0"
9
+ gem "rspec", "~> 3.0"
data/TODO ADDED
@@ -0,0 +1,3 @@
1
+
2
+ o Make it possible to execute prick in any subdirecty instead of only in the root
3
+
@@ -0,0 +1,114 @@
1
+
2
+
3
+ MIGRATION STATE FILES
4
+ .prick-migration (State file)
5
+ version: Version
6
+ The target version. The result of running the migration on the base
7
+ release
8
+ base_version: Version
9
+ Base version. Running the migration on a base release yields a release
10
+ of with the same version as the `version` property
11
+
12
+ The 0.0.0 version has base_version equal to nil. A Feature has version
13
+ equal to its base version.
14
+
15
+ Note that while a release's .prick-migration file lives in the release
16
+ directory, it's .prick-features file and the migrations lives in the
17
+ directory of the base release. This separation supports the
18
+ single-developer workflow where the next release is not known beforehand
19
+
20
+ .prick-features (State file)
21
+ features: Array
22
+ A list of features versions
23
+
24
+ MIGRATION FILES
25
+ migrate.sql
26
+ features.sql
27
+ diff.sql
28
+
29
+
30
+ MIGRATION FILE STRUCTURE
31
+ releases/
32
+ 0.0.0/
33
+ .prick-migration -> version: 0.0.0, base_version: nil
34
+ .prick-features -> [feature_a]
35
+ feature_a/
36
+ .prick-migration -> version: nil, base_version: 0.0.0
37
+ .prick-features -> []
38
+ feature_b/ (rebased)
39
+ .prick-migration -> version: 0.2.0, base_version: 0.2.0-pre.1
40
+ .prick-features -> []
41
+
42
+ 0.1.0/
43
+ .prick-migration -> version: 0.1.0, base_version: 0.0.0
44
+ feature_b/ symlinks to ../0.0.0/feature_b/
45
+
46
+ 0.1.0/ (wip - single developer work flow)
47
+ .prick-migration -> version: 0.1.0, base_version: 0.0.0
48
+ .prick-features -> [feature_c]
49
+ feature_c/
50
+ ...
51
+
52
+ 0.2.0/ (doing a pre-release)
53
+ .prick-migration -> version: 0.2.0-pre.1, base_version: 0.1.0
54
+
55
+ migrations/
56
+ 0.0.0_0.1.0/
57
+ .prick-migration -> version: 0.1.0, base_version: 0.0.0
58
+ .prick-features -> []
59
+
60
+
61
+ NOTES
62
+ #
63
+ # Distinguish between running a migration 0.1.0 -> 0.2.0 and running the
64
+ # migration in the 0.2.0 directory in the single-developer workflow
65
+ #
66
+ # prick migrate
67
+ # On a tag: Migrate to that tag
68
+ # On a branch: Run migrations in the release directory
69
+ #
70
+ # prick migrate 0.2.0 <- the version number reflects where to find the migration
71
+ # Runs the migration files in the release directory
72
+ #
73
+ # prick migrate 0.1.0
74
+ # Runs the migration files in the base release directory
75
+ #
76
+ #
77
+ # prick build
78
+ # Builds the current schema into the project database
79
+ #
80
+ # prick build 0.1.0
81
+ # Builds the given schema into a versioned database
82
+
83
+
84
+
85
+
86
+
87
+
88
+
89
+
90
+
91
+
92
+
93
+
94
+
95
+ ######################
96
+
97
+ PRICK FILES
98
+ ./prick-version
99
+ Contains just one line with the version of the prick command that should be
100
+ used with this project (eg. 'prick-0.1.0'). Prick checks this file at
101
+ startup and fails if the required version doesn't match the current command
102
+
103
+ ./prick
104
+ project_name
105
+ Name of the project
106
+
107
+ ./releases/*/.prick
108
+ base_version
109
+ The base version of this release. nil for release 0.0.0
110
+ features
111
+ List of features in a release based on this release. Initially empty
112
+ but filled in when the directory is prepared for a subsequent release.
113
+ To find the set of features in the current release, inspect the prick
114
+ file of the base_version in this branch
data/exe/prick CHANGED
@@ -1,15 +1,18 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'prick.rb'
4
+ require 'prick/program.rb'
4
5
 
5
6
  require 'shellopts'
6
7
  require 'indented_io'
8
+
7
9
  require 'tempfile'
8
- require 'ext/algorithm.rb'
9
10
 
10
11
  include ShellOpts
12
+ include Prick
13
+
14
+ PROGRAM = File.basename($0)
11
15
 
12
- # TODO: Backup & restore
13
16
  SPEC = %(
14
17
  n,name=NAME
15
18
  C,directory=DIR
@@ -18,37 +21,30 @@ SPEC = %(
18
21
  q,quiet
19
22
  version
20
23
 
21
- init!
22
- info!
23
- status!
24
- history!
25
-
26
- checkout!
24
+ init! u,user=USER
27
25
 
28
- feature!
29
- rebase!
26
+ info!
27
+ list! list.releases! m,migrations c,cancelled list.migrations! list.upgrades! a,all
30
28
 
31
- create! create.release! create.prerelease! create.feature! create.migration!
32
- increment! increment.prerelease!
29
+ build! d,database=DATABASE C,nocache
30
+ make!
31
+ load! d,database=DATABASE
32
+ save! d,database=DATABASE
33
+ migrate!
33
34
 
34
- prepare! prepare.release! prepare.prerelease! prepare.feature! prepare.migration!
35
- include!
36
- commit!
37
- prerelease!
38
- release!
35
+ prepare! prepare.release! prepare.migration! prepare.schema! prepare.diff!
36
+ include! include.feature!
37
+ check!
39
38
 
40
- list! list.databases! list.releases! list.prereleases!
41
- build!
42
- use! f,file=FILE
43
- load! f,file=FILE
44
- reload! f,file=FILE
45
- unload!
46
- clean!
39
+ create! create.release! create.prerelease! create.feature!
40
+ cancel! cancel.release!
47
41
 
48
- migrate!
42
+ upgrade!
43
+ backup!
44
+ restore!
49
45
  )
50
46
 
51
- USAGE = "-h -v -n NAME -C DIR COMMAND"
47
+ USAGE = "Usage: #{PROGRAM} -h -v -n NAME -C DIR COMMAND" # FIXME: Why doesn't shellopts include PROGRAM?
52
48
 
53
49
  HELP = %(
54
50
  NAME
@@ -75,387 +71,246 @@ HELP = %(
75
71
  Print prick version
76
72
 
77
73
  COMMANDS
78
- INFO COMMANDS
79
- init [DIR]
80
- Initialize a project directory
74
+ INITIALIZATION
75
+ init [DIR] --user=USER
76
+ Initialize a project in the given directory. DIR defaults to the
77
+ current directory. The USER is the postgres user, it defaults to
78
+ the project name
81
79
 
80
+ INFO COMMANDS
82
81
  info
83
- Print project information
84
82
 
85
- status
86
- Short status
87
-
88
- GENERAL COMMANDS
89
- checkout
90
- As git checkout but does some extra work behind the scenes
83
+ list releases --migrations --cancelled
84
+ list migrations
85
+ list upgrades --all
86
+ List releases/migrations/upgrades
87
+
88
+ BUILDING
89
+ build -d database -C --nocache [version]
90
+ Builds the current database from the content in the schemas/ directory.
91
+ With an explicit version the given version is built or loaded from cache
92
+ into the associated versioned database. The -C argument force a build even
93
+ if a cache file is present. The -d option overrides the database
94
+
95
+ make
96
+ Not yet implemented
97
+
98
+ load -d database file|version
99
+ Load a version or file into a database. If the argument is a version the
100
+ assocated versioned database will be loaded from cache. If the argument is
101
+ a file the project database is loaded. The -d option overrides what
102
+ database is used. This is often used to load a specific version into the
103
+ project database ('prick load -d <project-name> <version>') or to load into
104
+ an unrelated database not controlled by prick
105
+
106
+ save -d database [file]
107
+ Save the project database to the given file. Default file name is the
108
+ username suffixed with project name, custom name, and branch
91
109
 
92
110
  migrate
93
- Migrate from the current branch in the database to the current branch
94
-
95
-
96
- DEVELOPER COMMANDS
97
- create feature FEATURE
98
- Create a new feature branch and a feature directory under
99
- features/<base-version>. Note that the base version is the base version
100
- of the pre-release
101
-
102
- Features are named <feature>-<base-version>
103
-
104
- prepare migration
105
- Create migration files from the base release to the current schema. It
106
- does not overwrite existing migration files
111
+ Not yet implemented
107
112
 
108
- rebase VERSION
109
- Rebase the feature to HEAD of the release. The rebased feature lives on
110
- a branch of its own and have a symlink from the new base release to the
111
- feature implementation in the original release. Rebased features are
112
- named <feature>-<rebase-version>
113
+ PREPARING RELEASES
114
+ prepare release
115
+ Populate the current migration directory with migration files
113
116
 
117
+ prepare feature NAME
118
+ Create and populate a feature as a subdirectory of the current
119
+ directory. Also prepares the current release directory
114
120
 
115
- RELEASE MANAGER COMMANDS
116
- migrate VERSION|patch|minor|major
117
- Prepare migration from current release to the given version. The branch
118
- will be named <old-version>_<new-version>. Note that the generated
119
- files don't include data migrations so it may be easier to first create a
120
- prerelease and include missing features and then use that release as base
121
- for an empty migration release that just changes the version number
121
+ prepare migration FROM
122
+ Create and populate a migration directory
122
123
 
123
- (need some thought)
124
+ prepare schema NAME
125
+ Create and populate a new schema directory. Existing files and
126
+ directories are kept
124
127
 
125
- prepare VERSION|patch|minor|major
126
- Prepare a new release by branching to <version>.pre.0 and creating a
127
- features directory for the _base_ version. If version is one of the
128
- names patch, minor, or major then the version is constructed by
129
- incrementing the given part of the base release's version
128
+ prepare diff [VERSION]
130
129
 
131
- include FEATURE
132
- Merge a feature branch into the prepared release
130
+ include feature FEATURE
131
+ Include the given feature in the current pre-release
133
132
 
134
- prerelease
135
- Bumps the pre-release serial and create a new branch
133
+ check
134
+ Check that the current migration applied to the base version yields the
135
+ same result as loading the current schema
136
136
 
137
- release [VERSION]
138
- Create a new release. The version is not used if the release was prepared
137
+ CREATING RELEASES
138
+ create release [RELEASE]
139
+ Prepare a release and create release directory and migration file
140
+ before tagging and branching to a release branch. The RELEASE argument
141
+ can be left out if the current branch is a prerelease branch
139
142
 
140
-
141
- MANIPULATING DATABASES AND RELEASES
142
- list [databases|releases|prereleases]
143
- Output a list of databases, releases, or prereleases. List databases by
144
- default
145
-
146
- build [VERSION]
147
- Build the schema in the project database. If a version is given, the
148
- version is built into the versioned database and the release cached
149
- on disk
150
-
151
- load
152
- Load the current cache into the project database
153
-
154
- load -f FILE [VERSION]
155
- Load the cached release into its versioned database. It is an error if
156
- the release isn't cached - use build to create it
143
+ create prerelease RELEASE
144
+ Prepare a release and create release directory and migration file
145
+ before branching to a prerelease branch
157
146
 
158
- reload [VERSION]
159
- Clear the versioned database and reload the release from the cache
147
+ create feature NAME
148
+ Prepare a feature before branching to a feature branch
160
149
 
161
- unload [VERSION]
162
- Delete the versioned database. Default is to delete all project related
163
- databases
150
+ cancel release RELEASE
151
+ Cancel a release. Since tags are immutable, the release is cancelled by
152
+ added a special cancel-tag to the release that makes prick ignore it
164
153
 
165
- clean [VERSION]
166
- Delete the cached release. Default is to delete all cached releases
154
+ DEPLOYING RELEASES
155
+ upgrade
156
+ Migrate the database to match the current schema
167
157
 
158
+ backup [FILE]
159
+ Saves a backup of the database to the given file or to the var/spool
160
+ directory
168
161
 
162
+ restore [FILE]
163
+ Restore the database from the given backup file or from the latest
164
+ backup in the var/spool directory
169
165
  )
170
166
 
171
- INFO_PARAMS = {
172
- "Releases": :releases,
173
- "Pre-releases": :prereleases,
174
- "Features": :features,
175
- "Ignored releases": :ignored_release_nodes,
176
- "Ignored features": :ignored_feature_nodes,
177
- "Orphan disk features": :orphan_feature_nodes,
178
- "Orphan disk releases": :orphan_release_nodes,
179
- "Orphan git branches": :orphan_git_branches
180
- }
181
-
182
- def info(project)
183
- for header, member in INFO_PARAMS
184
- elements = project.send(member)
185
- puts header
186
- if elements.empty?
187
- puts " [none]"
188
- else
189
- if member == :features
190
- project.features.each { |release, features|
191
- puts " #{release}"
192
- features.each { |feature| puts " #{feature.feature}" }
193
- }
194
- else
195
- elements.sort.each { |element| puts " #{element}" }
196
- end
197
- end
198
- end
199
- end
200
-
201
- def compute_version(project, arg)
202
- if arg.nil?
203
- nil
204
- elsif %w(major minor patch).include?(arg)
205
- project.release.version.increment(arg.to_sym)
206
- else
207
- Prick::Version.new(arg)
208
- end
209
- end
210
167
 
211
168
  opts, args = ShellOpts.as_struct(SPEC, ARGV)
212
169
 
213
170
  # Handle --help
214
- if opts.help?
215
- begin
216
- file = Tempfile.new("prick")
217
- file.puts HELP.split("\n").map { |l| l.sub(/^ /, "") }
218
- file.flush
219
- system "less #{file.path}"
220
- ensure
221
- file.close
222
- end
223
- exit
224
- end
171
+ if opts.help?
172
+ begin
173
+ file = Tempfile.new("prick")
174
+ file.puts HELP.split("\n").map { |l| l.sub(/^ /, "") }
175
+ file.flush
176
+ system "less #{file.path}"
177
+ ensure
178
+ file.close
179
+ end
180
+ exit
181
+ end
225
182
 
226
183
  # Handle --version
227
- if opts.version?
228
- puts "prick-#{Prick::VERSION}"
229
- exit
184
+ if opts.version?
185
+ puts "prick-#{VERSION}"
186
+ exit
230
187
  end
231
188
 
232
189
  begin
233
190
  # Honor -C option
234
191
  if opts.directory
235
- begin
236
- Dir.chdir(opts.directory)
237
- rescue Errno::ENOENT
238
- raise Prick::Error, "Can't cd to '#{directory}'"
192
+ if File.exist?(opts.directory)
193
+ begin
194
+ Dir.chdir(opts.directory)
195
+ rescue Errno::ENOENT
196
+ raise Prick::Error, "Can't cd to '#{opts.directory}'"
197
+ end
198
+ else
199
+ raise Prick::Error, "Can't find directory: #{opts.directory}"
239
200
  end
240
201
  end
241
202
 
242
- name = opts.name || ENV["PRICK_PROJECT"] || File.basename(Dir.getwd)
243
- verbose = opts.verbose?
203
+ # Create program object
204
+ program = Program.new(quiet: opts.quiet?, verbose: opts.verbose?)
244
205
 
245
- # :init! is processed separately because the project object can't be
246
- # constructed before the directory has been initialized
206
+ # Handle init command
247
207
  if opts.subcommand == :init
248
- dir = args.expect(1)
249
- Prick::Project.initialize_directory(dir)
250
- Dir.chdir(dir) {
251
- Prick::Project.initialize_project(name)
252
- }
253
- if File.basename(dir) != name
254
- puts "Initialized project #{name} in #{dir}" if !opts.quiet?
255
- else
256
- puts "Initialized project #{name}" if !opts.quiet?
257
- end
208
+ directory = args.expect(0..1)
209
+ name = opts.name || directory || File.basename(Dir.getwd)
210
+ user = opts.init.user || name
211
+ program.initialize_directory(name, user, directory || ".")
212
+ exit 0
213
+ end
214
+
215
+ # Check prick version
216
+ file = PrickVersion.new
217
+ file.exist? or raise Prick::Error, "Can't find prick version file '#{file.path}'"
218
+ VERSION == file.read.to_s or
219
+ raise Prick::Fail, ".prick-version required prick-#{file.read} but you're using prick-#{VERSION}"
220
+
221
+ # Expect a sub-command
222
+ opts.subcommand? or raise Prick::Error, "Subcomand expected"
223
+
224
+ case opts.subcommand
225
+ when :info
226
+ args.expect(0)
227
+ program.info
228
+
229
+ when :build
230
+ version = args.expect(0..1)
231
+ program.build(opts.build.database, version, opts.build.nocache)
232
+
233
+ when :save
234
+ file_or_version = args.expect(0..1)
235
+ program.save(opts.save.database, file_or_version)
236
+
237
+ when :load
238
+ file_or_version = args.expect(1)
239
+ program.load(opts.load.database, file_or_version)
240
+
241
+ when :make
242
+ raise NotYet
243
+
244
+ when :migrate
245
+ raise NotYet
246
+
247
+ when :list
248
+ command = opts.list
249
+ case command.subcommand
250
+ when :releases;
251
+ obj = command.releases
252
+ program.list_releases(migrations: obj.migrations?, cancelled: obj.cancelled?)
253
+ when :migrations; program.list_migrations
254
+ when :upgrades; program.list_upgrades(*args.expect(0..2).compact)
255
+ when NilClass; raise Prick::Error, "list requires a releases|migrations|upgrades sub-command"
256
+ else
257
+ raise Prick::Internal, "Subcommand #{opts.subcommand}.#{command.subcommand} is not matched"
258
+ end
259
+
260
+ when :prepare
261
+ cmd = opts.prepare.subcommand || :release
262
+ case cmd
263
+ when :release; args.expect(0); program.prepare_release
264
+ when :feature; raise NotYet
265
+ when :migration; program.prepare_migration(args.expect(1))
266
+ when :schema; program.prepare_schema(args.expect(1))
267
+ when :diff; program.prepare_diff(args.expect(0..1))
268
+ else
269
+ raise Prick::Internal, "Subcommand #{opts.subcommand}.#{cmd} is not matched"
270
+ end
271
+
272
+ when :include
273
+ cmd = opts.include.subcommand || :feature
274
+ case cmd
275
+ when :feature; program.include_feature(args.expect(1))
276
+ else
277
+ raise Prick::Internal, "Subcommand #{opts.subcommand}.#{cmd} is not matched"
278
+ end
279
+
280
+ when :check
281
+ args.expect(0)
282
+ program.check
283
+
284
+ when :create
285
+ cmd = opts.create.subcommand || :release
286
+ case cmd
287
+ when :release; program.create_release(args.expect(0..1))
288
+ when :prerelease; program.create_prerelease(args.expect(0..1))
289
+ when :feature; program.create_feature(args.expect(1))
290
+ else
291
+ raise Prick::Internal, "Subcommand #{opts.subcommand}.#{cmd} is not matched"
292
+ end
293
+
294
+ when :cancel
295
+ cmd = opts.cancel.subcommand
296
+ case cmd
297
+ when :release; program.cancel_release(args.expect(1))
298
+ when nil; raise Prick::Error, "'cancel' subcommand require a release argument"
299
+ else
300
+ raise Prick::Internal, "Subcommand #{opts.subcommand}.#{cmd} is not matched"
301
+ end
302
+
303
+ when :upgrade
304
+ args.expect(0)
305
+ program.upgrade
306
+
307
+ when :backup
308
+ program.backup(args.expect(0..1))
309
+
310
+ when :restore
311
+ program.restore(args.expect(0..1))
258
312
  else
259
- project = Prick::Project.new(name)
260
-
261
- case cmd = opts.subcommand
262
-
263
- # INFO COMMANDS #########################################################
264
- #
265
- when :info
266
- args.expect(0)
267
-
268
- puts "Current branch"
269
- puts " #{project.release&.version || 'nil'}"
270
-
271
- puts "Project database"
272
- db = project.database
273
- if db.exist?
274
- print " #{project.database.name}"
275
- print " (present)" if project.database.exist? && !project.database.loaded?
276
- print " (using #{project.database.version})" if project.database.loaded?
277
- else
278
- print " [missing]" if !project.database.exist?
279
- end
280
- puts
281
-
282
- puts "Releases"
283
- project.releases.each { |release|
284
- print " #{release}"
285
- if release.database.exist?
286
- if release.database.version
287
- print " loaded"
288
- else
289
- print " (empty database)"
290
- end
291
- end
292
- if release.cached?
293
- print ", cached"
294
- end
295
- print " <#{release.database.name}>"
296
- print "\n"
297
- }
298
- puts
299
- info(project)
300
-
301
- when :status
302
- args.expect(0)
303
- puts "On branch #{project.release}" + (project.dirty? ? " (dirty)" : "")
304
-
305
- when :history
306
- args.expect(0)
307
- history = project.release.history
308
- history.each { |release, features|
309
- puts release.to_s
310
- indent {
311
- features.map { |feature|
312
- puts "#{feature}, base release: #{feature.base_release}"
313
- }
314
- }
315
- }
316
-
317
-
318
- # GENERAL COMMANDS ######################################################
319
- #
320
- when :checkout
321
- version = args.expect(1)
322
- project.checkout(version)
323
- puts "Checked out #{version}"
324
-
325
- when :migrate
326
- project.migrate
327
-
328
-
329
- # DEVELOPER COMMANDS ####################################################
330
- #
331
- when :feature # Shorthand for 'create feature'
332
-
333
- when :rebase
334
-
335
- when :prepare
336
- args.expect(0)
337
- if object = opts.prepare.subcommand!
338
- case object
339
- when :migration
340
- project.prepare_migration
341
- puts "Prepared migration"
342
- else
343
- raise "Oops: subcommand #{opts.subcommand.inspect} not matched"
344
- end
345
- else
346
- args.expect(0)
347
- project.prepare_release
348
- puts "Prepared new release" if !opts.quiet?
349
- end
350
-
351
-
352
- # RELEASE MANAGER COMMANDS ##############################################
353
- #
354
- when :create
355
- object = opts.create.subcommand!
356
- release =
357
- case object
358
- when :release
359
- version = compute_version(project, args.expect(0..1))
360
- project.create_release(version)
361
- when :prerelease
362
- version = compute_version(project, args.expect(1))
363
- project.create_prerelease(version)
364
- when :feature
365
- project.create_feature(args.expect(1))
366
- else
367
- raise "Oops: subcommand #{opts.subcommand.inspect} not matched"
368
- end
369
- puts "Created #{object} #{release.version}" if !opts.quiet?
370
-
371
- when :increment # and 'increment prerelease'
372
- args.expect(0)
373
- release = project.increment_prerelease
374
- puts "Created prerelease #{release.version}" if !opts.quiet?
375
-
376
- when :release # Shorthand for 'create release'
377
- version = compute_version(project, args.expect(0..1))
378
- release = project.create_release(version)
379
- puts "Created release #{release.version}" if !opts.quiet?
380
-
381
- when :prerelease # Shorthand for 'create prerelease' and 'increment'
382
- release =
383
- if project.release?
384
- version = compute_version(project, args.expect(1))
385
- project.create_prerelease(version)
386
- elsif project.prerelease?
387
- args.expect(0)
388
- project.increment_prerelease
389
- end
390
- puts "Created prerelease #{release.version}" if !opts.quiet?
391
-
392
- when :include
393
- name = args.expect(1)
394
- project.include_feature(name)
395
- puts "Included feature #{name}" if !opts.quiet?
396
- puts "Please check changed files and then commit using 'prick commit'"
397
-
398
- when :commit
399
- msg = project.commit_feature
400
- puts msg if !opts.quiet?
401
- puts "Committed changes" if !opts.quiet?
402
-
403
-
404
- # MANIPULATING DATABASES AND RELEASES ###################################
405
- #
406
- when :list
407
- # TODO: Mark cached releases as such
408
- args.expect(0)
409
- case opts.list.subcommand
410
- when :databases, nil; project.databases.map(&:name)
411
- when :releases; project.releases.map(&:name)
412
- when :prereleases; project.prereleases.map(&:version)
413
- else
414
- ShellOpts.error "Illegal list type: '#{opts.list.subcommand}"
415
- end.each { |e| puts e }
416
-
417
- when :build
418
- version = args.expect(0..1)
419
- project.build(version)
420
- if version
421
- puts "Built #{version}"
422
- else
423
- puts "Built current version"
424
- end
425
-
426
- when :use
427
- file = opts.use.file
428
- version = args.expect(0..1)
429
- file || version or raise Error, "Need either a version or a -f FILE argument"
430
- file.nil? != version.nil? or raise Error, "Not both version and -f FILE arguments can be specified"
431
- file ||= project[version].archive.path
432
- project.load_database(nil, file)
433
-
434
- when :load
435
- file = opts.load.file
436
- version = args.expect(1)
437
- project.load_database(version, file)
438
-
439
- when :reload
440
- file = opts.reload.file
441
- version = args.expect(1)
442
- project.reload(version, file)
443
-
444
- when :unload
445
- version = args.expect(0..1)
446
- project.unload(version)
447
-
448
- when :clean
449
- version = args.expect(0..1)
450
- project.clean(version, project: true)
451
-
452
- when NilClass
453
- if args.size > 0
454
- ShellOpts.error "#{args.first} is not a command"
455
- end
456
- else
457
- raise "Oops: subcommand #{opts.subcommand.inspect} not matched"
458
- end
313
+ raise Prick::Internal, "Subcommand #{opts.subcommand} is not matched"
459
314
  end
460
315
 
461
316
  rescue Prick::Fail => ex # Handling of Fail has to come first because Fail < Error
@@ -464,4 +319,3 @@ rescue Prick::Error => ex
464
319
  ShellOpts.error(ex.message)
465
320
  end
466
321
 
467
-