dbgeni 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Rakefile +29 -0
- data/bin/dbgeni +2 -0
- data/lib/dbgeni/base.rb +146 -0
- data/lib/dbgeni/base_code.rb +143 -0
- data/lib/dbgeni/blank_slate.rb +24 -0
- data/lib/dbgeni/cli.rb +96 -0
- data/lib/dbgeni/code.rb +235 -0
- data/lib/dbgeni/code_list.rb +60 -0
- data/lib/dbgeni/commands/code.rb +151 -0
- data/lib/dbgeni/commands/commands.rb +41 -0
- data/lib/dbgeni/commands/config.rb +36 -0
- data/lib/dbgeni/commands/dmls.rb +244 -0
- data/lib/dbgeni/commands/generate.rb +257 -0
- data/lib/dbgeni/commands/initialize.rb +41 -0
- data/lib/dbgeni/commands/migrations.rb +243 -0
- data/lib/dbgeni/commands/milestones.rb +52 -0
- data/lib/dbgeni/commands/new.rb +178 -0
- data/lib/dbgeni/config.rb +325 -0
- data/lib/dbgeni/connectors/connector.rb +59 -0
- data/lib/dbgeni/connectors/mysql.rb +146 -0
- data/lib/dbgeni/connectors/oracle.rb +149 -0
- data/lib/dbgeni/connectors/sqlite.rb +166 -0
- data/lib/dbgeni/connectors/sybase.rb +97 -0
- data/lib/dbgeni/dml_cli.rb +35 -0
- data/lib/dbgeni/environment.rb +161 -0
- data/lib/dbgeni/exceptions/exception.rb +69 -0
- data/lib/dbgeni/file_converter.rb +44 -0
- data/lib/dbgeni/initializers/initializer.rb +44 -0
- data/lib/dbgeni/initializers/mysql.rb +36 -0
- data/lib/dbgeni/initializers/oracle.rb +38 -0
- data/lib/dbgeni/initializers/sqlite.rb +33 -0
- data/lib/dbgeni/initializers/sybase.rb +34 -0
- data/lib/dbgeni/logger.rb +60 -0
- data/lib/dbgeni/migration.rb +302 -0
- data/lib/dbgeni/migration_cli.rb +204 -0
- data/lib/dbgeni/migration_list.rb +91 -0
- data/lib/dbgeni/migrators/migrator.rb +40 -0
- data/lib/dbgeni/migrators/migrator_interface.rb +51 -0
- data/lib/dbgeni/migrators/mysql.rb +82 -0
- data/lib/dbgeni/migrators/oracle.rb +211 -0
- data/lib/dbgeni/migrators/sqlite.rb +90 -0
- data/lib/dbgeni/migrators/sybase.rb +118 -0
- data/lib/dbgeni/plugin.rb +92 -0
- data/lib/dbgeni.rb +52 -0
- metadata +87 -0
@@ -0,0 +1,257 @@
|
|
1
|
+
def usage
|
2
|
+
puts <<-EOF
|
3
|
+
Usage:
|
4
|
+
|
5
|
+
The generate command is a helper to create appropriately named db migration
|
6
|
+
and code files.
|
7
|
+
|
8
|
+
Use --config-file to specify the config file to use. If none is specified
|
9
|
+
then a file called .dbgeni will be used if it is present in the current directory,
|
10
|
+
otherwise an error will be raised.
|
11
|
+
|
12
|
+
Usage:
|
13
|
+
dbgeni generate command parameters
|
14
|
+
|
15
|
+
The allowed commands are:
|
16
|
+
|
17
|
+
migration Generates a set of files for a new database migration. The only parameter
|
18
|
+
is a name for the migration:
|
19
|
+
dbgeni generate migration name_for_this_migration
|
20
|
+
|
21
|
+
dml_migration Generates a set of files for a new dml database migration. The only parameter
|
22
|
+
is a name for the migration:
|
23
|
+
dbgeni generate dml_migration name_for_this_migration
|
24
|
+
|
25
|
+
|
26
|
+
milestone Generates a milestone, which is like a tag on a particular migration indicating
|
27
|
+
that a migration completes a release of the application
|
28
|
+
dbgenu generate milestone name_for_milestone existing_migration_for_milestone
|
29
|
+
|
30
|
+
package Generates a pair of files for a plsql package with the given package name
|
31
|
+
dbgeni generate package my_package_name
|
32
|
+
|
33
|
+
procedure Generates a file for a stored procedure with the given procedure name
|
34
|
+
dbgeni generate procedure my_procedure_name
|
35
|
+
|
36
|
+
function Generates a file for a stored function with the given function name
|
37
|
+
dbgeni generate function my_procedure_name
|
38
|
+
|
39
|
+
trigger Generates a file for a trigger with the given trigger name
|
40
|
+
dbgeni generate trigger my_trigger_name
|
41
|
+
|
42
|
+
type Generates a file for a type definition with the given type name
|
43
|
+
dbgeni generate type my_type_name
|
44
|
+
|
45
|
+
EOF
|
46
|
+
end
|
47
|
+
|
48
|
+
if %w(-h --help).include? ARGV[0]
|
49
|
+
usage
|
50
|
+
exit(0)
|
51
|
+
end
|
52
|
+
|
53
|
+
command = ARGV.shift
|
54
|
+
name = ARGV.shift
|
55
|
+
|
56
|
+
unless name
|
57
|
+
puts "error: You must specify a name for the #{command}"
|
58
|
+
exit(1)
|
59
|
+
end
|
60
|
+
|
61
|
+
require 'fileutils'
|
62
|
+
|
63
|
+
config = DBGeni::Config.load_from_file($config_file)
|
64
|
+
|
65
|
+
case command
|
66
|
+
when 'migration', 'mig'
|
67
|
+
datestamp = Time.now.strftime('%Y%m%d%H%M')
|
68
|
+
%w(up down).each do |f|
|
69
|
+
filename = File.join(config.migration_directory, "#{datestamp}_#{f}_#{name}.sql")
|
70
|
+
puts "creating: #{filename}"
|
71
|
+
FileUtils.touch(filename)
|
72
|
+
end
|
73
|
+
when 'dml_migration', 'dml'
|
74
|
+
datestamp = Time.now.strftime('%Y%m%d%H%M')
|
75
|
+
%w(up down).each do |f|
|
76
|
+
filename = File.join(config.dml_directory, "#{datestamp}_#{f}_#{name}.sql")
|
77
|
+
puts "creating: #{filename}"
|
78
|
+
FileUtils.touch(filename)
|
79
|
+
end
|
80
|
+
when 'package', 'pkg'
|
81
|
+
filename = File.join(config.code_dir, "#{name}.pks")
|
82
|
+
if File.exists?(filename)
|
83
|
+
puts "exists: #{filename}"
|
84
|
+
else
|
85
|
+
puts "creating: #{filename}"
|
86
|
+
File.open(filename, 'w') do |f|
|
87
|
+
f.puts "create or replace package #{name}"
|
88
|
+
f.puts "as"
|
89
|
+
f.puts "begin"
|
90
|
+
f.puts ""
|
91
|
+
f.puts "end #{name};"
|
92
|
+
f.puts "/"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
filename = File.join(config.code_dir, "#{name}.pkb")
|
96
|
+
if File.exists?(filename)
|
97
|
+
puts "exists: #{filename}"
|
98
|
+
else
|
99
|
+
puts "creating: #{filename}"
|
100
|
+
File.open(filename, 'w') do |f|
|
101
|
+
f.puts "create or replace package body #{name}"
|
102
|
+
f.puts "as"
|
103
|
+
f.puts "begin"
|
104
|
+
f.puts ""
|
105
|
+
f.puts "end #{name};"
|
106
|
+
f.puts "/"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
when 'procedure', 'prc', 'proc'
|
110
|
+
filename = File.join(config.code_dir, "#{name}.prc")
|
111
|
+
if File.exists?(filename)
|
112
|
+
puts "exists: #{filename}"
|
113
|
+
else
|
114
|
+
puts "creating: #{filename}"
|
115
|
+
File.open(filename, 'w') do |f|
|
116
|
+
if config.db_type == 'oracle'
|
117
|
+
f.puts "create or replace procedure #{name}"
|
118
|
+
f.puts "as"
|
119
|
+
f.puts "begin"
|
120
|
+
f.puts " null;"
|
121
|
+
f.puts "end #{name};"
|
122
|
+
f.puts "/"
|
123
|
+
elsif config.db_type == 'mysql'
|
124
|
+
f.puts "delimiter $$"
|
125
|
+
f.puts "drop procedure if exists #{name}$$"
|
126
|
+
f.puts "create procedure #{name}()"
|
127
|
+
f.puts "begin"
|
128
|
+
f.puts "end$$"
|
129
|
+
elsif config.db_type == 'sybase'
|
130
|
+
f.puts "if exists (select 1 from sysobjects"
|
131
|
+
f.puts " where name = '#{name}'"
|
132
|
+
f.puts " and type in ('P', 'TR'))"
|
133
|
+
f.puts " drop proc #{name}"
|
134
|
+
f.puts "go"
|
135
|
+
f.puts ""
|
136
|
+
f.puts "create proc #{name}"
|
137
|
+
f.puts "as"
|
138
|
+
f.puts "return(0)"
|
139
|
+
f.puts "go"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
when 'function', 'fnc', 'func'
|
144
|
+
filename = File.join(config.code_dir, "#{name}.fnc")
|
145
|
+
if File.exists?(filename)
|
146
|
+
puts "exists: #{filename}"
|
147
|
+
else
|
148
|
+
puts "creating: #{filename}"
|
149
|
+
File.open(filename, 'w') do |f|
|
150
|
+
if config.db_type == 'oracle'
|
151
|
+
f.puts "create or replace function #{name}"
|
152
|
+
f.puts " return varchar2"
|
153
|
+
f.puts "as"
|
154
|
+
f.puts "begin"
|
155
|
+
f.puts " null;"
|
156
|
+
f.puts "end #{name};"
|
157
|
+
f.puts "/"
|
158
|
+
elsif config.db_type == 'mysql'
|
159
|
+
f.puts "delimiter $$"
|
160
|
+
f.puts "drop function if exists #{name}$$"
|
161
|
+
f.puts "create function #{name}()"
|
162
|
+
f.puts " returns varchar(10)"
|
163
|
+
f.puts "begin"
|
164
|
+
f.puts " return 'abcd';"
|
165
|
+
f.puts "end$$"
|
166
|
+
elsif config.db_type == 'sybase'
|
167
|
+
f.puts "if exists (select 1 from sysobjects"
|
168
|
+
f.puts " where name = '#{name}'"
|
169
|
+
f.puts " and type in ('P', 'TR'))"
|
170
|
+
f.puts " drop func #{name}"
|
171
|
+
f.puts "go"
|
172
|
+
f.puts ""
|
173
|
+
f.puts "create func #{name}"
|
174
|
+
f.puts " returns int"
|
175
|
+
f.puts "as"
|
176
|
+
f.puts " return(0)"
|
177
|
+
f.puts "go"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
when 'trigger', 'trg'
|
182
|
+
filename = File.join(config.code_dir, "#{name}.trg")
|
183
|
+
if File.exists?(filename)
|
184
|
+
puts "exists: #{filename}"
|
185
|
+
else
|
186
|
+
puts "creating: #{filename}"
|
187
|
+
File.open(filename, 'w') do |f|
|
188
|
+
if config.db_type == 'oracle'
|
189
|
+
f.puts "create or replace trigger #{name} before insert on TABLE"
|
190
|
+
f.puts "for each row"
|
191
|
+
f.puts "begin"
|
192
|
+
f.puts " null;"
|
193
|
+
f.puts "end;"
|
194
|
+
f.puts "/"
|
195
|
+
elsif config.db_type == 'mysql'
|
196
|
+
f.puts "delimiter $$"
|
197
|
+
f.puts "drop trigger if exists #{name}$$"
|
198
|
+
f.puts "CREATE TRIGGER #{name} BEFORE INSERT ON TABLE"
|
199
|
+
f.puts "FOR EACH ROW"
|
200
|
+
f.puts "BEGIN"
|
201
|
+
f.puts "END$$"
|
202
|
+
elsif config.db_type == 'sybase'
|
203
|
+
f.puts "if exists (select 1 from sysobjects"
|
204
|
+
f.puts " where name = '#{name}'"
|
205
|
+
f.puts " and type in ('P', 'TR'))"
|
206
|
+
f.puts " drop trigger #{name}"
|
207
|
+
f.puts "go"
|
208
|
+
f.puts ""
|
209
|
+
f.puts "create trigger #{name}"
|
210
|
+
f.puts "on MYTABLE"
|
211
|
+
f.puts "for insert, update"
|
212
|
+
f.puts ""
|
213
|
+
f.puts "go"
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
when 'type', 'typ'
|
218
|
+
filename = File.join(config.code_dir, "#{name}.typ")
|
219
|
+
if File.exists?(filename)
|
220
|
+
puts "exists: #{filename}"
|
221
|
+
else
|
222
|
+
puts "creating: #{filename}"
|
223
|
+
File.open(filename, 'w') do |f|
|
224
|
+
f.puts "create or replace type #{name}"
|
225
|
+
f.puts "as"
|
226
|
+
f.puts "/"
|
227
|
+
end
|
228
|
+
end
|
229
|
+
when 'milestone'
|
230
|
+
filename = File.join(config.migration_directory, "#{name}.milestone")
|
231
|
+
if File.exists?(filename)
|
232
|
+
puts "milestone already exists"
|
233
|
+
exit(1)
|
234
|
+
end
|
235
|
+
# The migration can be either the migration filename, or the internal :: name
|
236
|
+
migration = ARGV.shift
|
237
|
+
unless migration
|
238
|
+
puts "You must specify a migration for the milestone"
|
239
|
+
exit(1)
|
240
|
+
end
|
241
|
+
if migration =~ /::/ # internal name
|
242
|
+
migration = DBGeni::Migration.filename_from_internal_name(migration)
|
243
|
+
end
|
244
|
+
unless File.exists?(File.join(config.migration_directory, migration))
|
245
|
+
puts "The migration #{migration} does not exist"
|
246
|
+
exit(1)
|
247
|
+
end
|
248
|
+
File.open(filename, 'w') do |f|
|
249
|
+
f.puts migration
|
250
|
+
end
|
251
|
+
puts "creating: #{filename}"
|
252
|
+
else
|
253
|
+
puts "Error: #{command} is not a invalid generator"
|
254
|
+
exit(1)
|
255
|
+
end
|
256
|
+
|
257
|
+
exit(0)
|
@@ -0,0 +1,41 @@
|
|
1
|
+
if %w(-h --help).include? ARGV[0]
|
2
|
+
puts <<-EOF
|
3
|
+
Usage: dbgeni initialize <--environment-name env_name> <--config-file path/to/config> <--username user> <--password password>
|
4
|
+
|
5
|
+
If config-file is not specified, then a file called .dbgeni in the current directory will be
|
6
|
+
used if it exists, otherwise an error will occurr
|
7
|
+
|
8
|
+
If there is more than one environment defined in the config file, then environment-name must
|
9
|
+
be specified.
|
10
|
+
|
11
|
+
-e can be used as an abbreviation for --environment-name
|
12
|
+
-c can be used as an abbreviation for --config-file
|
13
|
+
-u can be used as an abbreviation for --username
|
14
|
+
-p can be used as an abbreviation for --password
|
15
|
+
|
16
|
+
|
17
|
+
EOF
|
18
|
+
exit(0)
|
19
|
+
end
|
20
|
+
|
21
|
+
installer = $build_installer.call
|
22
|
+
|
23
|
+
begin
|
24
|
+
logger = DBGeni::Logger.instance
|
25
|
+
installer.initialize_database
|
26
|
+
logger.info "Database initialized successfully"
|
27
|
+
rescue DBGeni::DatabaseAlreadyInitialized
|
28
|
+
logger.error "The Database has already been initialized"
|
29
|
+
exit(1)
|
30
|
+
rescue DBGeni::NoInitializerForDBType
|
31
|
+
logger.error "There is no initializer for the db_type setting"
|
32
|
+
exit(1)
|
33
|
+
rescue DBGeni::NoConnectorForDBType
|
34
|
+
logger.error "There is no connector defined for the db_type setting"
|
35
|
+
exit(1)
|
36
|
+
end
|
37
|
+
|
38
|
+
exit(0)
|
39
|
+
|
40
|
+
|
41
|
+
|
@@ -0,0 +1,243 @@
|
|
1
|
+
if %w(-h --help).include? ARGV[0]
|
2
|
+
puts <<-EOF
|
3
|
+
Usage: dbgeni migrations command <--environment-name env_name> <--config-file path/to/config> <--force> <--username user> <--password password>
|
4
|
+
|
5
|
+
If config-file is not specified, then a file called .dbgeni in the current directory will be
|
6
|
+
used if it exists, otherwise an error will occurr
|
7
|
+
|
8
|
+
If there is more than one environment defined in the config file, then environment-name must
|
9
|
+
be specified.
|
10
|
+
|
11
|
+
If --force is specified, the migration will run to completion and be marked as Completed even
|
12
|
+
if errors occur.
|
13
|
+
|
14
|
+
-e can be used as an abbreviation for --environment-name
|
15
|
+
-c can be used as an abbreviation for --config-file
|
16
|
+
-f can be used as an abbreviation for --force
|
17
|
+
-u can be used as an abbreviation for --username
|
18
|
+
-p can be used as an abbreviation for --password
|
19
|
+
|
20
|
+
|
21
|
+
Avaliable commands are:
|
22
|
+
|
23
|
+
Readonly
|
24
|
+
--------
|
25
|
+
|
26
|
+
list Prints out all available migrations
|
27
|
+
dbgeni migrations list --config-file /home/myapp/.dbgeni
|
28
|
+
|
29
|
+
applied Prints all migrations which have been applied to an environment
|
30
|
+
dbgeni migrations applied --environment-name test --config-file /home/myapp/.dbgeni
|
31
|
+
|
32
|
+
outstanding Prints all migrations which have not been applied to an environment
|
33
|
+
dbgeni migrations outstanding --environment-name test --config-file /home/myapp/.dbgeni
|
34
|
+
|
35
|
+
|
36
|
+
Destructive
|
37
|
+
-----------
|
38
|
+
|
39
|
+
apply Apply migrations to the given environment. Can specify:
|
40
|
+
|
41
|
+
all Apply all outstanding migrations
|
42
|
+
next Apply only the next migration and stop
|
43
|
+
until Apply upto and including the specified migration
|
44
|
+
specific migrations to apply
|
45
|
+
milestone Apply upto a specified milestone
|
46
|
+
|
47
|
+
dbgeni migrations apply all --environment-name test --config-file /home/myapp/.dbgeni <--force>
|
48
|
+
dbgeni migrations apply next --environment-name test --config-file /home/myapp/.dbgeni <--force>
|
49
|
+
dbgeni migrations apply until YYYYMMDDHHMM::Name1 --environment-name test --config-file /home/myapp/.dbgeni <--force>
|
50
|
+
dbgeni migrations apply YYYYMMDDHHMM::Name1 YYYYMMDDHHMM::Name2 YYYYMMDDHHMM::Name3 --environment-name test --config-file /home/myapp/.dbgeni <--force>
|
51
|
+
dbgeni migrations apply milestone release_1.0 --environment-name test --config-file /home/myapp/.dbgeni <--force>
|
52
|
+
|
53
|
+
rollback Run the rollback script for a given migration. Can specify:
|
54
|
+
|
55
|
+
all Rollback everything that has even been applied
|
56
|
+
last Rollback the last migration applied
|
57
|
+
until Rollback from the last applied migration until and including the specified migration
|
58
|
+
specific migrations to rollback
|
59
|
+
|
60
|
+
dbgeni migrations rollback all --environment-name test --config-file /home/myapp/.dbgeni <--force>
|
61
|
+
dbgeni migrations rollback last --environment-name test --config-file /home/myapp/.dbgeni <--force>
|
62
|
+
dbgeni migrations rollback until YYYYMMDDHHMM::Name1 --environment-name test --config-file /home/myapp/.dbgeni <--force>
|
63
|
+
dbgeni migrations rollback YYYYMMDDHHMM::Name1 YYYYMMDDHHMM::Name2 YYYYMMDDHHMM::Name3 --environment-name test --config-file /home/myapp/.dbgeni <--force>
|
64
|
+
dbgeni migrations rollback milestone release_1.0 --environment-name test --config-file /home/myapp/.dbgeni <--force>
|
65
|
+
|
66
|
+
EOF
|
67
|
+
exit
|
68
|
+
end
|
69
|
+
|
70
|
+
command = ARGV.shift
|
71
|
+
|
72
|
+
installer = nil
|
73
|
+
installer = $build_installer.call
|
74
|
+
|
75
|
+
logger = DBGeni::Logger.instance
|
76
|
+
|
77
|
+
begin
|
78
|
+
case command
|
79
|
+
when 'list'
|
80
|
+
migrations = installer.migrations
|
81
|
+
if migrations.length == 0
|
82
|
+
logger.info "There are no migrations in #{installer.config.migration_directory}"
|
83
|
+
end
|
84
|
+
migrations.each do |m|
|
85
|
+
puts m.to_s
|
86
|
+
end
|
87
|
+
when 'applied'
|
88
|
+
applied = installer.applied_migrations
|
89
|
+
if applied.length == 0
|
90
|
+
logger.info "There are no applied migrations in #{installer.config.migration_directory}"
|
91
|
+
end
|
92
|
+
applied.each do |m|
|
93
|
+
puts m.to_s
|
94
|
+
end
|
95
|
+
when 'outstanding'
|
96
|
+
outstanding = installer.outstanding_migrations
|
97
|
+
if outstanding.length == 0
|
98
|
+
logger.info "There are no outstanding migrations in #{installer.config.migration_directory}"
|
99
|
+
end
|
100
|
+
outstanding.each do |m|
|
101
|
+
puts m.to_s
|
102
|
+
end
|
103
|
+
|
104
|
+
when 'apply'
|
105
|
+
sub_command = ARGV.shift
|
106
|
+
case sub_command
|
107
|
+
when 'all'
|
108
|
+
installer.apply_all_migrations($force)
|
109
|
+
when 'next'
|
110
|
+
installer.apply_next_migration($force)
|
111
|
+
when 'until', 'milestone'
|
112
|
+
migration_name = nil
|
113
|
+
if sub_command == 'milestone'
|
114
|
+
unless ARGV[0]
|
115
|
+
logger.error "A milestone must be specified"
|
116
|
+
exit(1)
|
117
|
+
end
|
118
|
+
unless File.exists? File.join(installer.config.migration_directory, "#{ARGV[0]}.milestone")
|
119
|
+
logger.error "The milestone #{ARGV[0]} does not exist"
|
120
|
+
exit(1)
|
121
|
+
end
|
122
|
+
migration_name = DBGeni::Migration.internal_name_from_filename(
|
123
|
+
DBGeni::Migration.get_milestone_migration(
|
124
|
+
installer.config.migration_directory, "#{ARGV[0]}.milestone"))
|
125
|
+
else
|
126
|
+
# a migration name needs to be the next parameter
|
127
|
+
migration_name = ARGV[0]
|
128
|
+
end
|
129
|
+
|
130
|
+
unless migration_name
|
131
|
+
logger.error "A migration name must be specified"
|
132
|
+
exit(1)
|
133
|
+
end
|
134
|
+
# and the migration needs to be in the correct format
|
135
|
+
unless migration_name =~ /^(\d{12})::/
|
136
|
+
logger.error "#{migration_name} is not a valid migration name"
|
137
|
+
exit(1)
|
138
|
+
end
|
139
|
+
installer.apply_until_migration(migration_name, $force)
|
140
|
+
when /^(\d{12})::/
|
141
|
+
# The param list are specific migration files, but in the internal format. One is
|
142
|
+
# stored in sub_command and the rest are in ARGV. Grab all params that match the
|
143
|
+
# parameter name format
|
144
|
+
files = ARGV.select{ |f| f =~ /^(\d{12})::/ }
|
145
|
+
files.unshift sub_command
|
146
|
+
installer.apply_list_of_migrations(files, $force)
|
147
|
+
else
|
148
|
+
logger.error "#{sub_command} is not a valid command"
|
149
|
+
end
|
150
|
+
|
151
|
+
when 'rollback'
|
152
|
+
sub_command = ARGV.shift
|
153
|
+
case sub_command
|
154
|
+
when 'all'
|
155
|
+
installer.rollback_all_migrations($force)
|
156
|
+
when 'last'
|
157
|
+
installer.rollback_last_migration($force)
|
158
|
+
when 'until', 'milestone'
|
159
|
+
migration_name = nil
|
160
|
+
if sub_command == 'milestone'
|
161
|
+
unless ARGV[0]
|
162
|
+
logger.error "You must specify a milestone"
|
163
|
+
exit(1)
|
164
|
+
end
|
165
|
+
unless File.exists? File.join(installer.config.migration_directory, "#{ARGV[0]}.milestone")
|
166
|
+
logger.error "The milestone #{ARGV[0]} does not exist"
|
167
|
+
exit(1)
|
168
|
+
end
|
169
|
+
migration_name = DBGeni::Migration.internal_name_from_filename(
|
170
|
+
DBGeni::Migration.get_milestone_migration(
|
171
|
+
installer.config.migration_directory, "#{ARGV[0]}.milestone"))
|
172
|
+
else
|
173
|
+
# a migration name needs to be the next parameter
|
174
|
+
migration_name = ARGV[0]
|
175
|
+
end
|
176
|
+
|
177
|
+
unless migration_name
|
178
|
+
logger.error "A migration name must be specified"
|
179
|
+
exit(1)
|
180
|
+
end
|
181
|
+
# and the migration needs to be in the correct format
|
182
|
+
unless migration_name =~ /^(\d{12})::/
|
183
|
+
logger.error "#{migration_name} is not a valid migration name"
|
184
|
+
exit(1)
|
185
|
+
end
|
186
|
+
installer.rollback_until_migration(migration_name, $force)
|
187
|
+
when /^(\d{12})::/
|
188
|
+
# The param list are specific migration files, but in the internal format. One is
|
189
|
+
# stored in sub_command and the rest are in ARGV. Grab all params that match the
|
190
|
+
# parameter name format
|
191
|
+
files = ARGV.select{ |f| f =~ /^(\d{12})::/ }
|
192
|
+
files.unshift sub_command
|
193
|
+
installer.rollback_list_of_migrations(files, $force)
|
194
|
+
# migrations = files.map {|f| DBGeni::Migration.initialize_from_internal_name(installer.config.migration_directory, f)}
|
195
|
+
# # Now attempt to run each migration ... backwards for rollback
|
196
|
+
# migrations.sort{|x,y| y.migration_file <=> x.migration_file}.each do |m|
|
197
|
+
# installer.rollback_migration(m, $force)
|
198
|
+
# end
|
199
|
+
else
|
200
|
+
logger.error "#{sub_command} is not a valid command"
|
201
|
+
end
|
202
|
+
else
|
203
|
+
logger.error "#{command} is not a valid command"
|
204
|
+
end
|
205
|
+
rescue DBGeni::NoOutstandingMigrations => e
|
206
|
+
logger.info "There are no outstanding migrations to apply"
|
207
|
+
exit(0)
|
208
|
+
rescue DBGeni::MigrationApplyFailed => e
|
209
|
+
logger.error "There was a problem #{command == 'rollback' ? 'rolling back' : 'applying' } #{e.to_s}"
|
210
|
+
exit(1)
|
211
|
+
rescue DBGeni::MigrationAlreadyApplied => e
|
212
|
+
logger.error "The migration is already applied #{e.to_s}"
|
213
|
+
exit(1)
|
214
|
+
rescue DBGeni::MigrationFileNotExist => e
|
215
|
+
logger.error "The migration file #{e.to_s} does not exist"
|
216
|
+
exit(1)
|
217
|
+
rescue DBGeni:: DatabaseNotInitialized => e
|
218
|
+
logger.error "The database needs to be initialized with the command dbgeni initialize"
|
219
|
+
exit(1)
|
220
|
+
rescue DBGeni::NoAppliedMigrations => e
|
221
|
+
logger.error "There are no applied migrations to rollback"
|
222
|
+
exit(1)
|
223
|
+
rescue DBGeni::MigrationNotApplied => e
|
224
|
+
logger.error "#{e.to_s} has not been applied so cannot be rolledback"
|
225
|
+
exit(1)
|
226
|
+
rescue DBGeni::MigrationNotOutstanding => e
|
227
|
+
logger.error "#{e.to_s} does not exist or is not outstanding"
|
228
|
+
exit(1)
|
229
|
+
rescue DBGeni::DBCLINotOnPath => e
|
230
|
+
logger.error "The command line interface for the database is not on the path (sqlite3, sqlplus)"
|
231
|
+
exit(1)
|
232
|
+
rescue DBGeni::MilestoneHasNoMigration => e
|
233
|
+
logger.error "The milestone does not contain a valid migration"
|
234
|
+
exit(1)
|
235
|
+
rescue DBGeni::PluginDirectoryNotAccessible => e
|
236
|
+
logger.error "The plugin directory specified in config is not accessable: #{e.to_s}"
|
237
|
+
exit(1)
|
238
|
+
rescue DBGeni::PluginDoesNotRespondToRun
|
239
|
+
logger.error "A pluggin was loaded that does not have a run method: #{e.to_s}"
|
240
|
+
exit(1)
|
241
|
+
end
|
242
|
+
|
243
|
+
exit(0)
|
@@ -0,0 +1,52 @@
|
|
1
|
+
if %w(-h --help).include? ARGV[0]
|
2
|
+
puts <<-EOF
|
3
|
+
|
4
|
+
The milestone command can be used to list milestones.
|
5
|
+
|
6
|
+
Usage: dbgeni milestones command <--environment-name env_name> <--config-file path/to/config> <--force>
|
7
|
+
|
8
|
+
If config-file is not specified, then a file called .dbgeni in the current directory will be
|
9
|
+
used if it exists, otherwise an error will occurr
|
10
|
+
|
11
|
+
If there is more than one environment defined in the config file, then environment-name must
|
12
|
+
be specified.
|
13
|
+
|
14
|
+
If --force is specified, the migration will run to completion and be marked as Completed even
|
15
|
+
if errors occur.
|
16
|
+
|
17
|
+
-e can be used as an abbreviation for --environment-name
|
18
|
+
-c can be used as an abbreviation for --config-file
|
19
|
+
-f can be used as an abbreviation for --force
|
20
|
+
|
21
|
+
|
22
|
+
Avaliable commands are:
|
23
|
+
|
24
|
+
list Prints out all available milestones
|
25
|
+
dbgeni milestones list
|
26
|
+
|
27
|
+
EOF
|
28
|
+
exit(0)
|
29
|
+
end
|
30
|
+
|
31
|
+
command = ARGV.shift
|
32
|
+
|
33
|
+
installer = nil
|
34
|
+
installer = $build_installer.call
|
35
|
+
|
36
|
+
begin
|
37
|
+
case command
|
38
|
+
when 'list'
|
39
|
+
milestones = Dir.entries(installer.config.migration_directory).grep(/milestone$/)
|
40
|
+
if milestones.length == 0
|
41
|
+
puts "There are no milestones in the migrations_directory"
|
42
|
+
exit(1)
|
43
|
+
end
|
44
|
+
milestones.each do |m|
|
45
|
+
puts m.gsub(/\.milestone/, '')
|
46
|
+
end
|
47
|
+
else
|
48
|
+
puts "#{command} is an invalid command"
|
49
|
+
exit(1)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|