dbgeni 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +29 -0
  3. data/bin/dbgeni +2 -0
  4. data/lib/dbgeni/base.rb +146 -0
  5. data/lib/dbgeni/base_code.rb +143 -0
  6. data/lib/dbgeni/blank_slate.rb +24 -0
  7. data/lib/dbgeni/cli.rb +96 -0
  8. data/lib/dbgeni/code.rb +235 -0
  9. data/lib/dbgeni/code_list.rb +60 -0
  10. data/lib/dbgeni/commands/code.rb +151 -0
  11. data/lib/dbgeni/commands/commands.rb +41 -0
  12. data/lib/dbgeni/commands/config.rb +36 -0
  13. data/lib/dbgeni/commands/dmls.rb +244 -0
  14. data/lib/dbgeni/commands/generate.rb +257 -0
  15. data/lib/dbgeni/commands/initialize.rb +41 -0
  16. data/lib/dbgeni/commands/migrations.rb +243 -0
  17. data/lib/dbgeni/commands/milestones.rb +52 -0
  18. data/lib/dbgeni/commands/new.rb +178 -0
  19. data/lib/dbgeni/config.rb +325 -0
  20. data/lib/dbgeni/connectors/connector.rb +59 -0
  21. data/lib/dbgeni/connectors/mysql.rb +146 -0
  22. data/lib/dbgeni/connectors/oracle.rb +149 -0
  23. data/lib/dbgeni/connectors/sqlite.rb +166 -0
  24. data/lib/dbgeni/connectors/sybase.rb +97 -0
  25. data/lib/dbgeni/dml_cli.rb +35 -0
  26. data/lib/dbgeni/environment.rb +161 -0
  27. data/lib/dbgeni/exceptions/exception.rb +69 -0
  28. data/lib/dbgeni/file_converter.rb +44 -0
  29. data/lib/dbgeni/initializers/initializer.rb +44 -0
  30. data/lib/dbgeni/initializers/mysql.rb +36 -0
  31. data/lib/dbgeni/initializers/oracle.rb +38 -0
  32. data/lib/dbgeni/initializers/sqlite.rb +33 -0
  33. data/lib/dbgeni/initializers/sybase.rb +34 -0
  34. data/lib/dbgeni/logger.rb +60 -0
  35. data/lib/dbgeni/migration.rb +302 -0
  36. data/lib/dbgeni/migration_cli.rb +204 -0
  37. data/lib/dbgeni/migration_list.rb +91 -0
  38. data/lib/dbgeni/migrators/migrator.rb +40 -0
  39. data/lib/dbgeni/migrators/migrator_interface.rb +51 -0
  40. data/lib/dbgeni/migrators/mysql.rb +82 -0
  41. data/lib/dbgeni/migrators/oracle.rb +211 -0
  42. data/lib/dbgeni/migrators/sqlite.rb +90 -0
  43. data/lib/dbgeni/migrators/sybase.rb +118 -0
  44. data/lib/dbgeni/plugin.rb +92 -0
  45. data/lib/dbgeni.rb +52 -0
  46. metadata +87 -0
