jobmanager 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/FAQ.txt +151 -0
- data/History.txt +2 -0
- data/LICENSE +20 -0
- data/Manifest.txt +42 -0
- data/README.txt +395 -0
- data/Rakefile +17 -0
- data/bin/jobmanager +20 -0
- data/examples/email_settings.rb +14 -0
- data/examples/example.rb +23 -0
- data/examples/jobmanager.yaml +66 -0
- data/examples/mysql_backup.rb +18 -0
- data/lib/jobmanager.rb +1 -0
- data/lib/jobmanager/application.rb +455 -0
- data/lib/jobmanager/applicationconfig.rb +89 -0
- data/lib/jobmanager/applicationlogger.rb +306 -0
- data/lib/jobmanager/applicationoptionparser.rb +163 -0
- data/lib/jobmanager/system.rb +240 -0
- data/lib/jobmanager/teestream.rb +78 -0
- data/lib/jobmanager/util.rb +25 -0
- data/test/configs/all_values.yaml +33 -0
- data/test/configs/bad_email_condition.yaml +7 -0
- data/test/configs/bad_no_central_log_file.yaml +7 -0
- data/test/configs/bad_number_of_job_logs.yaml +7 -0
- data/test/configs/bad_timeout_zero.yaml +7 -0
- data/test/configs/email_settings.rb +16 -0
- data/test/configs/incomplete_1.yaml +23 -0
- data/test/configs/jobmanager_1.yaml +9 -0
- data/test/configs/jobmanager_2.yaml +11 -0
- data/test/configs/jobmanager_3.yaml +13 -0
- data/test/configs/jobmanager_4_bad_central_log_file.yaml +9 -0
- data/test/configs/jobmanager_4_bad_email_settings_file.yaml +9 -0
- data/test/configs/jobmanager_4_bad_job_logs_directory_1.yaml +9 -0
- data/test/configs/jobmanager_4_bad_job_logs_directory_2.yaml +9 -0
- data/test/configs/minimum_plus_email_settings.yaml +9 -0
- data/test/configs/minimum_required.yaml +5 -0
- data/test/helpers.rb +7 -0
- data/test/mock_syslog.rb +68 -0
- data/test/test_applicationlogger.rb +145 -0
- data/test/test_config.rb +208 -0
- data/test/test_jobmanager.rb +443 -0
- data/test/test_system.rb +206 -0
- data/test/test_teestream.rb +55 -0
- metadata +172 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'configtoolkit'
|
5
|
+
|
6
|
+
module JobManager
|
7
|
+
|
8
|
+
#
|
9
|
+
# This class is a configuration class used to represent the
|
10
|
+
# combination of the configurations specified in the jobmanager
|
11
|
+
# application's configuration file and the the jobmanager
|
12
|
+
# application's command line arguments.
|
13
|
+
#
|
14
|
+
class ApplicationConfig < ConfigToolkit::BaseConfig
|
15
|
+
|
16
|
+
EMAIL_CONDITIONS = [ :always, :never, :on_failure ]
|
17
|
+
CENTRAL_LOG_MODES = [ :syslog, :file ]
|
18
|
+
|
19
|
+
add_required_param(:command, String)
|
20
|
+
|
21
|
+
add_required_param(:job_name, String)
|
22
|
+
|
23
|
+
add_required_param(:job_logs_directory, Pathname)
|
24
|
+
|
25
|
+
add_optional_param(:email_condition, Symbol, :on_failure) do |value|
|
26
|
+
if (EMAIL_CONDITIONS.index(value) == nil)
|
27
|
+
raise_error("email_condition must be one of the following values: #{EMAIL_CONDITIONS.join(', ')}")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
add_optional_param(:central_log_mode, Symbol, :syslog) do |value|
|
32
|
+
if (CENTRAL_LOG_MODES.index(value) == nil)
|
33
|
+
modes = CENTRAL_LOG_MODES.join(', ')
|
34
|
+
raise_error("central_log_mode must be one of the following values: #{modes}")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
add_optional_param(:number_of_job_logs, Fixnum, 3) do |value|
|
39
|
+
if (value <= 0)
|
40
|
+
raise_error "value must be > 0"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
add_optional_param(:date_time_extension, ConfigToolkit::Boolean, true)
|
45
|
+
|
46
|
+
add_optional_param(:date_time_extension_format, String, '%F_%T') do |value|
|
47
|
+
begin
|
48
|
+
DateTime.now.strftime(value)
|
49
|
+
rescue => e
|
50
|
+
raise_error("Invalid format #{e.message}")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
add_optional_param(:zip_rotated_log_file, ConfigToolkit::Boolean, false)
|
55
|
+
|
56
|
+
add_optional_param(:debug, ConfigToolkit::Boolean, false)
|
57
|
+
|
58
|
+
add_optional_param(:central_log_file, Pathname)
|
59
|
+
|
60
|
+
add_optional_param(:command_path, String, ENV['PATH'])
|
61
|
+
|
62
|
+
add_optional_param(:timeout, Fixnum) do |value|
|
63
|
+
if (value <= 0)
|
64
|
+
raise_error("timeout must be a positive integer (seconds)")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
add_optional_param(:email_settings_file, Pathname, "email_settings.rb")
|
69
|
+
|
70
|
+
add_optional_param(:email_subject, String,
|
71
|
+
"jobmanager results for <%=job_name%> on <%=host_name%> : <%=result%>")
|
72
|
+
|
73
|
+
add_optional_param(:email_from_address, String)
|
74
|
+
|
75
|
+
add_optional_param(:email_to_address, String)
|
76
|
+
|
77
|
+
def validate_all_values()
|
78
|
+
if (self.central_log_mode == :file && !self.central_log_file?)
|
79
|
+
raise_error("If central_log_mode is set to file, central_log_file must be specified.")
|
80
|
+
end
|
81
|
+
|
82
|
+
if (self.central_log_mode == :syslog && self.central_log_file?)
|
83
|
+
raise_error("If central_log_mode is set to syslog, central_log_file should not be specified.")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
@@ -0,0 +1,306 @@
|
|
1
|
+
require 'syslog'
|
2
|
+
require 'logger'
|
3
|
+
require 'etc'
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'syslog_logger'
|
7
|
+
|
8
|
+
|
9
|
+
module JobManager
|
10
|
+
|
11
|
+
#
|
12
|
+
# This class is a base class for all of the ApplicationLogger*
|
13
|
+
# classes implemented in this file. This class should not be
|
14
|
+
# instantiated directly. This class derives from IO so that it can
|
15
|
+
# reuse the print methods (print, <<, puts, etc).
|
16
|
+
#
|
17
|
+
class ApplicationLogger < IO
|
18
|
+
|
19
|
+
#
|
20
|
+
# This constant is a map between the shortcut methods in the
|
21
|
+
# Logger interface (debug, info, warn, etc) and their associated
|
22
|
+
# severity constants.
|
23
|
+
#
|
24
|
+
LEVEL_LOGGER_MAP = SyslogLogger::LOGGER_LEVEL_MAP.invert
|
25
|
+
|
26
|
+
attr_accessor :job_name
|
27
|
+
attr_accessor :user_name
|
28
|
+
|
29
|
+
def initialize(job_name, user_name)
|
30
|
+
@job_name = job_name ? job_name : "UNKNOWN"
|
31
|
+
@user_name = user_name
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# ====Description:
|
36
|
+
# This method logs the given exception.
|
37
|
+
#
|
38
|
+
def record_exception(e)
|
39
|
+
error(e.message)
|
40
|
+
debug(e.backtrace.join("\n"))
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# ====Description:
|
45
|
+
# This method logs the given exception and the associated tag.
|
46
|
+
#
|
47
|
+
def record_tagged_exception(message, e)
|
48
|
+
error("#{message}: Error (#{e.class}): #{e.message}")
|
49
|
+
debug(e.backtrace.join("\n"))
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# ====Description:
|
54
|
+
# This method logs a message with severity level Logger::INFO.
|
55
|
+
#
|
56
|
+
def write(message)
|
57
|
+
info(message)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# This class provides a Logger interface and logs messages to syslog
|
64
|
+
# via the SysLogLogger gem. In addition, this class provides a
|
65
|
+
# string instance method which allows the caller to retrieve a
|
66
|
+
# concatenation of all the messages written to this logger. The
|
67
|
+
# level, user name, and job name are prepended to each message that
|
68
|
+
# is written to syslog. A number of the interface methods are
|
69
|
+
# implemented via the method_missing method.
|
70
|
+
#
|
71
|
+
class ApplicationSyslogLogger < ApplicationLogger
|
72
|
+
#
|
73
|
+
# ====Description:
|
74
|
+
# This method creates a new instance.
|
75
|
+
#
|
76
|
+
def initialize(program_name,
|
77
|
+
user_name,
|
78
|
+
job_name = nil)
|
79
|
+
|
80
|
+
super(job_name, user_name)
|
81
|
+
|
82
|
+
@program_name = program_name
|
83
|
+
@stringio = StringIO.new
|
84
|
+
|
85
|
+
@logger = SyslogLogger.new(program_name)
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# ====Returns:
|
90
|
+
# A string containing all mesages that were logged through this
|
91
|
+
# interface.
|
92
|
+
#
|
93
|
+
def string()
|
94
|
+
return @stringio.string()
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
# ====Description:
|
99
|
+
# This method is akin to the Logger::add interface method.
|
100
|
+
#
|
101
|
+
def add(severity, message = nil, &block)
|
102
|
+
wrap_record_send(LEVEL_LOGGER_MAP[severity], message || yield)
|
103
|
+
end
|
104
|
+
alias log add
|
105
|
+
|
106
|
+
#
|
107
|
+
# ====Description:
|
108
|
+
# This method closes the connection to the syslog daemon.
|
109
|
+
#
|
110
|
+
def close
|
111
|
+
if (Syslog.opened?) then Syslog.close() end
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
#
|
117
|
+
# ====Description:
|
118
|
+
# This method is intended to handle all shortcut methods (debug,
|
119
|
+
# warn, info, etc.), as well as the level attribute methods.
|
120
|
+
#
|
121
|
+
def method_missing(*args, &block)
|
122
|
+
method = args.shift
|
123
|
+
|
124
|
+
# if the method is a shortcut log method
|
125
|
+
if (SyslogLogger::LOGGER_MAP.find() {|key, value| method == key})
|
126
|
+
# wrap the message (with the job and user names)
|
127
|
+
wrap_record_send(method, (args.length > 0) ? args[0] : yield)
|
128
|
+
else
|
129
|
+
# otherwise forward the message directly on to the SyslogLogger instance.
|
130
|
+
@logger.send(method, *args, &block)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def wrap(method, message)
|
135
|
+
level = method.to_s.upcase
|
136
|
+
return "#{level} [#{user_name()}, #{job_name()}] #{message}"
|
137
|
+
end
|
138
|
+
|
139
|
+
def wrap_record_send(method, message)
|
140
|
+
if (!message) then return end
|
141
|
+
|
142
|
+
# if the level of the message is within the level of the logger
|
143
|
+
if (SyslogLogger::LOGGER_LEVEL_MAP[method] >= @logger.level)
|
144
|
+
lines = message.split("\n")
|
145
|
+
|
146
|
+
lines.each do |line|
|
147
|
+
wrapped_line = wrap(method, line)
|
148
|
+
@logger.send(method, wrapped_line)
|
149
|
+
@stringio << wrapped_line << "\n"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
#
|
156
|
+
# This class provides a Logger interface and logs messages to an IO
|
157
|
+
# stream. In addition, it provides a string instance method which
|
158
|
+
# allows the caller to retrieve a concatenation of all the messages
|
159
|
+
# written to this logger (with additional formatting such that the
|
160
|
+
# string represents exactly what was written to the IO stream).
|
161
|
+
# This class is implemented using the Logger class itself. The user
|
162
|
+
# name, and job name are prepended to each message, which is then
|
163
|
+
# written via the Logger class (to a string stream) which is in turn
|
164
|
+
# written to the IO stream. This was done so that the exact string
|
165
|
+
# that was logged to the IO stream could be later returned via the
|
166
|
+
# string instance method. A number of the interface methods are
|
167
|
+
# implemented via the method_missing method.
|
168
|
+
#
|
169
|
+
class ApplicationIOLogger < ApplicationLogger
|
170
|
+
|
171
|
+
LOGGER_LEVELS = [ :debug,
|
172
|
+
:info,
|
173
|
+
:warn,
|
174
|
+
:error,
|
175
|
+
:fatal,
|
176
|
+
:unknown
|
177
|
+
]
|
178
|
+
|
179
|
+
#
|
180
|
+
# ====Description:
|
181
|
+
# This method creates a new instance.
|
182
|
+
#
|
183
|
+
def initialize(io_stream,
|
184
|
+
user_name,
|
185
|
+
job_name = nil)
|
186
|
+
|
187
|
+
super(job_name, user_name)
|
188
|
+
|
189
|
+
@copy = StringIO.new
|
190
|
+
@io_stream = io_stream
|
191
|
+
|
192
|
+
@logger_stringio = StringIO.new
|
193
|
+
@logger = Logger.new(@logger_stringio)
|
194
|
+
@logger.formatter = Logger::Formatter.new
|
195
|
+
@logger.datetime_format = '%FT%T '
|
196
|
+
end
|
197
|
+
|
198
|
+
#
|
199
|
+
# ====Returns:
|
200
|
+
# A string containing all mesages that were logged through this
|
201
|
+
# interface.
|
202
|
+
#
|
203
|
+
def string()
|
204
|
+
return @copy.string()
|
205
|
+
end
|
206
|
+
|
207
|
+
#
|
208
|
+
# ====Description:
|
209
|
+
# This method is akin to the Logger::add interface method.
|
210
|
+
#
|
211
|
+
def add(severity, message = nil, &block)
|
212
|
+
wrap_record_send(LEVEL_LOGGER_MAP[severity], message || yield)
|
213
|
+
end
|
214
|
+
alias log add
|
215
|
+
|
216
|
+
#
|
217
|
+
# ====Description:
|
218
|
+
# This method exists only to complete the Logger interface. It
|
219
|
+
# is a noop.
|
220
|
+
#
|
221
|
+
def close
|
222
|
+
end
|
223
|
+
|
224
|
+
private
|
225
|
+
def wrap(message)
|
226
|
+
if (!message) then return nil end
|
227
|
+
|
228
|
+
return "[#{user_name()}, #{job_name()}] #{message}"
|
229
|
+
end
|
230
|
+
|
231
|
+
#
|
232
|
+
# ====Description:
|
233
|
+
# This method captures the output of the Logger instance and
|
234
|
+
# forwards it to the contained iostream and the aggregated string
|
235
|
+
# available for retrieval via the string method.
|
236
|
+
#
|
237
|
+
def wrap_record_send(method, message)
|
238
|
+
lines = message.split("\n")
|
239
|
+
lines.each do |line|
|
240
|
+
@logger.send(method, wrap(line))
|
241
|
+
end
|
242
|
+
|
243
|
+
output = @logger_stringio.string()
|
244
|
+
@logger_stringio.string = ""
|
245
|
+
|
246
|
+
@io_stream << output
|
247
|
+
@copy << output
|
248
|
+
end
|
249
|
+
|
250
|
+
#
|
251
|
+
# ====Description:
|
252
|
+
# This method is intended to handle all shortcut methods (debug,
|
253
|
+
# warn, info, etc.), as well as the level attribute methods.
|
254
|
+
#
|
255
|
+
def method_missing(*args, &block)
|
256
|
+
method = args.shift
|
257
|
+
|
258
|
+
# if the method is a shortcut log method
|
259
|
+
if (LOGGER_LEVELS.find() {|key| method == key})
|
260
|
+
wrap_record_send(method, args[0] ? args[0] : yield)
|
261
|
+
else
|
262
|
+
# forward the method directly onto the Logger instance.
|
263
|
+
@logger.send(method, *args, &block)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
#
|
269
|
+
# This class provides a Logger interface and logs messages to a
|
270
|
+
# file. In addition, it provides a string instance method which
|
271
|
+
# allows the caller to retrieve a concatenation of all the messages
|
272
|
+
# written to this logger. A number of the interface methods are
|
273
|
+
# implemented via the method_missing method.
|
274
|
+
#
|
275
|
+
class ApplicationFileLogger < ApplicationIOLogger
|
276
|
+
|
277
|
+
#
|
278
|
+
# ====Description:
|
279
|
+
# This method creates a new instance. All further messages
|
280
|
+
# written to this instance will be in turn written to the
|
281
|
+
# specified log file.
|
282
|
+
#
|
283
|
+
def initialize(log_file,
|
284
|
+
user_name,
|
285
|
+
job_name = nil)
|
286
|
+
|
287
|
+
FileUtils.mkdir_p(File.dirname(log_file))
|
288
|
+
@log_file_stream = File.open(log_file, "a")
|
289
|
+
|
290
|
+
super(@log_file_stream,
|
291
|
+
user_name,
|
292
|
+
job_name)
|
293
|
+
end
|
294
|
+
|
295
|
+
#
|
296
|
+
# ====Description:
|
297
|
+
# This method closes the log file stream.
|
298
|
+
#
|
299
|
+
def close
|
300
|
+
@log_file_stream.close()
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
end
|
305
|
+
|
306
|
+
|
@@ -0,0 +1,163 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'jobmanager/applicationconfig.rb'
|
5
|
+
|
6
|
+
module JobManager
|
7
|
+
|
8
|
+
#
|
9
|
+
# This class is composed of the command line argument parsing code
|
10
|
+
# for the jobmanager application.
|
11
|
+
#
|
12
|
+
class ApplicationOptionParser
|
13
|
+
|
14
|
+
#
|
15
|
+
# ====Description:
|
16
|
+
# This method parses the command line options and arguments passed
|
17
|
+
# in and returns a hash of these values.
|
18
|
+
# ====Parameters:
|
19
|
+
# [program_name]
|
20
|
+
# The program name.
|
21
|
+
# [args]
|
22
|
+
# The command line arguments.
|
23
|
+
# ====Returns:
|
24
|
+
# A hash of the command line options and arugments.
|
25
|
+
#
|
26
|
+
def self.parse(program_name, args)
|
27
|
+
options = {}
|
28
|
+
opts = OptionParser.new
|
29
|
+
|
30
|
+
opts.program_name = program_name
|
31
|
+
opts.summary_width = 40
|
32
|
+
opts.banner = get_usage(program_name)
|
33
|
+
|
34
|
+
opts.separator ""
|
35
|
+
opts.separator "Specific options:"
|
36
|
+
|
37
|
+
is_job_name_set = false
|
38
|
+
opts.on("-j", "--job_name NAME",
|
39
|
+
"The name of the job to be run, and thus the basename of the log file.") do |job_name|
|
40
|
+
options["job_name"] = job_name
|
41
|
+
is_job_name_set = true
|
42
|
+
end
|
43
|
+
|
44
|
+
opts.on("-l", "--job_logs_directory PATH",
|
45
|
+
"The directory in which the job logs will be kept.") do |logs_directory|
|
46
|
+
options["job_logs_directory"] = logs_directory
|
47
|
+
end
|
48
|
+
|
49
|
+
conditions = JobManager::ApplicationConfig::EMAIL_CONDITIONS.join(', ')
|
50
|
+
opts.on("-c", "--email_condition CONDITION",
|
51
|
+
"The condition upon which results should be emailed.",
|
52
|
+
"Possible values are:(#{conditions}.") do |condition|
|
53
|
+
options["email_condition"] = condition
|
54
|
+
end
|
55
|
+
|
56
|
+
modes = JobManager::ApplicationConfig::CENTRAL_LOG_MODES.join(', ')
|
57
|
+
opts.on("-m", "--central_log_mode MODE",
|
58
|
+
"Possible values are #{modes}.") do |mode|
|
59
|
+
options["central_log_mode"] = mode
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.on("-n", "--number_of_job_logs LOGS",
|
63
|
+
"Number of log files to be kept per job.") do |number_of_logs|
|
64
|
+
options["number_of_job_logs"] = number_of_logs
|
65
|
+
end
|
66
|
+
|
67
|
+
opts.on("-x", "--[no-]date_time_extension",
|
68
|
+
"Whether to add a date/time extension to the rotated log file.") do |value|
|
69
|
+
options["date_time_extension"] = value
|
70
|
+
end
|
71
|
+
|
72
|
+
opts.on("-f", "--date_time_extension_format FORMAT",
|
73
|
+
"The date/time format of the rotated log file extension.") do |format|
|
74
|
+
options["date_time_extension_format"] = format
|
75
|
+
end
|
76
|
+
|
77
|
+
opts.on("-z", "--[no-]zip_rotated_log_file",
|
78
|
+
"Zip the rotated log file.") do |value|
|
79
|
+
options["zip_rotated_log_file"] = value
|
80
|
+
end
|
81
|
+
|
82
|
+
opts.on("-r", "--central_log_file FILE",
|
83
|
+
"The central log file to which jobmanager writes.",
|
84
|
+
"This field is only valid if central_log_mode is set to \"file\".") do |file|
|
85
|
+
options["central_log_file"] = file
|
86
|
+
end
|
87
|
+
|
88
|
+
opts.on("-t", "--timeout TIMEOUT", OptionParser::DecimalInteger,
|
89
|
+
"Timeout (in seconds) after which the script is killed.") do |timeout|
|
90
|
+
options["timeout"] = timeout
|
91
|
+
end
|
92
|
+
|
93
|
+
opts.on("-e", "--email_settings_file PATH",
|
94
|
+
String,
|
95
|
+
"The configuration file for the simpleemail gem.",
|
96
|
+
"Note: If a relative path is specified, it will be considered to be relative to the",
|
97
|
+
"location of the configuration file.") do |file|
|
98
|
+
options["email_settings_file"] = file
|
99
|
+
end
|
100
|
+
|
101
|
+
opts.on("-o", "--email_from_address ADDRESS",
|
102
|
+
"The email address from which jobmanager sends results.") do |address|
|
103
|
+
options["email_from_address"] = address
|
104
|
+
end
|
105
|
+
|
106
|
+
opts.on("-o", "--email_to_address ADDRESS",
|
107
|
+
"The email address to which jobmanager sends results.") do |address|
|
108
|
+
options["email_to_address"] = address
|
109
|
+
end
|
110
|
+
|
111
|
+
opts.on("-p", "--command_path PATH",
|
112
|
+
"The path to search for the command that jobmanager is invoked with.") do |path|
|
113
|
+
options["command_path"] = path
|
114
|
+
end
|
115
|
+
|
116
|
+
opts.on("-s", "--email_subject SUBJECT",
|
117
|
+
"The email subject, to be interpreted by ERB.",
|
118
|
+
"Allowed variables: (job_name, command, host_name, result, user_name)") do |subject|
|
119
|
+
options["email_subject"] = subject
|
120
|
+
end
|
121
|
+
|
122
|
+
opts.on_tail("-d", "--[no-]debug", "Turn on/off debug trace.") do |value|
|
123
|
+
options["debug"] = value
|
124
|
+
end
|
125
|
+
|
126
|
+
opts.on_tail("-h", "--help", "Show this message.") do
|
127
|
+
puts opts, "\n"
|
128
|
+
exit(0)
|
129
|
+
end
|
130
|
+
|
131
|
+
opts.parse!(args)
|
132
|
+
|
133
|
+
if (args.length != 1)
|
134
|
+
puts opts, "\n"
|
135
|
+
raise ArgumentError, "One argument (command) is required!"
|
136
|
+
end
|
137
|
+
|
138
|
+
options["command"] = args.shift()
|
139
|
+
|
140
|
+
if (!is_job_name_set)
|
141
|
+
exe = options["command"].split(' ')[0]
|
142
|
+
options["job_name"] = File.basename(exe)
|
143
|
+
end
|
144
|
+
|
145
|
+
options
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
def self.get_usage(program_name)
|
150
|
+
usage = <<-EOL
|
151
|
+
|
152
|
+
Usage: #{program_name} [options] <command>
|
153
|
+
|
154
|
+
See http://jobmanager.rubyforge.com for a more detailed description and usage examples.
|
155
|
+
|
156
|
+
EOL
|
157
|
+
|
158
|
+
usage
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
end
|
163
|
+
end
|