prick 0.2.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -5
  3. data/Gemfile +4 -1
  4. data/TODO +10 -0
  5. data/doc/prick.txt +114 -0
  6. data/exe/prick +328 -402
  7. data/lib/ext/fileutils.rb +18 -0
  8. data/lib/ext/forward_method.rb +18 -0
  9. data/lib/ext/shortest_path.rb +44 -0
  10. data/lib/prick.rb +20 -10
  11. data/lib/prick/branch.rb +254 -0
  12. data/lib/prick/builder.rb +164 -0
  13. data/lib/prick/cache.rb +34 -0
  14. data/lib/prick/command.rb +19 -11
  15. data/lib/prick/constants.rb +122 -48
  16. data/lib/prick/database.rb +28 -20
  17. data/lib/prick/diff.rb +125 -0
  18. data/lib/prick/exceptions.rb +15 -3
  19. data/lib/prick/git.rb +77 -30
  20. data/lib/prick/head.rb +183 -0
  21. data/lib/prick/migration.rb +40 -200
  22. data/lib/prick/program.rb +493 -0
  23. data/lib/prick/project.rb +523 -351
  24. data/lib/prick/rdbms.rb +4 -13
  25. data/lib/prick/schema.rb +16 -90
  26. data/lib/prick/share.rb +64 -0
  27. data/lib/prick/state.rb +192 -0
  28. data/lib/prick/version.rb +62 -29
  29. data/libexec/strip-comments +33 -0
  30. data/make_releases +48 -345
  31. data/make_schema +10 -0
  32. data/prick.gemspec +14 -23
  33. data/share/diff/diff.after-tables.sql +4 -0
  34. data/share/diff/diff.before-tables.sql +4 -0
  35. data/share/diff/diff.tables.sql +8 -0
  36. data/share/migration/diff.tables.sql +8 -0
  37. data/share/migration/features.yml +6 -0
  38. data/share/migration/migrate.sql +3 -0
  39. data/share/migration/migrate.yml +8 -0
  40. data/share/migration/tables.sql +3 -0
  41. data/share/schema/build.yml +14 -0
  42. data/share/schema/schema.sql +5 -0
  43. data/share/schema/schema/build.yml +3 -0
  44. data/share/schema/schema/prick/build.yml +14 -0
  45. data/share/schema/schema/prick/data.sql +7 -0
  46. data/share/schema/schema/prick/schema.sql +5 -0
  47. data/share/{schemas/prick/schema.sql → schema/schema/prick/tables.sql} +2 -5
  48. data/{file → share/schema/schema/public/.keep} +0 -0
  49. data/share/schema/schema/public/build.yml +14 -0
  50. data/share/schema/schema/public/schema.sql +3 -0
  51. data/test_assorted +192 -0
  52. data/test_feature +112 -0
  53. data/test_refactor +34 -0
  54. data/test_single_dev +83 -0
  55. metadata +43 -68
  56. data/lib/prick/build.rb +0 -376
  57. data/lib/prick/migra.rb +0 -22
  58. data/share/schemas/prick/data.sql +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7a41038c7beeb2bb1503ccb199cc45622d6fbe28e113003b98e8e78e10658a37
4
- data.tar.gz: 59cb5055863ce2cd63ad9db5a2adf9a0de33d4386bca210dd8e9f25f602bb5e1
3
+ metadata.gz: dd62ad39d6f79354d9eb4e68e102cbe2fa45c3c83f3bb670bb67cc91faab2b6c
4
+ data.tar.gz: 1802956bd55eafd32b16ff2d473e7b8c4f22ffaa2526ab83afb1c8d271b3fe37
5
5
  SHA512:
