solutious-stella 0.5.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/CHANGES.txt +36 -0
  2. data/README.textile +162 -0
  3. data/Rakefile +88 -0
  4. data/bin/stella +12 -0
  5. data/bin/stella.bat +12 -0
  6. data/lib/daemonize.rb +56 -0
  7. data/lib/pcaplet.rb +180 -0
  8. data/lib/stella.rb +101 -0
  9. data/lib/stella/adapter/ab.rb +337 -0
  10. data/lib/stella/adapter/base.rb +106 -0
  11. data/lib/stella/adapter/httperf.rb +305 -0
  12. data/lib/stella/adapter/pcap_watcher.rb +221 -0
  13. data/lib/stella/adapter/proxy_watcher.rb +76 -0
  14. data/lib/stella/adapter/siege.rb +341 -0
  15. data/lib/stella/cli.rb +258 -0
  16. data/lib/stella/cli/agents.rb +73 -0
  17. data/lib/stella/cli/base.rb +55 -0
  18. data/lib/stella/cli/language.rb +18 -0
  19. data/lib/stella/cli/localtest.rb +78 -0
  20. data/lib/stella/cli/sysinfo.rb +16 -0
  21. data/lib/stella/cli/watch.rb +278 -0
  22. data/lib/stella/command/base.rb +40 -0
  23. data/lib/stella/command/localtest.rb +358 -0
  24. data/lib/stella/data/domain.rb +82 -0
  25. data/lib/stella/data/http.rb +131 -0
  26. data/lib/stella/logger.rb +84 -0
  27. data/lib/stella/response.rb +85 -0
  28. data/lib/stella/storable.rb +201 -0
  29. data/lib/stella/support.rb +276 -0
  30. data/lib/stella/sysinfo.rb +257 -0
  31. data/lib/stella/test/definition.rb +79 -0
  32. data/lib/stella/test/run/summary.rb +70 -0
  33. data/lib/stella/test/stats.rb +114 -0
  34. data/lib/stella/text.rb +64 -0
  35. data/lib/stella/text/resource.rb +38 -0
  36. data/lib/utils/crypto-key.rb +84 -0
  37. data/lib/utils/domainutil.rb +47 -0
  38. data/lib/utils/escape.rb +302 -0
  39. data/lib/utils/fileutil.rb +78 -0
  40. data/lib/utils/httputil.rb +266 -0
  41. data/lib/utils/mathutil.rb +15 -0
  42. data/lib/utils/stats.rb +88 -0
  43. data/lib/utils/textgraph.rb +267 -0
  44. data/lib/utils/timerutil.rb +58 -0
  45. data/lib/win32/Console.rb +970 -0
  46. data/lib/win32/Console/ANSI.rb +305 -0
  47. data/support/kvm.h +91 -0
  48. data/support/ruby-pcap-takuma-notes.txt +19 -0
  49. data/support/ruby-pcap-takuma-patch.txt +30 -0
  50. data/support/text/en.yaml +80 -0
  51. data/support/text/nl.yaml +7 -0
  52. data/support/useragents.txt +75 -0
  53. data/tests/01-util_test.rb +0 -0
  54. data/tests/02-stella-util_test.rb +42 -0
  55. data/tests/10-stella_test.rb +104 -0
  56. data/tests/11-stella-storable_test.rb +68 -0
  57. data/tests/60-stella-command_test.rb +248 -0
  58. data/tests/80-stella-cli_test.rb +45 -0
  59. data/tests/spec-helper.rb +31 -0
  60. metadata +165 -0
