dbgeni 0.10.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 (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)