6
- metadata.gz: 0b19d6f150e840101f60aa9337583257a0f72e36e2eb7a84b1403063b274099e7a27716aecd2ccaaaf09484a4f5d4b1f9da6eebde340fe9b69da8bab8342528e
7
- data.tar.gz: 7b71790136d8de6e2f3c77a58fb5d1e432bbbe6f0c910ada86608e05f759c8ea68d255f1cc038ce2b5efebfb7e379f0bb2f607a94cfd99b5f26cf3665f135130
6
+ metadata.gz: c8b1553cba9e5afe792b1f3119ffb9b85e23626d830b752dc98ee5bd28e4c7eeaf8e7b50acb52cfe9e32dcf935d8dcd99694bf2d1d29ebd830c1a9abcb852f38
7
+ data.tar.gz: 3a189a2dff6750afc58f01189dc86fd671b605f5281e17d725607483e0d2f24603f54cc9071145dcfa681109d971da8736a5e81be454b3b1d3d3ee055060f92f
data/.gitignore CHANGED
@@ -19,10 +19,11 @@
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
27
+
28
+ # Ignore stove-away directory
29
+ /hold
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,10 @@
1
+
2
+ o Check for commits to tags
3
+ o Accumulate version history in prick.versions instead of just having the newest
4
+ o Using rc's in migration syntax: fork-version-fork-version.rc1 ?
5
+ o Make it possible to execute prick in any subdirecty instead of only in the root
6
+ o Hack migra to create separate file(s) for table changes
7
+ o Also execute subject/ directory if only a subject.sql is found. subject.yml
8
+ should still override everything
9
+ o Track included files - this will make dependency checks much easier
10
+
data/doc/prick.txt ADDED
@@ -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,461 +1,335 @@
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
- require 'indented_io'
7
+
7
8
  require 'tempfile'
8
- require 'ext/algorithm.rb'
9
9
 
10
10
  include ShellOpts
11
+ include Prick
11
12
 
