t2-server 0.9.3 → 1.0.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.
- data/CHANGES.rdoc +79 -0
- data/LICENCE.rdoc +1 -1
- data/README.rdoc +94 -26
- data/Rakefile +6 -5
- data/bin/t2-delete-runs +25 -23
- data/bin/t2-get-output +11 -13
- data/bin/t2-run-workflow +91 -29
- data/bin/t2-server-info +29 -12
- data/extras/t2-server-stress +184 -0
- data/lib/t2-server-cli.rb +48 -23
- data/lib/t2-server.rb +2 -1
- data/lib/t2-server/admin.rb +7 -4
- data/lib/t2-server/exceptions.rb +23 -4
- data/lib/t2-server/interaction.rb +241 -0
- data/lib/t2-server/net/connection.rb +90 -60
- data/lib/t2-server/net/credentials.rb +25 -9
- data/lib/t2-server/net/parameters.rb +21 -6
- data/lib/t2-server/port.rb +229 -140
- data/lib/t2-server/run-cache.rb +99 -0
- data/lib/t2-server/run.rb +349 -332
- data/lib/t2-server/server.rb +115 -164
- data/lib/t2-server/util.rb +11 -9
- data/lib/t2-server/xml/libxml.rb +3 -2
- data/lib/t2-server/xml/nokogiri.rb +4 -3
- data/lib/t2-server/xml/rexml.rb +3 -2
- data/lib/t2-server/xml/xml.rb +47 -36
- data/lib/{t2server.rb → t2-server/xml/xpath_cache.rb} +29 -7
- data/t2-server.gemspec +16 -5
- data/test/tc_misc.rb +61 -0
- data/test/tc_perms.rb +17 -1
- data/test/tc_run.rb +164 -34
- data/test/tc_secure.rb +11 -2
- data/test/tc_server.rb +23 -2
- data/test/ts_t2server.rb +10 -8
- data/test/workflows/missing_outputs.t2flow +440 -0
- data/version.yml +3 -3
- metadata +42 -4
data/bin/t2-run-workflow
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# Copyright (c) 2010-
|
2
|
+
# Copyright (c) 2010-2013 The University of Manchester, UK.
|
3
3
|
#
|
4
4
|
# All rights reserved.
|
5
5
|
#
|
@@ -39,18 +39,18 @@ include T2Server::CLI
|
|
39
39
|
# set up options
|
40
40
|
inputs = {}
|
41
41
|
files = {}
|
42
|
-
options = {}
|
43
|
-
conn_params, creds = register_options("Usage: t2-run-workflow [options] "
|
42
|
+
options = {:screds => [], :interactions => :show}
|
43
|
+
conn_params, creds = register_options("Usage: t2-run-workflow [options] "\
|
44
44
|
"server-address") do |opt|
|
45
45
|
opt.separator " Where server-address is the full URI of the server to"
|
46
46
|
opt.separator " connect to, e.g.: http://example.com:8080/taverna"
|
47
47
|
opt.separator " and [options] can be:"
|
48
|
-
opt.on("-w WORKFLOW", "--workflow=WORKFLOW", "The workflow to run. If "
|
49
|
-
"this is not specified then the workflow is read from standard "
|
48
|
+
opt.on("-w WORKFLOW", "--workflow=WORKFLOW", "The workflow to run. If "\
|
49
|
+
"this is not specified then the workflow is read from standard "\
|
50
50
|
"input") do |val|
|
51
51
|
options[:wkf_file] = val.chomp
|
52
52
|
end
|
53
|
-
opt.on("-i INPUT:VALUE", "--input=INPUT:VALUE", "Set input port INPUT to "
|
53
|
+
opt.on("-i INPUT:VALUE", "--input=INPUT:VALUE", "Set input port INPUT to "\
|
54
54
|
"VALUE") do |val|
|
55
55
|
input, value = val.chomp.split(':', 2)
|
56
56
|
inputs[input] = value
|
@@ -60,35 +60,78 @@ conn_params, creds = register_options("Usage: t2-run-workflow [options] " +
|
|
60
60
|
input, filename = val.chomp.split(':', 2)
|
61
61
|
files[input] = filename
|
62
62
|
end
|
63
|
-
opt.on("-
|
63
|
+
opt.on("-I LEVEL", "--interactions=LEVEL", "Show, open or ignore any "\
|
64
|
+
"workflow interactions. LEVEL can be 'show' (the default), which simply "\
|
65
|
+
"lists the interaction URI in the terminal; 'open', which will open the "\
|
66
|
+
"interaction in a Web browser; or 'none', which will not check for "\
|
67
|
+
"interactions from the workflow at all. This should only be set to "\
|
68
|
+
"'none' if you are sure the workflow has no interactions or if you will "\
|
69
|
+
"be handling them in some other way.") do |val|
|
70
|
+
levels = [:show, :open, :none]
|
71
|
+
level = val.downcase.to_sym
|
72
|
+
options[:interactions] = levels.include?(level) ? level : :show
|
73
|
+
end
|
74
|
+
opt.on("-e EXPIRY", "--expiry=EXPIRY", "Set the expiry date/time of this "\
|
64
75
|
"run") do |val|
|
65
76
|
options[:expiry] = Time.parse(val.chomp)
|
66
77
|
end
|
67
|
-
opt.on("-
|
78
|
+
opt.on("-N NAME", "--name=NAME", "Give this run a name. Supported in "\
|
79
|
+
"Taverna Server versions 2.5.0 and up") do |val|
|
80
|
+
options[:name] = val.chomp
|
81
|
+
end
|
82
|
+
opt.on("-c URI::USER:PASS", "--credential=URI::USER:PASS",
|
83
|
+
"Provide a credential for a secure remote service. NOTE :: between URI "\
|
84
|
+
"and credential") do |val|
|
85
|
+
uri, cred = val.chomp.split('::', 2)
|
86
|
+
user, pass = cred.chomp.split(':', 2)
|
87
|
+
options[:screds] << [uri, user, pass]
|
88
|
+
end
|
89
|
+
opt.on("-b BACLAVA", "--baclava-in=BACLAVA", "Set baclava file for input "\
|
68
90
|
"port values") do |val|
|
69
91
|
inputs[:baclava] = val
|
70
92
|
end
|
71
|
-
opt.on("-o", "--baclava-out=BACLAVA", "Return outputs in baclava format."
|
93
|
+
opt.on("-o", "--baclava-out=BACLAVA", "Return outputs in baclava format."\
|
72
94
|
" A filename may be specified or 'out.xml' is used") do |val|
|
73
95
|
options[:baclava_out] = val.chomp
|
74
96
|
end
|
75
|
-
opt.on("-n", "--no-wait", "Do not wait for workflow to finish, return "
|
97
|
+
opt.on("-n", "--no-wait", "Do not wait for workflow to finish, return "\
|
76
98
|
"once it has started running") do |val|
|
77
99
|
options[:no_wait] = true
|
78
100
|
end
|
79
|
-
opt.on("-r", "--output-refs", "Return URIs that point to the data items "
|
101
|
+
opt.on("-r", "--output-refs", "Return URIs that point to the data items "\
|
80
102
|
"of the output rather than the data items themselves.") do |val|
|
81
103
|
options[:output_refs] = val
|
82
104
|
end
|
83
|
-
opt.on("-D", "--delete", "Delete the run from the server when it is "
|
84
|
-
"complete. By default the run and its results are preserved. Note that "
|
105
|
+
opt.on("-D", "--delete", "Delete the run from the server when it is "\
|
106
|
+
"complete. By default the run and its results are preserved. Note that "\
|
85
107
|
"the run will still be deleted when its expiry time is reached") do |val|
|
86
108
|
options[:delete] = val
|
87
109
|
end
|
88
|
-
opt.on("-z", "--zip=FILE", "Get the entire working directory of the run "
|
110
|
+
opt.on("-z", "--zip=FILE", "Get the entire working directory of the run "\
|
89
111
|
"in zip format and save it to the provided filename.") do |val|
|
90
112
|
options[:zip_out] = val.chomp
|
91
113
|
end
|
114
|
+
opt.on("-x", "--exitcode", "Return the exitcode of the run.") do
|
115
|
+
options[:exitcode] = true
|
116
|
+
end
|
117
|
+
opt.on("--stderr", 'Return the "standard error" output of the run.') do
|
118
|
+
options[:stderr] = true
|
119
|
+
end
|
120
|
+
opt.on("--stdout", 'Return the "standard out" output of the run.') do
|
121
|
+
options[:stdout] = true
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
if options[:interactions] == :open
|
126
|
+
begin
|
127
|
+
require 'launchy'
|
128
|
+
rescue LoadError
|
129
|
+
puts "\n****\nTo support opening interactions in your Web browser the "\
|
130
|
+
"launchy gem must be installed:\n\n$ gem install launchy\n\n"\
|
131
|
+
"Interaction URIs will be listed here instead. Please copy and paste "\
|
132
|
+
"them into your Web browser to display them.\n****\n\n"
|
133
|
+
options[:interactions] = :show
|
134
|
+
end
|
92
135
|
end
|
93
136
|
|
94
137
|
# read and check server address
|
@@ -107,6 +150,12 @@ begin
|
|
107
150
|
puts "Created run with identifier: #{run.identifier}"
|
108
151
|
puts "Created at #{run.create_time}"
|
109
152
|
|
153
|
+
# set run name
|
154
|
+
if options[:name]
|
155
|
+
run.name = options[:name]
|
156
|
+
puts "Run name set to '#{run.name}'"
|
157
|
+
end
|
158
|
+
|
110
159
|
# set run expiry
|
111
160
|
if options[:expiry]
|
112
161
|
run.expiry=(options[:expiry])
|
@@ -135,43 +184,56 @@ begin
|
|
135
184
|
end
|
136
185
|
end
|
137
186
|
|
187
|
+
# set remote service credentials
|
188
|
+
options[:screds].each do |list|
|
189
|
+
run.add_password_credential(list[0], list[1], list[2])
|
190
|
+
end
|
191
|
+
|
138
192
|
# output baclava?
|
139
193
|
run.request_baclava_output if options[:baclava_out]
|
140
194
|
|
141
|
-
# start run
|
142
|
-
run.start
|
195
|
+
# try to start run
|
196
|
+
unless run.start
|
197
|
+
puts "Run could not be started because the server is already running "\
|
198
|
+
"its configured maximum number of runs. Please try again later."
|
199
|
+
run.delete
|
200
|
+
exit 1
|
201
|
+
end
|
143
202
|
puts "Started at #{run.start_time}"
|
144
203
|
|
145
204
|
# bail out if user doesn't want to wait
|
146
205
|
exit 0 if options[:no_wait]
|
147
206
|
|
148
|
-
# otherwise wait
|
149
|
-
print "Running"
|
207
|
+
# otherwise wait, but list or open notifications if there are any
|
208
|
+
print "Running."
|
150
209
|
until run.finished?
|
151
210
|
sleep(1)
|
211
|
+
unless options[:interactions] == :none
|
212
|
+
run.notifications(:new_requests).each do |note|
|
213
|
+
if options[:interactions] == :open
|
214
|
+
Launchy.open note.uri
|
215
|
+
else
|
216
|
+
puts "\n#{note.uri}\n"
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
152
220
|
print "."
|
153
221
|
$stdout.flush
|
154
222
|
end
|
155
223
|
puts "\nFinished at #{run.finish_time}"
|
156
224
|
|
157
225
|
# get outputs
|
158
|
-
stdout = run.stdout
|
159
|
-
stderr = run.stderr
|
160
226
|
exitcd = run.exitcode
|
161
|
-
puts "Exitcode: #{exitcd}"
|
162
|
-
|
163
|
-
|
227
|
+
puts "Exitcode: #{exitcd}" if options[:exitcode] || exitcd != 0
|
228
|
+
puts "Stdout:\n#{run.stdout}" if options[:stdout]
|
229
|
+
puts "Stderr:\n#{run.stderr}" if options[:stderr]
|
164
230
|
|
165
231
|
if exitcd == 0
|
166
232
|
if options[:baclava_out]
|
167
|
-
|
168
|
-
file.syswrite(run.baclava_output)
|
169
|
-
end
|
233
|
+
run.baclava_output(options[:baclava_out])
|
170
234
|
puts "Baclava file written to '#{options[:baclava_out]}'"
|
171
235
|
elsif options[:zip_out]
|
172
|
-
|
173
|
-
file.syswrite(run.zip_output)
|
174
|
-
end
|
236
|
+
run.zip_output(options[:zip_out])
|
175
237
|
puts "Zip file written to '#{options[:zip_out]}'"
|
176
238
|
else
|
177
239
|
# go through the outputs and print them out
|
data/bin/t2-server-info
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# Copyright (c) 2010-
|
2
|
+
# Copyright (c) 2010-2013 The University of Manchester, UK.
|
3
3
|
#
|
4
4
|
# All rights reserved.
|
5
5
|
#
|
@@ -38,15 +38,16 @@ require 'hirb'
|
|
38
38
|
include T2Server::CLI
|
39
39
|
|
40
40
|
# set up options
|
41
|
-
options = {}
|
41
|
+
options = { :list => 0 }
|
42
42
|
conn_params, creds = register_options("Usage: t2-server-info [options] " +
|
43
43
|
"server-address") do |opt|
|
44
44
|
opt.separator " Where server-address is the full URI of the server to"
|
45
45
|
opt.separator " connect to, e.g.: http://example.com:8080/taverna"
|
46
46
|
opt.separator " and [options] can be:"
|
47
47
|
|
48
|
-
opt.on("-l", "--list", "List details for the runs on this server."
|
49
|
-
|
48
|
+
opt.on("-l", "--list", "List details for the runs on this server. Repeat "\
|
49
|
+
"(e.g. -ll or -lll) to increase the amount of detail shown.") do
|
50
|
+
options[:list] += 1
|
50
51
|
end
|
51
52
|
end
|
52
53
|
|
@@ -61,14 +62,30 @@ begin
|
|
61
62
|
puts " Run limit: #{server.run_limit(creds)}"
|
62
63
|
runs = server.runs(creds)
|
63
64
|
puts "No. of runs: #{runs.length}"
|
64
|
-
if options[:list] && runs.length > 0
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
:
|
71
|
-
:
|
65
|
+
if options[:list] > 0 && runs.length > 0
|
66
|
+
if options[:list] == 1
|
67
|
+
fields = [:identifier]
|
68
|
+
headers = {:identifier => 'Run ID'}
|
69
|
+
lengths = {}
|
70
|
+
elsif options[:list] == 2
|
71
|
+
fields = [:identifier, :status, :expiry]
|
72
|
+
headers = {:identifier => 'Run ID', :status => 'Status',
|
73
|
+
:expiry => 'Expiry time (local)'}
|
74
|
+
lengths = {:status => 11, :expiry => 19}
|
75
|
+
else
|
76
|
+
fields = [:identifier, :name, :status, :expiry]
|
77
|
+
headers = {:identifier => 'Run ID', :name => "Name",
|
78
|
+
:status => 'Status', :expiry => 'Expiry time (local)'}
|
79
|
+
lengths = {:identifier => 11, :name => 25, :status => 11,
|
80
|
+
:expiry => 19}
|
81
|
+
end
|
82
|
+
|
83
|
+
puts Hirb::Helpers::ObjectTable.render(runs,
|
84
|
+
:fields => fields,
|
85
|
+
:headers => headers,
|
86
|
+
:filters => {:expiry => [:strftime, "%H:%M:%S %d/%m/%Y"]},
|
87
|
+
:max_fields => lengths,
|
88
|
+
:description => false)
|
72
89
|
end
|
73
90
|
end
|
74
91
|
rescue RuntimeError => e
|
@@ -0,0 +1,184 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Copyright (c) 2010-2013 The University of Manchester, UK.
|
3
|
+
#
|
4
|
+
# All rights reserved.
|
5
|
+
#
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
7
|
+
# modification, are permitted provided that the following conditions are met:
|
8
|
+
#
|
9
|
+
# * Redistributions of source code must retain the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer.
|
11
|
+
#
|
12
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
13
|
+
# this list of conditions and the following disclaimer in the documentation
|
14
|
+
# and/or other materials provided with the distribution.
|
15
|
+
#
|
16
|
+
# * Neither the names of The University of Manchester nor the names of its
|
17
|
+
# contributors may be used to endorse or promote products derived from this
|
18
|
+
# software without specific prior written permission.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
23
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
24
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
25
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
26
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
27
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
28
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
29
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
30
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
#
|
32
|
+
# Author: Robert Haines
|
33
|
+
|
34
|
+
require 'rubygems'
|
35
|
+
require 't2-server-cli'
|
36
|
+
require 'hirb'
|
37
|
+
|
38
|
+
include T2Server::CLI
|
39
|
+
|
40
|
+
# Set up options and workflow inputs.
|
41
|
+
inputs = {}
|
42
|
+
files = {}
|
43
|
+
options = {:number => 5, :backoff => 0, :screds => []}
|
44
|
+
conn_params, creds = register_options("Usage: t2-server-stress [options] "\
|
45
|
+
"server-address") do |opt|
|
46
|
+
opt.separator " Where server-address is the full URI of the server to"
|
47
|
+
opt.separator " connect to, e.g.: http://example.com:8080/taverna"
|
48
|
+
opt.separator " and [options] can be:"
|
49
|
+
|
50
|
+
opt.on("-n NUMBER", "--number=NUMBER", "Number of concurrent runs. "\
|
51
|
+
"Default 5") do |val|
|
52
|
+
options[:number] = val.chomp.to_i
|
53
|
+
end
|
54
|
+
opt.on("-b NUMBER", "--backoff=NUMBER", "Time (in seconds) to back off "\
|
55
|
+
"before starting next run. Default 0") do |val|
|
56
|
+
options[:backoff] = val.chomp.to_i
|
57
|
+
end
|
58
|
+
opt.on("-w WORKFLOW", "--workflow=WORKFLOW", "The workflow to run. If "\
|
59
|
+
"this is not specified then the workflow is read from standard "\
|
60
|
+
"input") do |val|
|
61
|
+
options[:wkf_file] = val.chomp
|
62
|
+
end
|
63
|
+
opt.on("-i INPUT:VALUE", "--input=INPUT:VALUE", "Set input port INPUT to "\
|
64
|
+
"VALUE") do |val|
|
65
|
+
input, value = val.chomp.split(':', 2)
|
66
|
+
inputs[input] = value
|
67
|
+
end
|
68
|
+
opt.on("-f INPUT:FILE", "--input-file=INPUT:FILE",
|
69
|
+
"Set input port INPUT to use the contents of FILE as its input") do |val|
|
70
|
+
input, filename = val.chomp.split(':', 2)
|
71
|
+
files[input] = filename
|
72
|
+
end
|
73
|
+
opt.on("-K", "--keep-runs",
|
74
|
+
"Do not delete the runs at the end of the test") do
|
75
|
+
options[:keep] = true
|
76
|
+
end
|
77
|
+
opt.on("-c URI::USER:PASS", "--credential=URI::USER:PASS",
|
78
|
+
"Provide a credential for a secure remote service. NOTE :: between URI "\
|
79
|
+
"and credential") do |val|
|
80
|
+
uri, cred = val.chomp.split('::', 2)
|
81
|
+
user, pass = cred.chomp.split(':', 2)
|
82
|
+
options[:screds] << [uri, user, pass]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Read and check server address and credentials.
|
87
|
+
uri, creds = parse_address(ARGV.shift, creds)
|
88
|
+
|
89
|
+
# Read workflow and ensure that it is not empty.
|
90
|
+
if options[:wkf_file]
|
91
|
+
wkf = IO.read(options[:wkf_file])
|
92
|
+
else
|
93
|
+
wkf = ARGF.read
|
94
|
+
end
|
95
|
+
exit 1 if wkf == ""
|
96
|
+
|
97
|
+
# Connect to server and check it's in a good state.
|
98
|
+
server = T2Server::Server.new(uri, conn_params)
|
99
|
+
puts "\nConnected to server at #{server.uri}"
|
100
|
+
|
101
|
+
current_runs = server.runs(creds)
|
102
|
+
unless current_runs.length == 0
|
103
|
+
puts "\nServer already has runs on it. Please clear out all runs before "\
|
104
|
+
"running the stress tests."
|
105
|
+
exit 1
|
106
|
+
end
|
107
|
+
|
108
|
+
run_limit = server.run_limit(creds)
|
109
|
+
unless run_limit >= options[:number]
|
110
|
+
puts "\nYou have asked for more concurrent runs than this server has been "\
|
111
|
+
"configured to allow. Please set the number to #{run_limit} or less."
|
112
|
+
exit 1
|
113
|
+
end
|
114
|
+
|
115
|
+
puts "\nInitializing #{options[:number]} runs and setting inputs."
|
116
|
+
runs = []
|
117
|
+
options[:number].times do
|
118
|
+
server.create_run(wkf, creds) do |run|
|
119
|
+
# Set inputs.
|
120
|
+
run.input_ports.each_value do |port|
|
121
|
+
input = port.name
|
122
|
+
if inputs.include? input
|
123
|
+
port.value = inputs[input]
|
124
|
+
elsif files.include? input
|
125
|
+
port.file = files[input]
|
126
|
+
else
|
127
|
+
puts "Input '#{input}' has not been given, exiting."
|
128
|
+
run.delete
|
129
|
+
exit 1
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
options[:screds].each do |list|
|
134
|
+
run.add_password_credential(list[0], list[1], list[2])
|
135
|
+
end
|
136
|
+
|
137
|
+
runs << run
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
puts "\nStarting runs with #{options[:backoff]} seconds back-off time between."
|
142
|
+
|
143
|
+
w_start = Time.now
|
144
|
+
runs.each do |run|
|
145
|
+
r_start = Time.now
|
146
|
+
while !run.start
|
147
|
+
puts "Server has reached configured maximum of concurrently running "\
|
148
|
+
"runs. Backing off for 10 seconds before retrying..."
|
149
|
+
sleep(10)
|
150
|
+
end
|
151
|
+
r_started = Time.now
|
152
|
+
puts "Run started at #{r_started} and took #{r_started - r_start} seconds to start."
|
153
|
+
sleep options[:backoff] if options[:backoff] > 0
|
154
|
+
end
|
155
|
+
|
156
|
+
puts "\nWaiting for runs to finish."
|
157
|
+
|
158
|
+
while runs.count { |run| run.finished? } < options[:number] do
|
159
|
+
sleep(5)
|
160
|
+
end
|
161
|
+
w_end = Time.now
|
162
|
+
|
163
|
+
puts "\nRuns finished.\n\nRun times:"
|
164
|
+
|
165
|
+
total = 0
|
166
|
+
runs.each do |run|
|
167
|
+
time = run.finish_time - run.start_time
|
168
|
+
total += time
|
169
|
+
puts time
|
170
|
+
end
|
171
|
+
|
172
|
+
average = total / options[:number]
|
173
|
+
puts "\nAverage time: #{average}"
|
174
|
+
w_time = w_end - w_start
|
175
|
+
puts "Wallclock time: #{w_time}"
|
176
|
+
|
177
|
+
unless options[:keep]
|
178
|
+
puts "\nDeleting runs."
|
179
|
+
runs.each do |run|
|
180
|
+
run.delete
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
puts "\nDone."
|