@@ -0,0 +1,76 @@
1
+
2
+ require 'webrick/httpproxy'
3
+ require 'observer'
4
+
5
+
6
+ module Stella
7
+ module Adapter
8
+
9
+ # Stella::Adapter::ProxyWatcher
10
+ #
11
+ # Starts up an HTTP proxy using WEBrick to record HTTP events. This is used
12
+ # when PcapRecorder is not available.
13
+ class ProxyWatcher
14
+ include Observable
15
+
16
+ attr_accessor :port
17
+
18
+ def initialize(options={})
19
+ @port = options[:port]
20
+ end
21
+ require 'pp'
22
+ def run
23
+
24
+ @server = WEBrick::HTTPProxyServer.new(
25
+ :Port => @port || 3114,
26
+ :AccessLog => [],
27
+ :ProxyContentHandler => Proc.new do |req,res|
28
+
29
+ begin
30
+ res_obj = Stella::Data::HTTPResponse.new(res.to_s)
31
+ res_obj.time = Time.now
32
+
33
+ req_obj = Stella::Data::HTTPRequest.new(req.to_s)
34
+ req_obj.time = Time.now
35
+ req_obj.client_ip = '0.0.0.0'
36
+ req_obj.server_ip = '0.0.0.0'
37
+
38
+ req_obj.response = res_obj
39
+
40
+ changed
41
+ notify_observers(:http_request, req_obj)
42
+
43
+ rescue SystemExit => ex
44
+ after
45
+
46
+ rescue Exception => ex
47
+ # There are miscellaneous errors (mostly to do with
48
+ # incorrect content-length) that we don't care about.
49
+ Stella::LOGGER.error(ex.message)
50
+ end
51
+
52
+ end
53
+ )
54
+
55
+ # We need to trap this INT to kill WEBrick. Unlike with Pcap,
56
+ # rescuing Interrupt doesn't work.
57
+
58
+ trap('INT') do
59
+ after
60
+ end
61
+
62
+ @server.start
63
+ after
64
+
65
+ rescue => ex
66
+ after
67
+ end
68
+
69
+ def after
70
+ delete_observers
71
+ @server.shutdown
72
+ end
73
+
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,341 @@
1
+
2
+
3
+ module Stella
4
+ module Adapter
5
+
6
+ # SIEGE
7
+ # Usage: siege [options]
8
+ # siege [options] URL
9
+ # siege -g URL
10
+ # Options:
11
+ # -V, --version VERSION, prints version number to screen.
12
+ # -h, --help HELP, prints this section.
13
+ # -C, --config CONFIGURATION, show the current configuration.
14
+ # -v, --verbose VERBOSE, prints notification to screen.
15
+ # -g, --get GET, pull down headers from the server and display HTTP
16
+ # transaction. Great for web application debugging.
17
+ # -c, --concurrent=NUM CONCURRENT users, default is 10
18
+ # -u, --url="URL" Deprecated. Set URL as the last argument.
19
+ # -i, --internet INTERNET user simulation, hits the URLs randomly.
20
+ # -b, --benchmark BENCHMARK, signifies no delay for time testing.
21
+ # -t, --time=NUMm TIME based testing where "m" is the modifier S, M, or H
22
+ # no space between NUM and "m", ex: --time=1H, one hour test.
23
+ # -r, --reps=NUM REPS, number of times to run the test, default is 25
24
+ # -f, --file=FILE FILE, change the configuration file to file.
25
+ # -R, --rc=FILE RC, change the siegerc file to file. Overrides
26
+ # the SIEGERC environmental variable.
27
+ # -l, --log LOG, logs the transaction to PREFIX/var/siege.log
28
+ # -m, --mark="text" MARK, mark the log file with a string separator.
29
+ # -d, --delay=NUM Time DELAY, random delay between 1 and num designed
30
+ # to simulate human activity. Default value is 3
31
+ # -H, --header="text" Add a header to request (can be many)
32
+ # -A, --user-agent="text" Sets User-Agent in request
33
+ class Siege < Stella::Adapter::Base
34
+
35
+ attr_writer :reps, :concurrent, :version
36
+ attr_reader :user_agent
37
+ attr_accessor :help, :config, :verbose, :get, :log, :mark, :delay, :header
38
+ attr_accessor :rc, :file, :time, :benchmark, :internet
39
+
40
+ def initialize(options={}, arguments=[])
41
+
42
+ @name = 'siege'
43
+ @reps = 1
44
+ @concurrent = 1
45
+ @private_variables = ['private_variables', 'name', 'arguments', 'load_factor', 'working_directory', 'orig_logfile']
46
+ @load_factor = 1
47
+
48
+ @rc = File.join(ENV['HOME'] || ENV['USERPROFILE'], '.siegerc')
49
+
50
+ super(options, arguments)
51
+
52
+ # Siege won't run unless there's a siegerc file. If the default one doesn't exist
53
+ # we need to call siege.config to create it. This should only happen once.
54
+ # We use capture_output here so STDOUT and STDERR don't print to the screen.
55
+ Stella::Util.capture_output("#{@name}.config") do 'nothing' end unless File.exists? @rc
56
+ end
57
+
58
+
59
+
60
+ def error
61
+ (File.exists? stderr_path) ? FileUtil.read_file(stderr_path) : "Unknown error"
62
+ end
63
+
64
+ def version
65
+ vsn = 0
66
+ Stella::Util.capture_output("#{@name} --version") do |stdout, stderr|
67
+ stderr.join.scan(/SIEGE (\d+?\.\d+)/) { |v| vsn = v[0] }
68
+ end
69
+ vsn
70
+ end
71
+
72
+ # loadtest
73
+ #
74
+ # True or false: is the call to siege a load test? If it's a call to help or version or
75
+ # to display the config this with return false. It's no reason for someone to make this
76
+ # call through Stella but it's here for goodness sake.
77
+ def loadtest?
78
+ !@arguments.empty? # The argument is a URI
79
+ end
80
+
81
+ def ready?
82
+ @name && !instance_variables.empty?
83
+ end
84
+
85
+
86
+ # Before calling run
87
+ def before
88
+
89
+ # Keep a copy of the configuration file.
90
+ copy_siegerc
91
+
92
+ # Keep a copy of the URLs file.
93
+ copy_urls_file if @file
94
+
95
+ # TODO: Print message about neither --benchmark or --internet
96
+ end
97
+ def command
98
+ raise CommandNotReady.new(self.class.to_s) unless ready?
99
+
100
+ command = "#{@name} "
101
+
102
+ instance_variables.each do |name|
103
+ canon = name.tr('@', '') # instance_variables returns '@name'
104
+ next if @private_variables.member?(canon)
105
+
106
+ # It's important that we take the value from the getter method
107
+ # because it applies the load factor.
108
+ value = self.send(canon)
109
+ if (value.is_a? Array)
110
+ value.each { |el| command << "--#{canon.tr('_', '-')} #{EscapeUtil.shell_single_word(el.to_s)} " }
111
+ else
112
+ command << "--#{canon.tr('_', '-')} #{EscapeUtil.shell_single_word(value.to_s)} "
113
+ end
114
+
115
+ end
116
+
117
+ command << (@arguments.map { |uri| "'#{uri}'" }).join(' ') unless @arguments.empty?
118
+ command
119
+ end
120
+
121
+ # After calling run
122
+ def after
123
+
124
+ update_orig_logfile if @orig_logfile
125
+
126
+ end
127
+
128
+
129
+ def process_arguments(arguments)
130
+ opts = OptionParser.new
131
+ opts.on('-V', '--version') do |v| @version = v end
132
+ opts.on('-h', '--help') do |v| @help = v end
133
+ opts.on('-C', '--config') do |v| @config = v end
134
+ opts.on('-v', '--verbose') do |v| @verbose = v end
135
+ opts.on('-g', '--get') do |v| @get = v end
136
+ opts.on('-l', '--log') do |v| @log = v end
137
+ opts.on('-m S', '--mark=S', String) do |v| @mark = v end
138
+ opts.on('-d N', '--delay=N', Float) do |v| @delay = v end
139
+ opts.on('-H S', '--header=S', String) do |v| @header ||= []; @header << v end
140
+
141
+ opts.on('-r N', '--reps=N', Integer) do |v| @reps = v.to_i end
142
+ opts.on('-c N', '--concurrent=N', Integer) do |v| @concurrent = v.to_i end
143
+ opts.on('-R S', '--rc=S', String) do |v| @rc = v end
144
+ opts.on('-f S', '--file=S', String) do |v| @file = v end
145
+ opts.on('-t S', '--time=S', String) do |v| @time = v end
146
+ opts.on('-b', '--benchmark') do |v| @benchmark = true; end
147
+ opts.on('-i', '--internet') do |v| @internet = true; end
148
+ opts.on('-A S', '--user-agent=S', String) do |v| @user_agent ||= []; @user_agent << v end
149
+
150
+
151
+ opts.on('-n N',Integer) do |v|
152
+ Stella::LOGGER.error("-n is not a Siege parameter. You probably want -r.")
153
+ exit 1
154
+ end
155
+
156
+ # parse! removes the options it finds.
157
+ # It also fails when it finds unknown switches (i.e. -X)
158
+ # Which should leave only the remaining arguments (URIs in this case)
159
+ opts.parse!(arguments)
160
+
161
+ unless @benchmark
162
+ Stella::LOGGER.warn('--benchmark (or -b) is not selected. Siege will include "think time" for all requests.')
163
+ end
164
+
165
+ self.arguments = arguments
166
+
167
+ rescue OptionParser::InvalidOption => ex
168
+ # We want to replace this text so we grab just the name of the argument
169
+ badarg = ex.message.gsub('invalid option: ', '')
170
+ raise InvalidArgument.new(badarg)
171
+ end
172
+
173
+
174
+ def add_header(name, value)
175
+ @header ||= []
176
+ @header << "#{name}: #{value}"
177
+ end
178
+ def user_agent=(list=[])
179
+ return unless list && !list.empty?
180
+ list = list.to_ary
181
+ @user_agent ||= []
182
+ @user_agent << list
183
+ @user_agent.flatten
184
+ end
185
+
186
+ def vusers
187
+ concurrent || 0
188
+ end
189
+ def vusers=(v)
190
+ @concurrent = v
191
+ end
192
+ def requests
193
+ (@reps * concurrent_f).to_i
194
+ end
195
+ def requests=(v)
196
+ @reps = (v / concurrent_f).to_i
197
+ end
198
+ def vuser_requests
199
+ @reps
200
+ end
201
+
202
+ def concurrent
203
+ (@concurrent * @load_factor).to_i
204
+ end
205
+ def concurrent_f
206
+ (@concurrent * @load_factor).to_f
207
+ end
208
+ def reps
209
+ @reps
210
+ end
211
+
212
+
213
+ # Take the last line of the siege.log file and write it to the log file
214
+ # specified by the user. We don't this so running with Stella is
215
+ # identical to running it standalone
216
+ def update_orig_logfile
217
+
218
+ return unless (@orig_logfile)
219
+ log_str = FileUtil.read_file_to_array(log_file) || ''
220
+ return if log_str.empty?
221
+
222
+ if File.exists?(@orig_logfile)
223
+ FileUtil.append_file(@orig_logfile, log_str[-1], true)
224
+ else
225
+ FileUtil.write_file(@orig_logfile, log_str.join(''), true)
226
+ end
227
+
228
+ end
229
+
230
+ # We want to keep a copy of the configuration file and also
231
+ # modify it a little bit to make sure we get all the mad info from siege
232
+ def copy_siegerc
233
+
234
+ # Read in the siegerc file so we can manipulate it
235
+ siegerc_str = FileUtil.read_file(File.expand_path(@rc))
236
+
237
+ siegerc_vars = {
238
+ :verbose => [false, true], # We want to maximize the data output by siege
239
+ :logging => [false, true],
240
+ :csv => [false, true]
241
+ }
242
+
243
+ #if (@agent)
244
+ # siegerc_vars['user-agent'] = ['.*', 'dogs2']
245
+ #end
246
+
247
+ # We'll set the variables in the siegerc file
248
+ siegerc_vars.each_pair do |var,value|
249
+ siegerc_str.gsub!(/#{var}\s*=\s*#{value[0]}/, "#{var} = #{value[1]}") # make true
250
+ siegerc_str.gsub!(/^\#+\s*#{var}/, "#{var}") # remove comment
251
+ end
252
+
253
+ # Look for the enabled logile path
254
+ # We will use this later to update it from the last line in our copy
255
+ siegerc_str =~ /^\s*logfile\s*=\s*(.+?)$/
256
+ @orig_logfile = $1 || nil
257
+
258
+ # Replace all environment variables with literal values
259
+ @orig_logfile.gsub!(/\$\{#{$1}\}/, ENV[$1]) while (@orig_logfile =~ /\$\{(.+?)\}/ && ENV.has_key?($1))
260
+
261
+ @orig_logfile = File.expand_path(@orig_logfile) if @orig_logfile
262
+
263
+
264
+ siegerc_str.gsub!(/^\#*\s*logfile\s*=\s*.*?$/, "logfile = " + log_file)
265
+
266
+ FileUtil.write_file(rc_file, siegerc_str, true)
267
+ @rc = rc_file
268
+ end
269
+
270
+ # We want to keep a copy of the URLs file too
271
+ def copy_urls_file
272
+ if @file
273
+ File.copy(File.expand_path(@file), uris_file)
274
+ @file = uris_file
275
+ end
276
+ end
277
+
278
+ # Siege writes the summary to STDERR
279
+ def summary_file
280
+ File.new(stderr_path) if File.exists?(stderr_path)
281
+ end
282
+
283
+ def rc_file
284
+ File.join(@working_directory, "siegerc")
285
+ end
286
+
287
+ def log_file
288
+ File.join(@working_directory, "siege.log")
289
+ end
290
+
291
+ def uris_file
292
+ File.join(@working_directory, File.basename(@file))
293
+ end
294
+
295
+ def summary
296
+ return unless summary_file
297
+ raw = {}
298
+ summary_file.each_line { |l|
299
+ l.chomp!
300
+ nvpair = l.split(':')
301
+ next unless nvpair && nvpair.size == 2
302
+ n = nvpair[0].strip.tr(' ', '_').downcase[/\w+/]
303
+ v = nvpair[1].strip[/[\.\d]+/]
304
+ raw[n.to_sym] = v.to_f
305
+ }
306
+
307
+ stats = Stella::Test::Run::Summary.new
308
+
309
+ # Transactions: 750 hits
310
+ # Availability: 100.00 %
311
+ # Elapsed time: 2.33 secs
312
+ # Data transferred: 0.07 MB
313
+ # Response time: 0.21 secs
314
+ # Transaction rate: 321.89 trans/sec
315
+ # Throughput: 0.03 MB/sec
316
+ # Concurrency: 67.49
317
+ # Successful transactions: 750
318
+ # Failed transactions: 0
319
+ # Longest transaction: 0.33
320
+ # Shortest transaction: 0.10
321
+
322
+ stats.vusers = raw[:concurrency]
323
+ stats.data_transferred = raw[:data_transferred]
324
+ stats.elapsed_time = raw[:elapsed_time]
325
+ stats.response_time = raw[:response_time]
326
+ stats.transactions = raw[:transactions].to_i
327
+ stats.transaction_rate = raw[:transaction_rate]
328
+ stats.failed = raw[:failed_transactions].to_i
329
+ stats.successful = raw[:successful_transactions].to_i
330
+
331
+ #stats.shortest_transaction = raw[:shortest_transaction]
332
+ #stats.longest_transaction = raw[:longest_transaction]
333
+
334
+ stats
335
+ end
336
+
337
+
338
+
339
+ end
340
+ end
341
+ end
data/lib/stella/cli.rb ADDED
@@ -0,0 +1,258 @@
1
+
2
+ # http://www.ruby-doc.org/stdlib/libdoc/observer/rdoc/index.html
3
+
4
+
5
+ require 'stella/cli/base'
6
+
7
+ module Stella
8
+
9
+
10
+ # Stella::CLI
11
+ #
12
+ # The is the front-end class for the command-line implementation. The stella script
13
+ # creates an instance of this class which is the glue between the command-line
14
+ # and the Stella command classes.
15
+ # Note: All Stella::CLI classes are autoloaded and they add themselves to @@commands.
16
+ class CLI
17
+
18
+ # Auto populated with 'command' => Stella::CLI::[class] by each cli class on 'require'.
19
+ @@commands = {}
20
+
21
+ attr_reader :command_name
22
+ attr_reader :options
23
+ attr_reader :logger
24
+ attr_reader :stella_arguments
25
+ attr_reader :command_arguments
26
+
27
+
28
+ def initialize(arguments=[], stdin=nil)
29
+ @arguments = arguments
30
+ @stdin = stdin
31
+
32
+ @options = OpenStruct.new
33
+ @options.verbose = 0
34
+ @options.data_path = 'stella'
35
+ @options.agents = []
36
+
37
+ @stella_arguments = []
38
+ @command_arguments = []
39
+
40
+ process_arguments
41
+ process_options
42
+
43
+ end
44
+
45
+ def commands
46
+ @@commands
47
+ end
48
+
49
+ def run
50
+
51
+ unless (@command_name)
52
+ process_options(:display)
53
+ exit 0
54
+ end
55
+
56
+ # Pull the requested command object out of the list
57
+ # and tell it what shortname that was used to call it.
58
+ command = @@commands[@command_name].new(@command_name)
59
+
60
+ # Give the command object access to the runtime options and arguments
61
+ command.stella_options = @options
62
+ command.arguments = @command_arguments
63
+ command.working_directory = @options.data_path
64
+
65
+ command.run
66
+
67
+ rescue => ex
68
+ Stella::LOGGER.error(ex)
69
+ end
70
+
71
+
72
+ protected
73
+
74
+
75
+ # process_arguments
76
+ #
77
+ # Split the arguments into stella args and command args
78
+ # i.e. stella -H push -f (-H is a stella arg, -f is a command arg)
79
+ # True if required arguments were provided
80
+ def process_arguments
81
+
82
+ @command_name = nil
83
+ @arguments.each do |arg|
84
+ if (@@commands.has_key? arg)
85
+ @command_name = arg
86
+ index = @arguments.index(@command_name)
87
+ @command_arguments = @arguments[index + 1..@arguments.size]
88
+ @stella_arguments = @arguments[0..index - 1] if index > 0
89
+ break
90
+ end
91
+ end
92
+
93
+ @stella_arguments = [] unless @stella_arguments
94
+ @command_arguments = [] unless @command_arguments
95
+
96
+ # If there's no command we'll assume all the options are for Stella
97
+ unless @command_name
98
+ @stella_arguments = @arguments
99
+ @arguments = []
100
+ end
101
+
102
+ end
103
+
104
+ # process_options
105
+ #
106
+ # Handle the command-line options for stella. Note: The command specific
107
+ # options are handled by the command/*.rb classes
108
+ # display:: When true, it'll print out the options and not parse the arguments
109
+ def process_options(display=false)
110
+
111
+ opts = OptionParser.new
112
+ opts.banner = Stella::TEXT.msg(:option_help_usage)
113
+ opts.on Stella::TEXT.msg(:option_help_preamble, @@commands.keys.sort.join(', '))
114
+
115
+ opts.on(Stella::TEXT.msg(:option_help_options_title))
116
+ opts.on('-V', '--version', Stella::TEXT.msg(:option_help_version)) do
117
+ output_version
118
+ exit 0
119
+ end
120
+ opts.on('-h', '--help', Stella::TEXT.msg(:option_help_help)) { puts opts; exit 0 }
121
+ opts.on('-F', '--force', Stella::TEXT.msg(:option_help_force)) { |v| @options.force = true }
122
+
123
+ opts.on('-v', '--verbose', Stella::TEXT.msg(:option_help_verbose)) do
124
+
125
+ @options.verbose ||= 0
126
+ @options.verbose += 1
127
+ end
128
+ opts.on('-q', '--quiet', Stella::TEXT.msg(:option_help_quiet)) do
129
+ @options.quiet = true
130
+ end
131
+
132
+ # Overhead is interesting for development and auditing but we're not
133
+ # currently tracking this. It needed to be re-implemented from scratch
134
+ # so we'll redo this soon. It's also useful for comparing Ruby/JRuby/IronRuby
135
+ #opts.on('--overhead', String, Stella::TEXT.msg(:option_help_overhead)) do
136
+ # @options.showoverhead = true
137
+ #end
138
+
139
+ opts.on('-O', '--stdout', Stella::TEXT.msg(:option_help_stdout)) do
140
+ @options.stdout = true
141
+ end
142
+ opts.on('-E', '--stderr', Stella::TEXT.msg(:option_help_stderr)) do
143
+ @options.stdout = true
144
+ end
145
+
146
+ opts.on('-m', '--message=M', String, Stella::TEXT.msg(:option_help_message)) do |v|
147
+ @options.message = v.to_s
148
+ end
149
+ opts.on('-s', '--sleep=N', Float, Stella::TEXT.msg(:option_help_sleep)) do |v|
150
+ @options.sleep = v.to_f
151
+ end
152
+
153
+ # Ramp up, establish default and enforce limits
154
+ opts.on('-r [R,U]', '--rampup', String, Stella::TEXT.msg(:option_help_rampup)) do |v|
155
+ amount = (v) ? Stella::Util::expand_str(v) : [10,100]
156
+ amount[0] = MathUtil.enforce_limit(amount[0].to_i, 1, 100)
157
+ amount[1] = MathUtil.enforce_limit((amount[1]) ? amount[1].to_i : 0, (amount[0]*2), 1000)
158
+ @options.rampup = amount
159
+ end
160
+
161
+ opts.on('-x', '--repetitions=N', Integer, Stella::TEXT.msg(:option_help_testreps)) do |v|
162
+ @options.repetitions = MathUtil.enforce_limit(v,1,99)
163
+ end
164
+
165
+ opts.on('-w [N]', '--warmup', Float, Stella::TEXT.msg(:option_help_warmup, 0.1)) do |v|
166
+ @options.warmup = MathUtil.enforce_limit(((v) ? v : 0), 0.1, 1)
167
+ end
168
+
169
+ opts.on('-a', '--agent=[S]', String, Stella::TEXT.msg(:option_help_agent)) do |v|
170
+ @options.agents ||= []
171
+ agent_ary = Stella::Util::expand_str(v || 'random')
172
+ @options.agents.push(agent_ary)
173
+ end
174
+
175
+ opts.on('-d', '--datapath=S', String, Stella::TEXT.msg(:option_help_datapath, ".#{File::SEPARATOR}stella")) do |v|
176
+ @options.data_path = v.to_s
177
+ end
178
+ opts.on('-f', '--format=S', String, Stella::TEXT.msg(:option_help_format)) do |v|
179
+ @options.format = v.to_s
180
+ end
181
+
182
+ # This is used for printing the help from other parts of this class
183
+ if display
184
+ Stella::LOGGER.info opts
185
+ return
186
+ end
187
+
188
+ # This applies the configuration above to the arguments provided.
189
+ # It also removes the discovered options from @stella_arguments
190
+ # leaving only the unnamed arguments.
191
+ opts.parse!(@stella_arguments)
192
+
193
+ # Quiet supercedes verbose
194
+ @options.verbose = 0 if @options.quiet
195
+
196
+
197
+ # This outputs when debugging is enabled.
198
+ dump_inputs
199
+
200
+
201
+ rescue OptionParser::InvalidOption => ex
202
+ # We want to replace this text so we grab just the name of the argument
203
+ badarg = ex.message.gsub('invalid option: ', '')
204
+ raise InvalidArgument.new(badarg)
205
+ end
206
+
207
+ #
208
+ # Process data sent to STDIN (a pipe for example).
209
+ # We assume each line is a URI and add it to @arguments.
210
+ def process_standard_input
211
+ return if @stdin.tty? # We only want piped data
212
+
213
+ while !@stdin.eof? do
214
+ line = @stdin.readline
215
+ line.chomp!
216
+ @arguments << line
217
+ end
218
+
219
+ end
220
+
221
+ def output_version
222
+ Stella::LOGGER.info(:cli_print_version, Stella::VERSION.to_s)
223
+ end
224
+
225
+ def dump_inputs
226
+
227
+ #ENV.each_pair do |n,v|
228
+ # Stella::LOGGER.debug("ENV[#{n}]=#{v}")
229
+ #end
230
+
231
+ Stella::LOGGER.debug("Commands (#{@command_name}): #{@@commands.keys.join(',')}")
232
+
233
+
234
+ Stella::LOGGER.debug("Options: ")
235
+ @options.marshal_dump.each_pair do |n,v|
236
+ v = [v] unless v.is_a? Array
237
+ Stella::LOGGER.debug(" #{n} = #{v.join(',')}")
238
+ end
239
+
240
+ Stella::LOGGER.debug("Stella Arguments: #{@stella_arguments.join(',')}")
241
+ Stella::LOGGER.debug("Command Arguments: #{@command_arguments.join(',')}" )
242
+ end
243
+ end
244
+ end
245
+
246
+ # Autoload CLI classes. These classes add themselves to the class variable @@commands.
247
+ begin
248
+ previous_path = ""
249
+ cli_classes = Dir.glob(File.join(STELLA_HOME, 'lib', 'stella', 'cli', "*.rb"))
250
+ cli_classes.each do |path|
251
+ previous_path = path
252
+ require path
253
+ end
254
+ rescue LoadError => ex
255
+ Stella::LOGGER.info("Error loading #{previous_path}: #{ex.message}")
256
+ end
257
+
258
+