12
- # TODO: Backup & restore
13
13
  SPEC = %(
14
- n,name=NAME
15
- C,directory=DIR
16
- h,help
17
- v,verbose
18
- q,quiet
19
- version
20
-
21
- init!
22
- info!
23
- status!
24
- history!
25
-
26
- checkout!
27
-
28
- feature!
29
- rebase!
30
-
31
- create! create.release! create.prerelease! create.feature! create.migration!
32
- increment! increment.prerelease!
33
-
34
- prepare! prepare.release! prepare.prerelease! prepare.feature! prepare.migration!
35
- include!
36
- commit!
37
- prerelease!
38
- release!
39
-
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!
47
-
48
- migrate!
49
- )
50
-
51
- USAGE = "-h -v -n NAME -C DIR COMMAND"
52
-
53
- HELP = %(
54
- NAME
55
- prick - Database version management
56
-
57
- USAGE
58
- prick -v -n NAME -C DIR -h <command>
59
-
60
- OPTIONS
61
- -n, --name=NAME
14
+ -n,name=NAME
62
15
  Name of project. Defauls to the environment variable `PRICK_PROJECT` if
63
16
  set and else the name of the current directory
64
17
 
65
- -C, --directory=DIR
66
- Change to directory DIR before anything else
18
+ -C,directory=DIR
19
+ Change to directory DIR before doing anything else
67
20
 
68
- -h, --help
21
+ -h,help COMMAND...
69
22
  Print this page
70
23
 
71
- -v, --verbose
72
- Be verbose
24
+ +v,verbose
25
+ Be verbose. Repeated --verbose options increase the verbosity level
73
26
 
74
- --version
75
- Print prick version
76
-
77
- COMMANDS
78
- INFO COMMANDS
79
- init [DIR]
80
- Initialize a project directory
27
+ -q,quiet
28
+ Be quiet
81
29
 
82
- info
83
- Print project information
84
-
85
- status
86
- Short status
87
-
88
- GENERAL COMMANDS
89
- checkout
90
- As git checkout but does some extra work behind the scenes
91
-
92
- 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
107
-
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
-
114
-
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
30
+ --version
31
+ Print prick version
122
32
 
123
- (need some thought)
33
+ init! -u,user=USER [DIR]
34
+ Initialize a project in the given directory. DIR defaults to the current
35
+ directory. The USER is the postgres user, it defaults to the project name
124
36
 
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
37
+ info!
38
+ Print project information
130
39
 
131
- include FEATURE
132
- Merge a feature branch into the prepared release
40
+ list.releases! -m,migrations -c,cancelled
41
+ List releases. Include migration releases if the --migration option is
42
+ present and also include cancelled releases if the --cancelled option is
43
+ present
133
44
 
134
- prerelease
135
- Bumps the pre-release serial and create a new branch
45
+ list.migrations!
46
+ List migrations
136
47
 
137
- release [VERSION]
138
- Create a new release. The version is not used if the release was prepared
48
+ list.upgrades! [FROM [TO]]
49
+ List available upgrades
139
50
 
51
+ list.cache!
52
+ List cache files
140
53
 
141
- MANIPULATING DATABASES AND RELEASES
142
- list [databases|releases|prereleases]
143
- Output a list of databases, releases, or prereleases. List databases by
144
- default
54
+ build! -d,database=DATABASE -C,no-cache [TAG]
55
+ Build the current database from the content in the schemas/ directory.
56
+ With a tag the version is built into the associated versioned database
57
+ and the result is saved to cache unless the -C option is given. The -d
58
+ option overrides the default database
145
59
 
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
60
+ make! -d,database=DATABASE -C,no-cache [TAG]
61
+ Build the current database from the content in the schemas/ directory.
62
+ With a tag the associated versioned database is loaded from cache if
63
+ present. The -C option ignores the cache and the -d option overrides
64
+ the default database
150
65
 
151
- load
152
- Load the current cache into the project database
66
+ make.clean! -a,all
67
+ Drop versioned databases and remove cached and other temporary files.
68
+ Also drop the project database if the -a option is given
153
69
 
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
157
-
158
- reload [VERSION]
159
- Clear the versioned database and reload the release from the cache
70
+ load! -d,database=DATABASE VERSION|FILE
71
+ Load the cached version or the file into the associated versioned
72
+ database. It is an error if the version hasn't been cached. The --database
73
+ argument overrides the database
160
74
 
161
- unload [VERSION]
162
- Delete the versioned database. Default is to delete all project related
163
- databases
75
+ save! VERSION [FILE]
76
+ Save the versioned database associated with version to the cache or the
77
+ given file
164
78
 
165
- clean [VERSION]
166
- Delete the cached release. Default is to delete all cached releases
79
+ drop! -a,all [DATABASE]
80
+ Drop the given database or all versioned databases. The --all option also
81
+ drops the project database
167
82
 
83
+ diff! -m,mark -t,tables -T,notables
84
+ diff [FROM-DATABASE|FROM-VERSION [TO-DATABASE|TO-VERSION]]
85
+ Create a schema diff between the given databases or versions. Default
86
+ to-version is the current schema and default from-version is the base
87
+ version of this branch/tag
168
88
 
89
+ migrate!
90
+ Not yet implemented
91
+
92
+ prepare!
93
+ Prepare a release. Just a shorthand for 'prick prepare release'
94
+
95
+ prepare.release! [FORK]
96
+ Populate the current migration directory with migration files
97
+
98
+ prepare.feature! NAME
99
+ Create and populate a feature as a subdirectory of the current directory.
100
+ Also prepares the current release directory
101
+
102
+ prepare.migration! [FROM]
103
+ Create and populate a migration directory
104
+
105
+ prepare.schema! NAME
106
+ Create and populate a new schema directory. Existing files and
107
+ directories are kept
108
+
109
+ prepare.diff! [VERSION]
110
+ Not yet implemented
111
+
112
+ include.feature! FEATURE
113
+ Include the given feature in the current pre-release
114
+
115
+ check!
116
+ Check that the current migration applied to the base version yields the
117
+ same result as loading the current schema
118
+
119
+ create.release! [RELEASE]
120
+ Prepare a release and create release directory and migration file before
121
+ tagging and branching to a release branch. The RELEASE argument can be
122
+ left out if the current branch is a prerelease branch
123
+
124
+ create.prerelease! RELEASE
125
+ Prepare a release and create release directory and migration file before
126
+ branching to a prerelease branch
127
+
128
+ create.feature! NAME
129
+ Prepare a feature before branching to a feature branch
130
+
131
+ cancel!
132
+ Cancel a release. Just a shorthand for 'prick cancel release'
133
+
134
+ cancel.release!
135
+ Cancel a release. Since tags are immutable, the release is cancelled by
136
+ added a special cancel-tag to the release that makes prick ignore it
137
+
138
+ generate.migration!
139
+ Create a script to migrate the database
140
+
141
+ generate.schema!
142
+ Create a script to create the database
143
+
144
+ upgrade!
145
+ Migrate the database to match the current schema
146
+
147
+ backup! [FILE]
148
+ Saves a backup of the database to the given file or to the var/spool
149
+ directory
150
+
151
+ restore! [FILE]
152
+ Restore the database from the given backup file or from the latest backup
153
+ in the var/spool directory
169
154
  )
170
155
 
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
156
 
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
157
 
211
- opts, args = ShellOpts.as_struct(SPEC, ARGV)
158
+ opts, args = ShellOpts.process(SPEC, ARGV)
212
159
 
213
160
  # Handle --help
214
161
  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
162
+ ShellOpts.help
223
163
  exit
224
- end
164
+ end
225
165
 
226
166
  # Handle --version
227
- if opts.version?
228
- puts "prick-#{Prick::VERSION}"
229
- exit
167
+ if opts.version?
168
+ puts "prick-#{VERSION}"
169
+ exit
230
170
  end
