t2-server 0.0.4 → 0.1.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/README.rdoc +9 -2
- data/bin/delete_all_runs +6 -1
- data/bin/run_workflow +18 -9
- data/bin/server_info +14 -9
- data/lib/t2server.rb +31 -0
- data/lib/t2server/exceptions.rb +153 -0
- data/lib/t2server/run.rb +215 -31
- data/lib/t2server/server.rb +175 -95
- data/test/tc_paths.rb +60 -0
- data/test/tc_run.rb +72 -0
- data/test/tc_server.rb +71 -0
- data/test/ts_t2server.rb +52 -0
- data/test/workflows/hello.t2flow +21 -0
- metadata +27 -8
data/README.rdoc
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
= Taverna[http://www.taverna.org.uk/] 2 Server Interaction Gem
|
2
2
|
|
3
3
|
Authors:: Robert Haines
|
4
|
-
Gem Version:: 0.0
|
4
|
+
Gem Version:: 0.1.0
|
5
5
|
API Version:: 2.2a1
|
6
6
|
Contact:: mailto:rhaines@manchester.ac.uk
|
7
7
|
URL:: http://taverna.sourceforge.net/
|
@@ -29,7 +29,14 @@ http://github.com/myGrid/t2-server-gem
|
|
29
29
|
|
30
30
|
== Usage
|
31
31
|
|
32
|
-
|
32
|
+
There are two entry points for the T2Server API:
|
33
|
+
* T2Server::Run - Use this for running single jobs on a server.
|
34
|
+
* T2Server::Server - Use this if you are providing a web interface to one or
|
35
|
+
more Taverna 2 Server instances.
|
36
|
+
|
37
|
+
See the rdoc for more information.
|
38
|
+
|
39
|
+
As well as rdoc there are also a couple of example scripts which
|
33
40
|
demonstrate good use of the T2Server API. These are available in the
|
34
41
|
<tt>bin</tt> directory:
|
35
42
|
* run_workflow
|
data/bin/delete_all_runs
CHANGED
data/bin/run_workflow
CHANGED
@@ -47,8 +47,8 @@ def get_outputs(run, pout, dir="")
|
|
47
47
|
if pout
|
48
48
|
p data
|
49
49
|
else
|
50
|
-
# remove
|
51
|
-
filename = "#{dir
|
50
|
+
# strip path and convert remove /'s for file output
|
51
|
+
filename = "#{dir.strip_path}/#{out}".gsub('/', '-')
|
52
52
|
File.open(filename, "w") do |file|
|
53
53
|
file.syswrite(data)
|
54
54
|
end
|
@@ -106,11 +106,17 @@ else
|
|
106
106
|
wkf = IO.read(wkf_file)
|
107
107
|
end
|
108
108
|
|
109
|
-
# create run
|
110
|
-
|
109
|
+
# create run
|
110
|
+
begin
|
111
|
+
run = T2Server::Run.create(uri, wkf)
|
112
|
+
rescue T2Server::T2ServerError => e
|
113
|
+
puts e
|
114
|
+
exit 1
|
115
|
+
end
|
111
116
|
puts "Created run with uuid: #{run.uuid}"
|
112
117
|
puts "Created at #{run.create_time}"
|
113
118
|
|
119
|
+
# set inputs
|
114
120
|
inputs.each do |input, value|
|
115
121
|
puts "Set input '#{input}' to #{value}"
|
116
122
|
run.set_input(input, value)
|
@@ -126,12 +132,15 @@ puts "Finished at #{run.finish_time}"
|
|
126
132
|
# get outputs
|
127
133
|
stdout = run.stdout
|
128
134
|
stderr = run.stderr
|
129
|
-
|
130
|
-
|
131
|
-
if
|
135
|
+
exitcd = run.exitcode
|
136
|
+
puts "Exitcode: #{exitcd}"
|
137
|
+
if stdout != "" then puts "Stdout:\n#{stdout}" end
|
138
|
+
if stderr != "" then puts "Stderr:\n#{stderr}" end
|
132
139
|
|
133
|
-
|
134
|
-
|
140
|
+
if exitcd == 0
|
141
|
+
puts "Outputs:"
|
142
|
+
get_outputs(run, print_output)
|
143
|
+
end
|
135
144
|
|
136
145
|
# delete run
|
137
146
|
run.delete
|
data/bin/server_info
CHANGED
@@ -62,14 +62,19 @@ if uri == nil
|
|
62
62
|
end
|
63
63
|
|
64
64
|
# connect to server and output information
|
65
|
-
|
66
|
-
|
67
|
-
print "
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
65
|
+
begin
|
66
|
+
server = T2Server::Server.connect(uri)
|
67
|
+
print " Server: #{uri}\n"
|
68
|
+
print " Run limit: #{server.run_limit}\n"
|
69
|
+
runs = server.runs
|
70
|
+
print "No. of runs: #{runs.length}\n"
|
71
|
+
if runs.length > 0
|
72
|
+
print " Run list: #{runs[0].uuid} - #{runs[0].expiry}\n"
|
73
|
+
runs[1..-1].each do |run|
|
74
|
+
print " #{run.uuid} - #{run.expiry}\n"
|
75
|
+
end
|
74
76
|
end
|
77
|
+
rescue T2Server::T2ServerError => e
|
78
|
+
puts e
|
79
|
+
exit 1
|
75
80
|
end
|
data/lib/t2server.rb
CHANGED
@@ -31,10 +31,41 @@
|
|
31
31
|
# Author: Robert Haines
|
32
32
|
|
33
33
|
require 't2server/xml'
|
34
|
+
require 't2server/exceptions'
|
34
35
|
require 't2server/server'
|
35
36
|
require 't2server/run'
|
36
37
|
|
38
|
+
# This is a Ruby library to interface with the Taverna 2 Server REST API.
|
39
|
+
#
|
40
|
+
# There are two API entry points:
|
41
|
+
# * T2Server::Run - Use this for running single jobs on a server.
|
42
|
+
# * T2Server::Server - Use this if you are providing a web interface to a
|
43
|
+
# Taverna 2 Server instance.
|
37
44
|
module T2Server
|
45
|
+
# The version of this library
|
38
46
|
GEM_VERSION = "0.0.4"
|
47
|
+
# The version of the Taverna 2 Server API that this library can interface with
|
39
48
|
API_VERSION = "2.2a1"
|
40
49
|
end
|
50
|
+
|
51
|
+
# Add methods to the String class to operate on file paths.
|
52
|
+
class String
|
53
|
+
# :call-seq:
|
54
|
+
# str.strip_path -> string
|
55
|
+
#
|
56
|
+
# Returns a new String with one leading and one trailing slash
|
57
|
+
# removed from the ends of _str_ (if present).
|
58
|
+
def strip_path
|
59
|
+
self.gsub(/^\//, "").chomp("/")
|
60
|
+
end
|
61
|
+
|
62
|
+
# :call-seq:
|
63
|
+
# str.strip_path! -> str or nil
|
64
|
+
#
|
65
|
+
# Modifies _str_ in place as described for String#strip_path,
|
66
|
+
# returning _str_, or returning +nil+ if no modifications were made.
|
67
|
+
def strip_path!
|
68
|
+
g = self.gsub!(/^\//, "")
|
69
|
+
self.chomp!("/") || g
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# Copyright (c) 2010, The University of Manchester, UK.
|
2
|
+
#
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# * Redistributions of source code must retain the above copyright notice,
|
9
|
+
# this list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# * Neither the names of The University of Manchester nor the names of its
|
16
|
+
# contributors may be used to endorse or promote products derived from this
|
17
|
+
# software without specific prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
22
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
23
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
24
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
25
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
26
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
27
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
28
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
29
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
#
|
31
|
+
# Author: Robert Haines
|
32
|
+
|
33
|
+
require 'net/http'
|
34
|
+
|
35
|
+
module T2Server
|
36
|
+
# An internal module to collect all the exceptions that we
|
37
|
+
# can't really do anything about ourselves, such as
|
38
|
+
# timeouts and lost connections. This is further wrapped
|
39
|
+
# and exposed in the API as T2Server::ConnectionError below.
|
40
|
+
module InternalHTTPError #:nodoc:
|
41
|
+
end
|
42
|
+
|
43
|
+
# These are the HTTP errors we want to catch.
|
44
|
+
# Add the above exception as an ancestor to them all.
|
45
|
+
[
|
46
|
+
EOFError,
|
47
|
+
SocketError,
|
48
|
+
Timeout::Error,
|
49
|
+
Errno::EINVAL,
|
50
|
+
Errno::ETIMEDOUT,
|
51
|
+
Errno::ECONNRESET,
|
52
|
+
Errno::ECONNREFUSED,
|
53
|
+
Net::HTTPBadResponse,
|
54
|
+
Net::HTTPHeaderSyntaxError,
|
55
|
+
Net::ProtocolError
|
56
|
+
].each {|err| err.send(:include, InternalHTTPError)}
|
57
|
+
|
58
|
+
# This is a superclass for all T2Server exceptions. It is provided as a
|
59
|
+
# useful catch-all for all the internally raised/thrown exceptions.
|
60
|
+
class T2ServerError < RuntimeError
|
61
|
+
end
|
62
|
+
|
63
|
+
# Raised when there is an error with the connection to the server in some
|
64
|
+
# way. This could be due to the server not accepting the connection, the
|
65
|
+
# connection being dropped unexpectedly or a timeout of some sort.
|
66
|
+
class ConnectionError < T2ServerError
|
67
|
+
attr_reader :cause
|
68
|
+
|
69
|
+
# Create a new ConnectionError with the specified cause. The cause to be
|
70
|
+
# passed in should be the exception object that caused the connection
|
71
|
+
# error.
|
72
|
+
def initialize(cause)
|
73
|
+
@cause = cause
|
74
|
+
super "Connection error (#{@cause.class.name}): #{@cause.message}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Raised when there is an unexpected response from the server. This does
|
79
|
+
# not necessarily indicate a problem with the server.
|
80
|
+
class UnexpectedServerResponse < T2ServerError
|
81
|
+
|
82
|
+
# Create a new UnexpectedServerResponse with the specified unexpected
|
83
|
+
# response. The response to be passed in is that which was returned by a
|
84
|
+
# call to Net::HTTP#request.
|
85
|
+
def initialize(response)
|
86
|
+
body = "\n#{response.body}" if response.body
|
87
|
+
super "Unexpected server response: #{response.code}\n#{response.error!}#{body}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Raised when the run that is being operated on cannot be found. If the
|
92
|
+
# expectation is that the run exists then it could have been destroyed by
|
93
|
+
# a timeout or another user.
|
94
|
+
class RunNotFoundError < T2ServerError
|
95
|
+
attr_reader :uuid
|
96
|
+
|
97
|
+
# Create a new RunNotFoundError with the specified UUID.
|
98
|
+
def initialize(uuid)
|
99
|
+
@uuid = uuid
|
100
|
+
super "Could not find run #{@uuid}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Indicates that the attribute that the user is trying to read/change does
|
105
|
+
# not exist. The attribute could be a server or run attribute.
|
106
|
+
class AttributeNotFoundError < T2ServerError
|
107
|
+
attr_reader :path
|
108
|
+
|
109
|
+
# Create a new AttributeNotFoundError with the path to the erroneous
|
110
|
+
# attribute.
|
111
|
+
def initialize(path)
|
112
|
+
@path = path
|
113
|
+
super "Could not find attribute at #{@path}"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# The server is at capacity and cannot accept anymore runs at this time.
|
118
|
+
class ServerAtCapacityError < T2ServerError
|
119
|
+
attr_reader :limit
|
120
|
+
|
121
|
+
# Create a new ServerAtCapacityError with the specified limit for
|
122
|
+
# information.
|
123
|
+
def initialize(limit)
|
124
|
+
@limit = limit
|
125
|
+
super "The server is already running its configured limit of concurrent workflows (#{@limit})"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Access to the entity (run or attribute) is denied. The credentials
|
130
|
+
# supplied are not sufficient or the server does not allow the operation.
|
131
|
+
class AccessForbiddenError < T2ServerError
|
132
|
+
attr_reader :path
|
133
|
+
|
134
|
+
# Create a new AccessForbiddenError with the path to the restricted
|
135
|
+
# attribute.
|
136
|
+
def initialize(path)
|
137
|
+
@path = path
|
138
|
+
super "Access to #{@path} is forbidden. Either you do not have the required credentials or the server does not allow the requested operation"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Raised if an operation is performed on a run when it is in the wrong
|
143
|
+
# state. Trying to start a run if it is the finished state would cause this
|
144
|
+
# exception to be raised.
|
145
|
+
class RunStateError < T2ServerError
|
146
|
+
|
147
|
+
# Create a new RunStateError specifying both the current state and that
|
148
|
+
# which is needed to run the operation.
|
149
|
+
def initialize(current, need)
|
150
|
+
super "The run is in the wrong state (#{current}); it should be '#{need}' to perform that action"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
data/lib/t2server/run.rb
CHANGED
@@ -34,19 +34,29 @@ require 'rexml/document'
|
|
34
34
|
include REXML
|
35
35
|
|
36
36
|
module T2Server
|
37
|
-
|
37
|
+
|
38
|
+
# An interface for easily running jobs on a Taverna 2 Server with minimal
|
39
|
+
# setup and configuration required.
|
40
|
+
#
|
41
|
+
# A run can be in one of three states:
|
42
|
+
# * Initialized: The run has been accepted by the server. It may not yet be
|
43
|
+
# ready to run though as its input port may not have been set.
|
44
|
+
# * Running: The run is being run by the server.
|
45
|
+
# * Finished: The run has finished running and its outputs are available for
|
46
|
+
# download.
|
38
47
|
class Run
|
39
|
-
|
48
|
+
private_class_method :new
|
49
|
+
attr_reader :uuid
|
50
|
+
|
51
|
+
# :stopdoc:
|
40
52
|
STATE = {
|
41
53
|
:initialized => "Initialized",
|
42
54
|
:running => "Operating",
|
43
55
|
:finished => "Finished",
|
44
56
|
:stopped => "Stopped"
|
45
57
|
}
|
46
|
-
|
47
|
-
|
48
|
-
attr_reader :uuid
|
49
|
-
|
58
|
+
|
59
|
+
# New is private but rdoc does not get it right! Hence :stopdoc: section.
|
50
60
|
def initialize(server, uuid)
|
51
61
|
@server = server
|
52
62
|
@uuid = uuid
|
@@ -56,7 +66,16 @@ module T2Server
|
|
56
66
|
@links = get_attributes(@server.get_run_attribute(uuid, ""))
|
57
67
|
#@links.each {|key, val| puts "#{key}: #{val}"}
|
58
68
|
end
|
69
|
+
# :startdoc:
|
59
70
|
|
71
|
+
# :call-seq:
|
72
|
+
# Run.create(server, workflow) -> run
|
73
|
+
#
|
74
|
+
# Create a new run in the +Initialized+ state. The run will be created on
|
75
|
+
# the server with address supplied by _server_. This can either be a
|
76
|
+
# String of the form <tt>http://example.com:8888/blah</tt> or an already
|
77
|
+
# created instance of T2Server::Server. The _workflow_ must also be
|
78
|
+
# supplied as a string in t2flow or scufl format.
|
60
79
|
def Run.create(server, workflow, uuid="")
|
61
80
|
if server.class == String
|
62
81
|
server = Server.connect(server)
|
@@ -67,55 +86,130 @@ module T2Server
|
|
67
86
|
new(server, uuid)
|
68
87
|
end
|
69
88
|
end
|
70
|
-
|
89
|
+
|
90
|
+
# :call-seq:
|
91
|
+
# run.delete
|
92
|
+
#
|
93
|
+
# Delete this run from the server.
|
71
94
|
def delete
|
72
95
|
@server.delete_run uuid
|
73
96
|
end
|
74
|
-
|
97
|
+
|
98
|
+
# :call-seq:
|
99
|
+
# run.inputs -> string
|
100
|
+
#
|
101
|
+
# Return the path to the input ports of this run on the server.
|
75
102
|
def inputs
|
76
103
|
@links[:inputs]
|
77
104
|
end
|
78
|
-
|
105
|
+
|
106
|
+
# :call-seq:
|
107
|
+
# run.set_input(input, value) -> bool
|
108
|
+
#
|
109
|
+
# Set the workflow input port _input_ to _value_.
|
110
|
+
#
|
111
|
+
# Raises RunStateError if the run is not in the +Initialized+ state.
|
79
112
|
def set_input(input, value)
|
113
|
+
state = status
|
114
|
+
raise RunStateError.new(state, STATE[:initialized]) if state != STATE[:initialized]
|
115
|
+
|
80
116
|
@server.set_run_input(self, input, value)
|
81
117
|
end
|
82
|
-
|
118
|
+
|
119
|
+
# :call-seq:
|
120
|
+
# run.set_input_file(input, filename) -> bool
|
121
|
+
#
|
122
|
+
# Set the workflow input port _input_ to use the file at _filename_ as its
|
123
|
+
# input data.
|
124
|
+
#
|
125
|
+
# Raises RunStateError if the run is not in the +Initialized+ state.
|
83
126
|
def set_input_file(input, filename)
|
127
|
+
state = status
|
128
|
+
raise RunStateError.new(state, STATE[:initialized]) if state != STATE[:initialized]
|
129
|
+
|
84
130
|
@server.set_run_input_file(self, input, filename)
|
85
131
|
end
|
86
|
-
|
132
|
+
|
133
|
+
# :call-seq:
|
134
|
+
# run.get_output(output) -> string
|
135
|
+
#
|
136
|
+
# Return the value of the workflow output port _output_.
|
137
|
+
#
|
138
|
+
# Raises RunStateError if the run is not in the +Finished+ state.
|
87
139
|
def get_output(output, type="text/plain")
|
88
|
-
|
140
|
+
state = status
|
141
|
+
raise RunStateError.new(state, STATE[:finished]) if state != STATE[:finished]
|
142
|
+
|
143
|
+
output.strip_path!
|
89
144
|
doc = @server.get_run_attribute(@uuid, "#{@links[:wdir]}/out/#{output}")
|
90
145
|
doc
|
91
146
|
end
|
92
|
-
|
147
|
+
|
148
|
+
# :call-seq:
|
149
|
+
# run.expiry -> string
|
150
|
+
#
|
151
|
+
# Return the expiry time of this run. It is formatted as an ISO-8601
|
152
|
+
# timestamp.
|
93
153
|
def expiry
|
94
154
|
@server.get_run_attribute(@uuid, @links[:expiry])
|
95
155
|
end
|
96
|
-
|
156
|
+
|
157
|
+
# :call-seq:
|
158
|
+
# run.expiry=(time) -> bool
|
159
|
+
#
|
160
|
+
# Set the expiry time of this run to _time_. The format of _time_ should
|
161
|
+
# be an ISO-8601 timestamp.
|
97
162
|
def expiry=(date)
|
98
163
|
@server.set_run_attribute(@uuid, @links[:expiry], date)
|
99
164
|
end
|
100
165
|
|
166
|
+
# :call-seq:
|
167
|
+
# run.workflow -> string
|
168
|
+
#
|
169
|
+
# Get the workflow that this run represents.
|
101
170
|
def workflow
|
102
171
|
if @workflow == ""
|
103
172
|
@workflow = @server.get_run_attribute(@uuid, @links[:workflow])
|
104
173
|
end
|
105
174
|
@workflow
|
106
175
|
end
|
107
|
-
|
176
|
+
|
177
|
+
# :call-seq:
|
178
|
+
# run.status -> string
|
179
|
+
#
|
180
|
+
# Get the status of this run.
|
108
181
|
def status
|
109
182
|
@server.get_run_attribute(@uuid, @links[:status])
|
110
183
|
end
|
111
|
-
|
184
|
+
|
185
|
+
# :call-seq:
|
186
|
+
# run.start
|
187
|
+
#
|
188
|
+
# Start this run on the server.
|
189
|
+
#
|
190
|
+
# Raises RunStateError if the run is not in the +Initialized+ state.
|
112
191
|
def start
|
192
|
+
state = status
|
193
|
+
raise RunStateError.new(state, STATE[:initialized]) if state != STATE[:initialized]
|
194
|
+
|
113
195
|
@server.set_run_attribute(@uuid, @links[:status], STATE[:running])
|
114
196
|
end
|
115
|
-
|
197
|
+
|
198
|
+
# :call-seq:
|
199
|
+
# run.wait(params={})
|
200
|
+
#
|
201
|
+
# Wait (block) for this run to finish. Possible values that can be passed
|
202
|
+
# in via _params_ are:
|
203
|
+
# * :interval - How often (in seconds) to test for run completion.
|
204
|
+
# Default +1+.
|
205
|
+
# * :progress - Print a dot (.) each interval to show that something is
|
206
|
+
# actually happening. Default +false+.
|
207
|
+
#
|
208
|
+
# Raises RunStateError if the run is not in the +Running+ state.
|
116
209
|
def wait(params={})
|
117
|
-
|
118
|
-
|
210
|
+
state = status
|
211
|
+
raise RunStateError.new(state, STATE[:running]) if state != STATE[:running]
|
212
|
+
|
119
213
|
interval = params[:interval] || 1
|
120
214
|
progress = params[:progress] || false
|
121
215
|
keepalive = params[:keepalive] || false ### TODO maybe move out of params
|
@@ -132,42 +226,108 @@ module T2Server
|
|
132
226
|
# tidy up output if there is any
|
133
227
|
puts if progress
|
134
228
|
end
|
135
|
-
|
229
|
+
|
230
|
+
# :call-seq:
|
231
|
+
# run.exitcode -> integer
|
232
|
+
#
|
233
|
+
# Get the return code of the run. Zero indicates success.
|
136
234
|
def exitcode
|
137
235
|
@server.get_run_attribute(@uuid, @links[:exitcode]).to_i
|
138
236
|
end
|
139
|
-
|
237
|
+
|
238
|
+
# :call-seq:
|
239
|
+
# run.stdout -> string
|
240
|
+
#
|
241
|
+
# Get anything that the run printed to the standard out stream.
|
140
242
|
def stdout
|
141
243
|
@server.get_run_attribute(@uuid, @links[:stdout])
|
142
244
|
end
|
143
|
-
|
245
|
+
|
246
|
+
# :call-seq:
|
247
|
+
# run.stderr -> string
|
248
|
+
#
|
249
|
+
# Get anything that the run printed to the standard error stream.
|
144
250
|
def stderr
|
145
251
|
@server.get_run_attribute(@uuid, @links[:stderr])
|
146
252
|
end
|
147
|
-
|
253
|
+
|
254
|
+
# :call-seq:
|
255
|
+
# run.mkdir(dir) -> bool
|
256
|
+
#
|
257
|
+
# Create a directory in the run's working directory on the server. This
|
258
|
+
# could be used to store input data.
|
148
259
|
def mkdir(dir)
|
149
|
-
|
260
|
+
dir.strip_path!
|
261
|
+
if dir.include? ?/
|
262
|
+
# if a path is given then separate the leaf from the
|
263
|
+
# end and add the rest of the path to the wdir link
|
264
|
+
leaf = dir.split("/")[-1]
|
265
|
+
path = dir[0...-(leaf.length + 1)]
|
266
|
+
@server.make_run_dir(@uuid, "#{@links[:wdir]}/#{path}", leaf)
|
267
|
+
else
|
268
|
+
@server.make_run_dir(@uuid, @links[:wdir], dir)
|
269
|
+
end
|
150
270
|
end
|
151
|
-
|
271
|
+
|
272
|
+
# :call-seq:
|
273
|
+
# run.upload_file(filename, params={}) -> string
|
274
|
+
#
|
275
|
+
# Upload a file, with name _filename_, to the server. Possible values that
|
276
|
+
# can be passed in via _params_ are:
|
277
|
+
# * :dir - The directory to upload to. If this is not left blank the
|
278
|
+
# corresponding directory will need to have been created by Run#mkdir.
|
279
|
+
# * :rename - Save the file on the server with a different name.
|
280
|
+
#
|
281
|
+
# The name of the file on the server is returned.
|
152
282
|
def upload_file(filename, params={})
|
153
283
|
location = params[:dir] || ""
|
154
284
|
location = "#{@links[:wdir]}/#{location}"
|
155
285
|
rename = params[:rename] || ""
|
156
286
|
@server.upload_run_file(@uuid, filename, location, rename)
|
157
287
|
end
|
158
|
-
|
288
|
+
|
289
|
+
# :call-seq:
|
290
|
+
# run.upload_input_file(input, filename, params={}) -> string
|
291
|
+
#
|
292
|
+
# Upload a file, with name _filename_, to the server and set it as the
|
293
|
+
# input data for input port _input_. Possible values that can be passed
|
294
|
+
# in via _params_ are:
|
295
|
+
# * :dir - The directory to upload to. If this is not left blank the
|
296
|
+
# corresponding directory will need to have been created by Run#mkdir.
|
297
|
+
# * :rename - Save the file on the server with a different name.
|
298
|
+
#
|
299
|
+
# The name of the file on the server is returned.
|
300
|
+
#
|
301
|
+
# Raises RunStateError if the run is not in the +Initialized+ state.
|
159
302
|
def upload_input_file(input, filename, params={})
|
303
|
+
state = status
|
304
|
+
raise RunStateError.new(state, STATE[:initialized]) if state != STATE[:initialized]
|
305
|
+
|
160
306
|
file = upload_file(filename, params)
|
161
307
|
set_input_file(input, file)
|
162
308
|
end
|
163
|
-
|
309
|
+
|
310
|
+
# :call-seq:
|
311
|
+
# run.upload_baclava_file(filename) -> bool
|
312
|
+
#
|
313
|
+
# Upload a baclava file to be used for the workflow inputs.
|
164
314
|
def upload_baclava_file(filename)
|
315
|
+
state = status
|
316
|
+
raise RunStateError.new(state, STATE[:initialized]) if state != STATE[:initialized]
|
317
|
+
|
165
318
|
@baclava = true
|
166
319
|
rename = upload_file(filename)
|
167
320
|
@server.set_run_attribute(@uuid, @links[:baclava], rename)
|
168
321
|
end
|
169
322
|
|
323
|
+
# :call-seq:
|
324
|
+
# run.ls(dir="") -> [[dirs], [objects]]
|
325
|
+
#
|
326
|
+
# List a directory in the run's workspace on the server. If _dir_ is left
|
327
|
+
# blank then / is listed. The contents of a directory are returned as a
|
328
|
+
# list of two lists, directories and "objects" respectively.
|
170
329
|
def ls(dir="")
|
330
|
+
dir.strip_path!
|
171
331
|
dir_list = @server.get_run_attribute(@uuid, "#{@links[:wdir]}/#{dir}")
|
172
332
|
doc = Document.new(dir_list)
|
173
333
|
|
@@ -180,26 +340,50 @@ module T2Server
|
|
180
340
|
[dirs, files]
|
181
341
|
end
|
182
342
|
|
343
|
+
# :call-seq:
|
344
|
+
# run.initialized? -> bool
|
345
|
+
#
|
346
|
+
# Is this run in the +Initialized+ state?
|
183
347
|
def initialized?
|
184
348
|
status == STATE[:initialized]
|
185
349
|
end
|
186
|
-
|
350
|
+
|
351
|
+
# :call-seq:
|
352
|
+
# run.running? -> bool
|
353
|
+
#
|
354
|
+
# Is this run in the +Running+ state?
|
187
355
|
def running?
|
188
356
|
status == STATE[:running]
|
189
357
|
end
|
190
|
-
|
358
|
+
|
359
|
+
# :call-seq:
|
360
|
+
# run.finished? -> bool
|
361
|
+
#
|
362
|
+
# Is this run in the +Finished+ state?
|
191
363
|
def finished?
|
192
364
|
status == STATE[:finished]
|
193
365
|
end
|
194
|
-
|
366
|
+
|
367
|
+
# :call-seq:
|
368
|
+
# run.create_time -> string
|
369
|
+
#
|
370
|
+
# Get the creation time of this run formatted as an ISO-8601 timestamp.
|
195
371
|
def create_time
|
196
372
|
@server.get_run_attribute(@uuid, @links[:createtime])
|
197
373
|
end
|
198
|
-
|
374
|
+
|
375
|
+
# :call-seq:
|
376
|
+
# run.start_time -> string
|
377
|
+
#
|
378
|
+
# Get the start time of this run formatted as an ISO-8601 timestamp.
|
199
379
|
def start_time
|
200
380
|
@server.get_run_attribute(@uuid, @links[:starttime])
|
201
381
|
end
|
202
382
|
|
383
|
+
# :call-seq:
|
384
|
+
# run.finish_time -> string
|
385
|
+
#
|
386
|
+
# Get the finish time of this run formatted as an ISO-8601 timestamp.
|
203
387
|
def finish_time
|
204
388
|
@server.get_run_attribute(@uuid, @links[:finishtime])
|
205
389
|
end
|