@@ -0,0 +1,60 @@
1
+ module DBGeni
2
+
3
+ class CodeList
4
+
5
+ attr_reader :code
6
+ attr_reader :code_directory
7
+
8
+ def initialize(code_directory)
9
+ @code_directory = code_directory
10
+ file_list
11
+ end
12
+
13
+ def current(config, connection)
14
+ @code.select{ |c| c.current?(config, connection) }
15
+ end
16
+
17
+ def outstanding(config, connection)
18
+ @code.select{ |c| ! c.current?(config, connection) }
19
+ end
20
+
21
+ def list(list_of_code, config, connection)
22
+ valid_code = []
23
+ list_of_code.each do |c|
24
+ code_obj = Code.new(config.code_dir, c)
25
+ if i = @code.index(code_obj)
26
+ valid_code.push @code[i]
27
+ else
28
+ raise DBGeni::CodeFileNotExist, c
29
+ end
30
+ end
31
+ valid_code.sort {|x,y|
32
+ x.sort_field <=> y.sort_field
33
+ }
34
+ end
35
+
36
+ private
37
+
38
+ def file_list
39
+ begin
40
+ # The allowed list of code filetypes is in the Code class.
41
+ # Use that list to form a dynamic regex so all the extensions are only in one place.
42
+ extensions = DBGeni::Code::EXT_MAP.keys
43
+ files = Dir.entries(@code_directory).grep(/\.(#{extensions.join('|')})$/).sort
44
+ rescue Exception => e
45
+ raise DBGeni::CodeDirectoryNotExist, "Code directory: #{@code_directory}"
46
+ end
47
+ @code = Array.new
48
+ files.each do |f|
49
+ @code.push DBGeni::Code.new(@code_directory, f)
50
+ @code.sort! {|x,y|
51
+ x.sort_field <=> y.sort_field
52
+ }
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ end
59
+
60
+
@@ -0,0 +1,151 @@
1
+ if %w(-h --help).include? ARGV[0]
2
+ puts <<-EOF
3
+ Usage: dbgeni code 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, all code files will be compiled 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 code modules
27
+ dbgeni code list --config-file /home/myapp/.dbgeni
28
+
29
+ current Prints all code modules that have been applied to an environment
30
+ dbgeni code applied --environment-name test --config-file /home/myapp/.dbgeni
31
+
32
+ outstanding Prints all code modules that have not been applied to an environment
33
+ dbgeni code outstanding --environment-name test --config-file /home/myapp/.dbgeni
34
+
35
+
36
+ Destructive
37
+ -----------
38
+
39
+ apply Apply code modules to the given environment. Can specify:
40
+
41
+ all Apply all code modules, even if they have already been applied.
42
+ outstanding Apply only code modules that have changed since they were last applied
43
+ specific code modules to apply
44
+
45
+ dbgeni code apply all --environment-name test --config-file /home/myapp/.dbgeni <--force>
46
+ dbgeni code apply outstanding --environment-name test --config-file /home/myapp/.dbgeni <--force>
47
+ dbgeni code apply insert_t1_proc.prc admin_package.pkb --environment-name test --config-file /home/myapp/.dbgeni <--force>
48
+
49
+ remove Remove code modules from the given environment. Can specify:
50
+
51
+ all Remove all code modules installed
52
+ specific code modules to remove
53
+
54
+ dbgeni code remove all --environment-name test --config-file /home/myapp/.dbgeni <--force>
55
+ dbgeni code remove insert_t1_proc.prc admin_package.pkb --environment-name test --config-file /home/myapp/.dbgeni <--force>
56
+
57
+ EOF
58
+ exit
59
+ end
60
+
61
+ command = ARGV.shift
62
+ installer = $build_installer.call
63
+ logger = DBGeni::Logger.instance
64
+
65
+ begin
66
+ case command
67
+ when 'list', 'current', 'outstanding'
68
+ method_mapper = {
69
+ 'list' => :code,
70
+ 'current' => :current_code,
71
+ 'outstanding' => :outstanding_code
72
+ }
73
+ code = installer.send(method_mapper[command])
74
+ if code.length == 0
75
+ if command == 'list'
76
+ logger.info "There are no code modules in #{installer.config.code_dir}"
77
+ else
78
+ logger.info "There are no code modules #{command}"
79
+ end
80
+ exit(0)
81
+ end
82
+ code.each do |c|
83
+ puts c.to_s
84
+ end
85
+ when 'apply'
86
+ sub_command = ARGV.shift
87
+ case sub_command
88
+ when 'all'
89
+ installer.apply_all_code($force)
90
+ when 'outstanding'
91
+ installer.apply_outstanding_code($force)
92
+ when /\.(#{DBGeni::Code::EXT_MAP.keys.join('|')})$/
93
+ # The param list are specific code files. One is
94
+ # stored in sub_command and the rest are in ARGV. Grab all params that match the
95
+ # parameter name format
96
+ files = ARGV.select{ |f| f =~ /\.(#{DBGeni::Code::EXT_MAP.keys.join('|')})$/ }
97
+ files.unshift sub_command
98
+ installer.apply_list_of_code(files, $force)
99
+ else
100
+ logger.error "#{sub_command} is not a valid command"
101
+ end
102
+
103
+ when 'remove'
104
+ sub_command = ARGV.shift
105
+ case sub_command
106
+ when 'all'
107
+ installer.remove_all_code($force)
108
+ when /\.(#{DBGeni::Code::EXT_MAP.keys.join('|')})$/
109
+ files = ARGV.select{ |f| f =~ /\.(#{DBGeni::Code::EXT_MAP.keys.join('|')})$/ }
110
+ files.unshift sub_command
111
+ installer.remove_list_of_code(files, $force)
112
+ else
113
+ logger.error "#{sub_command} is not a valid command"
114
+ end
115
+ else
116
+ logger.error "#{command} is not a valid command"
117
+ end
118
+ rescue DBGeni::NoOutstandingCode => e
119
+ logger.info "There are no outstanding code modules to apply"
120
+ exit(0)
121
+ rescue DBGeni::NoCodeFilesExist => e
122
+ logger.error "There are no code files in the code_directory"
123
+ exit(1)
124
+ rescue DBGeni::CodeApplyFailed => e
125
+ # logger.error "There was a problem applying #{e.to_s}"
126
+ exit(1)
127
+ rescue DBGeni::CodeModuleCurrent => e
128
+ logger.error "The code module is already current #{e.to_s}"
129
+ exit(1)
130
+ rescue DBGeni::CodeFileNotExist => e
131
+ logger.error "The code file, #{e.to_s} does not exist"
132
+ exit(1)
133
+ rescue DBGeni:: DatabaseNotInitialized => e
134
+ logger.error "The database needs to be initialized with the command dbgeni initialize"
135
+ exit(1)
136
+ rescue DBGeni::CodeDirectoryNotExist
137
+ logger.error "The code directory does not exist"
138
+ exit(1)
139
+ rescue DBGeni::DBCLINotOnPath
140
+ logger.error "The command line interface for the database is not on the path (sqlite3, sqlplus)"
141
+ exit(1)
142
+ rescue DBGeni::PluginDirectoryNotAccessible => e
143
+ logger.error "The plugin directory specified in config is not accessable: #{e.to_s}"
144
+ exit(1)
145
+ rescue DBGeni::PluginDoesNotRespondToRun
146
+ logger.error "A pluggin was loaded that does not have a run method: #{e.to_s}"
147
+ exit(1)
148
+ end
149
+
150
+
151
+ exit(0)
@@ -0,0 +1,41 @@
1
+ ARGV << '--help' if ARGV.empty?
2
+
3
+ $initial_command = ARGV.shift
4
+
5
+ case $initial_command
6
+ when 'new', 'new-config' ,'n'
7
+ require 'dbgeni/commands/new'
8
+ when 'initialize' ,'i'
9
+ require 'dbgeni/commands/initialize'
10
+ when 'config'
11
+ require 'dbgeni/commands/config'
12
+ when 'generate' ,'g'
13
+ require 'dbgeni/commands/generate'
14
+ when 'migrations' ,'m'
15
+ require 'dbgeni/commands/migrations'
16
+ when 'dmls', 'dml' ,'d'
17
+ require 'dbgeni/commands/dmls'
18
+ when 'code' ,'c'
19
+ require 'dbgeni/commands/code'
20
+ when 'milestones'
21
+ require 'dbgeni/commands/milestones'
22
+
23
+ else
24
+ puts "Error: Command not recognized" unless %w(-h --help).include?($initial_command)
25
+ puts <<-EOT
26
+ Usage: dbgeni COMMAND [ARGS]
27
+
28
+ The available dbgeni commands are:
29
+ new Generate a new default application directory structure
30
+ new-config Generate a templated config file in an existing directory
31
+ initialize Create the dbgeni_migrations table in the database
32
+ config List the current config for a given environment
33
+ migrations List and Apply Migations
34
+ dmls List and Apply DML Migrations
35
+ code List, compile and remove stored procedures
36
+ generate Generate migrations and code files
37
+
38
+ All commands can be run with -h for more information.
39
+ EOT
40
+ end
41
+
@@ -0,0 +1,36 @@
1
+ if %w(-h --help).include? ARGV[0]
2
+ puts <<-EOF
3
+ Usage:
4
+ By default, dbgeni will search in the current directory for a config file
5
+ called .dbgeni
6
+
7
+ To list all the config for all environments:
8
+ dbgeni config
9
+
10
+ To use a different config_file, specify the config_file switch:
11
+ dbgeni config environment_name --config_file </path/to/config/file>
12
+ EOF
13
+ exit(0)
14
+ end
15
+
16
+ if ! File.exists?($config_file)
17
+ puts "error: The config file #{$config_file} does not exist"
18
+ exit(1)
19
+ end
20
+
21
+ begin
22
+ cfg = DBGeni::Config.load_from_file($config_file)
23
+ rescue DBGeni::ConfigSyntaxError => e
24
+ puts "There is an error in the config file: #{e.to_s}"
25
+ end
26
+ puts "-----------------------------\n"
27
+ puts "| Current Parameter Details |\n"
28
+ puts "-----------------------------\n\n"
29
+ puts cfg.to_s
30
+
31
+ exit(0)
32
+
33
+
34
+
35
+
36
+
@@ -0,0 +1,244 @@
1
+ if %w(-h --help).include? ARGV[0]
2
+ puts <<-EOF
3
+ Usage: dbgeni dmls 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
+
22
+ Avaliable commands are:
23
+
24
+ Readonly
25
+ --------
26
+
27
+ list Prints out all available dml migrations
28
+ dbgeni dmls list --config-file /home/myapp/.dbgeni
29
+
30
+ applied Prints all dml migrations which have been applied to an environment
31
+ dbgeni dmls applied --environment-name test --config-file /home/myapp/.dbgeni
32
+
33
+ outstanding Prints all dml migrations which have not been applied to an environment
34
+ dbgeni dmls outstanding --environment-name test --config-file /home/myapp/.dbgeni
35
+
36
+
37
+ Destructive
38
+ -----------
39
+
40
+ apply Apply dml migrations to the given environment. Can specify:
41
+
42
+ all Apply all outstanding dml migrations
43
+ next Apply only the next dml migration and stop
44
+ until Apply upto and including the specified dml migration
45
+ specific dml migrations to apply
46
+ milestone Apply upto a specified milestone
47
+
48
+ dbgeni dmls apply all --environment-name test --config-file /home/myapp/.dbgeni <--force>
49
+ dbgeni dmls apply next --environment-name test --config-file /home/myapp/.dbgeni <--force>
50
+ dbgeni dmls apply until YYYYMMDDHHMM::Name1 --environment-name test --config-file /home/myapp/.dbgeni <--force>
51
+ dbgeni dmls apply YYYYMMDDHHMM::Name1 YYYYMMDDHHMM::Name2 YYYYMMDDHHMM::Name3 --environment-name test --config-file /home/myapp/.dbgeni <--force>
52
+ dbgeni dmls apply milestone release_1.0 --environment-name test --config-file /home/myapp/.dbgeni <--force>
53
+
54
+ rollback Run the rollback script for a given dml migration. Can specify:
55
+
56
+ all Rollback everything that has even been applied
57
+ last Rollback the last dml migration applied
58
+ until Rollback from the last applied dml migration until and including the specified migration
59
+ specific migrations to rollback
60
+
61
+ dbgeni dmls rollback all --environment-name test --config-file /home/myapp/.dbgeni <--force>
62
+ dbgeni dmls rollback last --environment-name test --config-file /home/myapp/.dbgeni <--force>
63
+ dbgeni dmls rollback until YYYYMMDDHHMM::Name1 --environment-name test --config-file /home/myapp/.dbgeni <--force>
64
+ dbgeni dmls rollback YYYYMMDDHHMM::Name1 YYYYMMDDHHMM::Name2 YYYYMMDDHHMM::Name3 --environment-name test --config-file /home/myapp/.dbgeni <--force>
65
+ dbgeni dmls rollback milestone release_1.0 --environment-name test --config-file /home/myapp/.dbgeni <--force>
66
+
67
+ EOF
68
+ exit
69
+ end
70
+
71
+ command = ARGV.shift
72
+
73
+ installer = nil
74
+ installer = $build_installer.call
75
+
76
+ logger = DBGeni::Logger.instance
77
+
78
+ begin
79
+ case command
80
+ when 'list'
81
+ migrations = installer.dmls
82
+ if migrations.length == 0
83
+ logger.info "There are no dml migrations in #{installer.config.dml_directory}"
84
+ end
85
+ migrations.each do |m|
86
+ puts m.to_s
87
+ end
88
+ when 'applied'
89
+ applied = installer.applied_dmls
90
+ if applied.length == 0
91
+ logger.info "There are no applied dml migrations in #{installer.config.dml_directory}"
92
+ end
93
+ applied.each do |m|
94
+ puts m.to_s
95
+ end
96
+ when 'outstanding'
97
+ outstanding = installer.outstanding_dmls
98
+ if outstanding.length == 0
99
+ logger.info "There are no outstanding dml migrations in #{installer.config.dml_directory}"
100
+ end
101
+ outstanding.each do |m|
102
+ puts m.to_s
103
+ end
104
+
105
+ when 'apply'
106
+ sub_command = ARGV.shift
107
+ case sub_command
108
+ when 'all'
109
+ installer.apply_all_dmls($force)
110
+ when 'next'
111
+ installer.apply_next_dml($force)
112
+ when 'until', 'milestone'
113
+ migration_name = nil
114
+ if sub_command == 'milestone'
115
+ unless ARGV[0]
116
+ logger.error "A milestone must be specified"
117
+ exit(1)
118
+ end
119
+ unless File.exists? File.join(installer.config.dml_directory, "#{ARGV[0]}.milestone")
120
+ logger.error "The milestone #{ARGV[0]} does not exist"
121
+ exit(1)
122
+ end
123
+ migration_name = DBGeni::Migration.internal_name_from_filename(
124
+ DBGeni::Migration.get_milestone_migration(
125
+ installer.config.dml_directory, "#{ARGV[0]}.milestone"))
126
+ else
127
+ # a migration name needs to be the next parameter
128
+ migration_name = ARGV[0]
129
+ end
130
+
131
+ unless migration_name
132
+ logger.error "A dml migration name must be specified"
133
+ exit(1)
134
+ end
135
+ # and the migration needs to be in the correct format
136
+ unless migration_name =~ /^(\d{12})::/
137
+ logger.error "#{migration_name} is not a valid dml migration name"
138
+ exit(1)
139
+ end
140
+ installer.apply_until_dml(migration_name, $force)
141
+ when /^(\d{12})::/
142
+ # The param list are specific migration files, but in the internal format. One is
143
+ # stored in sub_command and the rest are in ARGV. Grab all params that match the
144
+ # parameter name format
145
+ files = ARGV.select{ |f| f =~ /^(\d{12})::/ }
146
+ files.unshift sub_command
147
+ installer.apply_list_of_dmls(files, $force)
148
+ else
149
+ logger.error "#{sub_command} is not a valid command"
150
+ end
151
+
152
+ when 'rollback'
153
+ sub_command = ARGV.shift
154
+ case sub_command
155
+ when 'all'
156
+ installer.rollback_all_dmls($force)
157
+ when 'last'
158
+ installer.rollback_last_dml($force)
159
+ when 'until', 'milestone'
160
+ migration_name = nil
161
+ if sub_command == 'milestone'
162
+ unless ARGV[0]
163
+ logger.error "You must specify a milestone"
164
+ exit(1)
165
+ end
166
+ unless File.exists? File.join(installer.config.dml_directory, "#{ARGV[0]}.milestone")
167
+ logger.error "The milestone #{ARGV[0]} does not exist"
168
+ exit(1)
169
+ end
170
+ migration_name = DBGeni::Migration.internal_name_from_filename(
171
+ DBGeni::Migration.get_milestone_migration(
172
+ installer.config.dml_directory, "#{ARGV[0]}.milestone"))
173
+ else
174
+ # a migration name needs to be the next parameter
175
+ migration_name = ARGV[0]
176
+ end
177
+
178
+ unless migration_name
179
+ logger.error "A dml migration name must be specified"
180
+ exit(1)
181
+ end
182
+ # and the migration needs to be in the correct format
183
+ unless migration_name =~ /^(\d{12})::/
184
+ logger.error "#{migration_name} is not a valid dml migration name"
185
+ exit(1)
186
+ end
187
+ installer.rollback_until_dml(migration_name, $force)
188
+ when /^(\d{12})::/
189
+ # The param list are specific migration files, but in the internal format. One is
190
+ # stored in sub_command and the rest are in ARGV. Grab all params that match the
191
+ # parameter name format
192
+ files = ARGV.select{ |f| f =~ /^(\d{12})::/ }
193
+ files.unshift sub_command
194
+ installer.rollback_list_of_dmls(files, $force)
195
+ # migrations = files.map {|f| DBGeni::Migration.initialize_from_internal_name(installer.config.migration_directory, f)}
196
+ # # Now attempt to run each migration ... backwards for rollback
197
+ # migrations.sort{|x,y| y.migration_file <=> x.migration_file}.each do |m|
198
+ # installer.rollback_migration(m, $force)
199
+ # end
200
+ else
201
+ logger.error "#{sub_command} is not a valid command"
202
+ end
203
+ else
204
+ logger.error "#{command} is not a valid command"
205
+ end
206
+ rescue DBGeni::NoOutstandingMigrations => e
207
+ logger.info "There are no outstanding dml migrations to apply"
208
+ exit(0)
209
+ rescue DBGeni::MigrationApplyFailed => e
210
+ logger.error "There was a problem #{command == 'rollback' ? 'rolling back' : 'applying' } #{e.to_s}"
211
+ exit(1)
212
+ rescue DBGeni::MigrationAlreadyApplied => e
213
+ logger.error "The dml migration is already applied #{e.to_s}"
214
+ exit(1)
215
+ rescue DBGeni::MigrationFileNotExist => e
216
+ logger.error "The dml migration file #{e.to_s} does not exist"
217
+ exit(1)
218
+ rescue DBGeni:: DatabaseNotInitialized => e
219
+ logger.error "The database needs to be initialized with the command dbgeni initialize"
220
+ exit(1)
221
+ rescue DBGeni::NoAppliedMigrations => e
222
+ logger.error "There are no applied dml migrations to rollback"
223
+ exit(1)
224
+ rescue DBGeni::MigrationNotApplied => e
225
+ logger.error "#{e.to_s} has not been applied so cannot be rolledback"
226
+ exit(1)
227
+ rescue DBGeni::MigrationNotOutstanding => e
228
+ logger.error "#{e.to_s} does not exist or is not outstanding"
229
+ exit(1)
230
+ rescue DBGeni::DBCLINotOnPath => e
231
+ logger.error "The command line interface for the database is not on the path (sqlite3, sqlplus)"
232
+ exit(1)
233
+ rescue DBGeni::MilestoneHasNoMigration => e
234
+ logger.error "The milestone does not contain a valid dml migration"
235
+ exit(1)
236
+ rescue DBGeni::PluginDirectoryNotAccessible => e
237
+ logger.error "The plugin directory specified in config is not accessable: #{e.to_s}"
238
+ exit(1)
239
+ rescue DBGeni::PluginDoesNotRespondToRun
240
+ logger.error "A pluggin was loaded that does not have a run method: #{e.to_s}"
241
+ exit(1)
242
+ end
243
+
244
+ exit(0)