231
171
 
232
172
  begin
233
173
  # Honor -C option
234
- if opts.directory
235
- begin
236
- Dir.chdir(opts.directory)
237
- rescue Errno::ENOENT
238
- raise Prick::Error, "Can't cd to '#{directory}'"
174
+ if opts.directory?
175
+ if File.exist?(opts.directory)
176
+ begin
177
+ Dir.chdir(opts.directory)
178
+ rescue Errno::ENOENT
179
+ raise Prick::Error, "Can't cd to '#{opts.directory}'"
180
+ end
181
+ else
182
+ raise Prick::Error, "Can't find directory: #{opts.directory}"
239
183
  end
240
184
  end
241
185
 
242
- name = opts.name || ENV["PRICK_PROJECT"] || File.basename(Dir.getwd)
243
- verbose = opts.verbose?
186
+ # Create program object
187
+ program = Program.new(quiet: opts.quiet?, verbose: opts.verbose?)
244
188
 
245
- # :init! is processed separately because the project object can't be
246
- # constructed before the directory has been initialized
189
+ # Handle init command
247
190
  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
258
- else
259
- project = Prick::Project.new(name)
260
-
261
- case cmd = opts.subcommand
191
+ directory = args.expect(0..1)
192
+ name = opts.name || (directory && File.basename(directory)) || File.basename(Dir.getwd)
193
+ user = opts.init!.user || name
194
+ program.init(name, user, directory || ".")
195
+ exit 0
196
+ end
262
197
 
263
- # INFO COMMANDS #########################################################
264
- #
265
- when :info
266
- args.expect(0)
198
+ # Check prick version
199
+ file = PrickVersion.new
200
+ file.exist? or raise Prick::Error, "Can't find prick version file '#{file.path}'"
201
+ VERSION == file.read.to_s or
202
+ raise Prick::Fail, ".prick-version required prick-#{file.read} but you're using prick-#{VERSION}"
203
+
204
+ # TODO: Check for dirty detached head
205
+
206
+ # Expect a sub-command
207
+ opts.subcommand or raise Prick::Error, "Subcomand expected"
208
+
209
+ case opts.subcommand
210
+ when :info
211
+ args.expect(0)
212
+ program.info
213
+
214
+ when :list
215
+ command = opts.list!
216
+ case command.subcommand
217
+ when :releases;
218
+ obj = command.releases!
219
+ program.list_releases(migrations: obj.migrations?, cancelled: obj.cancelled?)
220
+ when :migrations; program.list_migrations
221
+ when :upgrades; program.list_upgrades(*args.expect(0..2).compact)
222
+ when :cache;
223
+ args.expect(0)
224
+ program.list_cache
225
+ when NilClass; raise Prick::Error, "list requires a releases|migrations|upgrades sub-command"
226
+ else
227
+ raise Prick::Internal, "Subcommand #{opts.subcommand}.#{command.subcommand} is not matched"
228
+ end
267
229
 
268
- puts "Current branch"
269
- puts " #{project.release&.version || 'nil'}"
230
+ when :build
231
+ version = args.expect(0..1)
232
+ program.build(opts.build!.database, version, opts.build!.no_cache?)
270
233
 
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
234
+ when :make
235
+ command = opts.make!
236
+ case command.subcommand
237
+ when :clean
346
238
  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}"
239
+ program.make_clean(command.clean!.all?)
422
240
  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
241
+ version = args.expect(0..1)
242
+ program.make(opts.make!.database, version, opts.make!.no_cache?)
243
+ end
244
+
245
+ when :load
246
+ version_or_file = args.expect(1)
247
+ program.load(opts.load!.database, version_or_file)
248
+
249
+ when :save
250
+ version, file = args.expect(1..2)
251
+ program.save(version, file)
252
+
253
+ when :drop
254
+ program.drop(args.expect(0..1), opts.drop!.all)
255
+
256
+ when :diff
257
+ mark = opts.diff!.mark
258
+ tables = opts.diff!.tables
259
+ no_tables = opts.diff!.notables
260
+ tables.nil? && no_tables.nil? || tables ^ no_tables or
261
+ raise Error, "--tables and --no-tables options are exclusive"
262
+ select = tables ? :tables : (no_tables ? :no_tables : :all)
263
+ from, to = args.expect(0..2)
264
+ program.diff(from, to, mark, select)
265
+
266
+ when :migrate
267
+ raise NotYet
268
+
269
+ when :prepare
270
+ cmd = opts.prepare!.subcommand || :release
271
+ case cmd
272
+ when :release; program.prepare_release(args.expect(0..1))
273
+ when :feature; program.prepare_feature(args.expect(1))
274
+ when :migration; program.prepare_migration(args.expect(0..1))
275
+ when :schema; program.prepare_schema(args.expect(1))
276
+ when :diff; program.prepare_diff(args.expect(0..1))
277
+ else
278
+ raise Prick::Internal, "Subcommand #{opts.subcommand}.#{cmd} is not matched"
279
+ end
280
+
281
+ when :include
282
+ cmd = opts.include!.subcommand || :feature
283
+ case cmd
284
+ when :feature; program.include_feature(args.expect(1))
285
+ else
286
+ raise Prick::Internal, "Subcommand #{opts.subcommand}.#{cmd} is not matched"
287
+ end
288
+
289
+ when :check
290
+ args.expect(0)
291
+ program.check
292
+
293
+ when :create
294
+ cmd = opts.create!.subcommand || :release
295
+ case cmd
296
+ when :release; program.create_release(args.expect(0..1))
297
+ when :prerelease; program.create_prerelease(args.expect(0..1))
298
+ when :feature; program.create_feature(args.expect(1))
299
+ else
300
+ raise Prick::Internal, "Subcommand #{opts.subcommand}.#{cmd} is not matched"
301
+ end
302
+
303
+ when :cancel
304
+ cmd = opts.cancel!.subcommand
305
+ case cmd
306
+ when :release; program.cancel_release(args.expect(1))
307
+ when nil; raise Prick::Error, "'cancel' subcommand requires a release argument"
308
+ else
309
+ raise Prick::Internal, "Subcommand #{opts.subcommand}.#{cmd} is not matched"
310
+ end
311
+
312
+ when :generate
313
+ cmd = opts.generate!.subcommand
314
+ case cmd
315
+ when :schema; program.generate_schema
316
+ when :migration; program.generate_migration
317
+ when nil; raise Prick::Error, "'generate' subcommand requires a 'schema' or 'migration' argument"
318
+ else
319
+ raise Prick::Internal, "Subcommand #{opts.subcommand}.#{cmd} is not matched"
320
+ end
321
+
322
+ when :upgrade
323
+ args.expect(0)
324
+ program.upgrade
325
+
326
+ when :backup
327
+ program.backup(args.expect(0..1))
328
+
329
+ when :restore
330
+ program.restore(args.expect(0..1))
331
+ else
332
+ raise Prick::Internal, "Subcommand #{opts.subcommand} is not matched"
459
333
  end
460
334
 
461
335
  rescue Prick::Fail => ex # Handling of Fail has to come first because Fail < Error
@@ -464,4 +338,56 @@ rescue Prick::Error => ex
464
338
  ShellOpts.error(ex.message)
465
339
  end
466
340
 
341
+ __END__
467
342
 
343
+ # Awaits support for sections in ShellOpts
344
+ HELP = %(
345
+ OPTIONS
346
+ -n, --name=NAME
347
+ -C, --directory=DIR
348
+ -h, --help
349
+ -v, --verbose
350
+ --version
351
+
352
+ COMMANDS
353
+ INITIALIZATION
354
+ init --user=USER [DIR]
355
+
356
+ INFO COMMANDS
357
+ info
358
+ list releases --migrations --cancelled
359
+ list migrations
360
+ list upgrades --all
361
+
362
+ BUILDING
363
+ build -d DATABASE -C --nocache [TAG]
364
+ make -d DATABASE -C --nocache [TAG]
365
+ make clean -a
366
+ load -d DATABASE VERSION|FILE
367
+ save VERSION [FILE]
368
+ drop --all [DATABASE]
369
+ diff [FROM-DATABASE|FROM-VERSION [TO-DATABASE|TO-VERSION]]
370
+ migrate
371
+
372
+ PREPARING RELEASES
373
+ prepare release [FORK]
374
+ prepare feature NAME
375
+ prepare migration FROM
376
+ prepare schema NAME
377
+ prepare diff [VERSION]
378
+ include feature FEATURE
379
+ check
380
+
381
+ CREATING RELEASES
382
+ create release [RELEASE]
383
+ create prerelease RELEASE
384
+ create feature NAME
385
+ cancel release RELEASE
386
+
387
+ DEPLOYING RELEASES
388
+ generate migration
389
+ generate schema
390
+ upgrade
391
+ backup [FILE]
392
+ restore [FILE]
393
+ )