t2-server 0.2.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +11 -6
- data/bin/{delete_all_runs → t2-delete-runs} +51 -9
- data/bin/{run_workflow → t2-run-workflow} +35 -28
- data/bin/{server_info → t2-server-info} +3 -2
- data/lib/t2-server.rb +71 -0
- data/lib/{t2server → t2-server}/exceptions.rb +3 -1
- data/lib/{t2server → t2-server}/run.rb +87 -31
- data/lib/{t2server → t2-server}/server.rb +89 -47
- data/lib/{t2server → t2-server}/xml.rb +36 -1
- data/lib/t2server.rb +3 -39
- data/test/tc_paths.rb +1 -1
- data/test/tc_run.rb +2 -5
- data/test/tc_server.rb +1 -1
- data/test/ts_t2server.rb +5 -2
- metadata +37 -16
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.
|
4
|
+
Gem Version:: 0.5.0
|
5
5
|
API Version:: 2.2a1
|
6
6
|
Contact:: mailto:rhaines@manchester.ac.uk
|
7
7
|
URL:: http://taverna.sourceforge.net/
|
@@ -34,17 +34,22 @@ There are two entry points for the T2Server API:
|
|
34
34
|
* T2Server::Server - Use this if you are providing a web interface to one or
|
35
35
|
more Taverna 2 Server instances.
|
36
36
|
|
37
|
+
In both cases the gem should be initialized by requiring the top level ruby
|
38
|
+
file:
|
39
|
+
require 't2-server.rb'
|
40
|
+
|
37
41
|
See the rdoc for more information.
|
38
42
|
|
39
43
|
As well as rdoc there are also a couple of example scripts which
|
40
44
|
demonstrate good use of the T2Server API. These are available in the
|
41
|
-
<tt>bin</tt> directory
|
42
|
-
|
43
|
-
*
|
44
|
-
*
|
45
|
+
<tt>bin</tt> directory but are also installed with the library code when the
|
46
|
+
gem is installed:
|
47
|
+
* t2-run-workflow
|
48
|
+
* t2-server-info
|
49
|
+
* t2-delete-runs
|
45
50
|
Running any of these scripts with a <tt>-h</tt> or <tt>--help</tt>
|
46
51
|
switch will show how to use them, e.g.:
|
47
|
-
|
52
|
+
t2-run-workflow --help
|
48
53
|
|
49
54
|
== Support
|
50
55
|
|
@@ -31,16 +31,21 @@
|
|
31
31
|
#
|
32
32
|
# Author: Robert Haines
|
33
33
|
|
34
|
-
require '
|
34
|
+
require 'rubygems'
|
35
|
+
require 't2-server'
|
35
36
|
require 'optparse'
|
36
37
|
|
37
38
|
# set up options
|
39
|
+
delete_all = false
|
38
40
|
opts = OptionParser.new do |opt|
|
39
|
-
opt.banner = "Usage:
|
41
|
+
opt.banner = "Usage: t2-delete-runs [options] server-address [run-ids...]"
|
40
42
|
opt.separator ""
|
41
|
-
opt.separator " Where server-address is the full URI of the server to"
|
42
|
-
opt.separator "
|
43
|
-
opt.separator " and [options] can be:"
|
43
|
+
opt.separator " Where server-address is the full URI of the server to connect to,"
|
44
|
+
opt.separator " e.g.: http://example.com:8080/taverna, run-ids are the id numbers"
|
45
|
+
opt.separator " of the runs you want to delete and [options] can be:"
|
46
|
+
opt.on("--all", "Delete all runs on the server") do
|
47
|
+
delete_all = true
|
48
|
+
end
|
44
49
|
opt.on_tail("-h", "-?", "--help", "Show this message") do
|
45
50
|
puts opt
|
46
51
|
exit
|
@@ -55,16 +60,53 @@ end
|
|
55
60
|
# parse options
|
56
61
|
opts.parse!
|
57
62
|
|
58
|
-
#
|
59
|
-
|
63
|
+
# get runs and server address from the arguments
|
64
|
+
runs = []
|
65
|
+
address = ""
|
66
|
+
for arg in ARGV
|
67
|
+
if arg.match(/https?:\/\//) == nil
|
68
|
+
runs << arg
|
69
|
+
else
|
70
|
+
address = arg
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# can't do anything without a server address
|
75
|
+
if address == ""
|
60
76
|
puts opts
|
61
77
|
exit 1
|
62
78
|
end
|
63
79
|
|
64
|
-
# connect
|
80
|
+
# connect...
|
65
81
|
begin
|
66
|
-
T2Server::Server.connect(ARGV[0])
|
82
|
+
server = T2Server::Server.connect(ARGV[0])
|
67
83
|
rescue T2Server::T2ServerError => e
|
68
84
|
puts e
|
69
85
|
exit 1
|
70
86
|
end
|
87
|
+
|
88
|
+
# ...and delete them!
|
89
|
+
if delete_all
|
90
|
+
begin
|
91
|
+
server.delete_all_runs
|
92
|
+
rescue T2Server::AuthorizationError => ae
|
93
|
+
puts "You are not authorized to delete runs on this server."
|
94
|
+
rescue T2Server::T2ServerError => e
|
95
|
+
puts "There was a problem while deleting runs. Some may remain on the server."
|
96
|
+
end
|
97
|
+
else
|
98
|
+
for run in runs
|
99
|
+
begin
|
100
|
+
server.delete_run(run)
|
101
|
+
rescue T2Server::RunNotFoundError => rnf
|
102
|
+
puts "Run '#{run}' not found - skipping."
|
103
|
+
next
|
104
|
+
rescue T2Server::AuthorizationError => ae
|
105
|
+
puts "You are not authorized to delete run '#{run}' - skipping."
|
106
|
+
next
|
107
|
+
rescue T2Server::T2ServerError => e
|
108
|
+
puts "There was a problem while deleting run '#{run}' - skipping."
|
109
|
+
next
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -31,39 +31,39 @@
|
|
31
31
|
#
|
32
32
|
# Author: Robert Haines
|
33
33
|
|
34
|
-
require '
|
34
|
+
require 'rubygems'
|
35
|
+
require 't2-server'
|
35
36
|
require 'optparse'
|
36
37
|
|
37
38
|
# go through the outputs and either print the contents
|
38
39
|
# out or save them to a file.
|
39
40
|
# if the output is a list, it appears as a directory so
|
40
41
|
# all the individual entries must be grabbed from there.
|
41
|
-
def get_outputs(run,
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
puts "written to file: #{filename}"
|
56
|
-
end
|
42
|
+
def get_outputs(run, refs)
|
43
|
+
# get a list of the outputs
|
44
|
+
lists, items = run.ls("out")
|
45
|
+
|
46
|
+
# go through the lists
|
47
|
+
lists.each do |l|
|
48
|
+
print " #{l} -> "
|
49
|
+
p run.get_output("#{l}", refs)
|
50
|
+
end
|
51
|
+
|
52
|
+
# go through the singletons
|
53
|
+
items.each do |i|
|
54
|
+
print " #{i} -> "
|
55
|
+
p run.get_output("#{i}", refs)
|
57
56
|
end
|
58
|
-
end
|
57
|
+
end
|
59
58
|
|
60
59
|
# set up options
|
61
60
|
inputs = {}
|
62
61
|
wkf_file = ""
|
63
|
-
|
62
|
+
output_refs = false
|
64
63
|
baclava_out = ""
|
64
|
+
delete_run = false
|
65
65
|
opts = OptionParser.new do |opt|
|
66
|
-
opt.banner = "Usage:
|
66
|
+
opt.banner = "Usage: t2-run-workflow [options] server-address"
|
67
67
|
opt.separator ""
|
68
68
|
opt.separator " Where server-address is the full URI of the server to"
|
69
69
|
opt.separator " connect to, e.g.: http://example.com:8080/taverna"
|
@@ -73,7 +73,7 @@ opts = OptionParser.new do |opt|
|
|
73
73
|
wkf_file = val
|
74
74
|
end
|
75
75
|
opt.on("-i INPUT:VALUE", "--input=INPUT:VALUE", "Set input port INPUT to VALUE") do |val|
|
76
|
-
input, value = val.chomp.split(':')
|
76
|
+
input, value = val.chomp.split(':', 2)
|
77
77
|
inputs[input] = value
|
78
78
|
end
|
79
79
|
opt.on("-b BACLAVA", "--baclava-in=BACLAVA", "Set baclava file for input port values") do |val|
|
@@ -87,9 +87,14 @@ opts = OptionParser.new do |opt|
|
|
87
87
|
baclava_out = "out.xml"
|
88
88
|
end
|
89
89
|
end
|
90
|
-
opt.on("-
|
91
|
-
"
|
92
|
-
|
90
|
+
opt.on("-r", "--output-refs", "Return URIs that point to the data items " +
|
91
|
+
"of the output rather than the data items themselves.") do |val|
|
92
|
+
output_refs = val
|
93
|
+
end
|
94
|
+
opt.on("-D", "--delete", "Delete the run from the server when it is " +
|
95
|
+
"complete. By default the run and its results are preserved. Note that " +
|
96
|
+
"the run will still be deleted when its expiry time is reached") do |val|
|
97
|
+
delete_run = val
|
93
98
|
end
|
94
99
|
opt.on_tail("-h", "-?", "--help", "Show this message") do
|
95
100
|
puts opt
|
@@ -166,10 +171,12 @@ if exitcd == 0
|
|
166
171
|
puts "Baclava file written to '#{baclava_out}'"
|
167
172
|
else
|
168
173
|
puts "Outputs:"
|
169
|
-
get_outputs(run,
|
174
|
+
get_outputs(run, output_refs)
|
170
175
|
end
|
171
176
|
end
|
172
177
|
|
173
|
-
# delete run
|
174
|
-
|
175
|
-
|
178
|
+
# delete run?
|
179
|
+
if delete_run
|
180
|
+
run.delete
|
181
|
+
puts "Run deleted"
|
182
|
+
end
|
@@ -31,11 +31,12 @@
|
|
31
31
|
#
|
32
32
|
# Author: Robert Haines
|
33
33
|
|
34
|
-
require '
|
34
|
+
require 'rubygems'
|
35
|
+
require 't2-server'
|
35
36
|
require 'optparse'
|
36
37
|
|
37
38
|
opts = OptionParser.new do |opt|
|
38
|
-
opt.banner = "Usage:
|
39
|
+
opt.banner = "Usage: t2-server-info [options] server-address"
|
39
40
|
opt.separator ""
|
40
41
|
opt.separator " Where server-address is the full URI of the server to"
|
41
42
|
opt.separator " connect to, e.g.: http://example.com:8080/taverna"
|
data/lib/t2-server.rb
ADDED
@@ -0,0 +1,71 @@
|
|
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 't2-server/xml'
|
34
|
+
require 't2-server/exceptions'
|
35
|
+
require 't2-server/server'
|
36
|
+
require 't2-server/run'
|
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.
|
44
|
+
module T2Server
|
45
|
+
# The version of this library
|
46
|
+
GEM_VERSION = "0.5.0"
|
47
|
+
# The version of the Taverna 2 Server API that this library can interface with
|
48
|
+
API_VERSION = "2.2a1"
|
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
|
@@ -33,11 +33,12 @@
|
|
33
33
|
require 'net/http'
|
34
34
|
|
35
35
|
module T2Server
|
36
|
+
# :stopdoc:
|
36
37
|
# An internal module to collect all the exceptions that we
|
37
38
|
# can't really do anything about ourselves, such as
|
38
39
|
# timeouts and lost connections. This is further wrapped
|
39
40
|
# and exposed in the API as T2Server::ConnectionError below.
|
40
|
-
module InternalHTTPError
|
41
|
+
module InternalHTTPError
|
41
42
|
end
|
42
43
|
|
43
44
|
# These are the HTTP errors we want to catch.
|
@@ -55,6 +56,7 @@ module T2Server
|
|
55
56
|
Net::ProtocolError
|
56
57
|
].each {|err| err.send(:include, InternalHTTPError)}
|
57
58
|
|
59
|
+
# :startdoc:
|
58
60
|
# This is a superclass for all T2Server exceptions. It is provided as a
|
59
61
|
# useful catch-all for all the internally raised/thrown exceptions.
|
60
62
|
class T2ServerError < RuntimeError
|
@@ -30,7 +30,8 @@
|
|
30
30
|
#
|
31
31
|
# Author: Robert Haines
|
32
32
|
|
33
|
-
require '
|
33
|
+
require 'rubygems'
|
34
|
+
require 'libxml'
|
34
35
|
|
35
36
|
module T2Server
|
36
37
|
|
@@ -44,6 +45,8 @@ module T2Server
|
|
44
45
|
# * Finished: The run has finished running and its outputs are available for
|
45
46
|
# download.
|
46
47
|
class Run
|
48
|
+
include LibXML
|
49
|
+
|
47
50
|
private_class_method :new
|
48
51
|
|
49
52
|
# The identifier of this run on the server. It is currently a UUID
|
@@ -134,18 +137,53 @@ module T2Server
|
|
134
137
|
end
|
135
138
|
|
136
139
|
# :call-seq:
|
137
|
-
# run.get_output(output) ->
|
138
|
-
#
|
139
|
-
# Return the
|
140
|
-
#
|
141
|
-
#
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
140
|
+
# run.get_output(output, refs=false) -> list
|
141
|
+
#
|
142
|
+
# Return the values of the workflow output port _output_. These are
|
143
|
+
# returned as a list of strings. If the output port represents a singleton
|
144
|
+
# output then a one item list is returned. By default this method returns
|
145
|
+
# the actual data from the output port but if _refs_ is set to true then
|
146
|
+
# it will instead return URIs to the actual data in the same list format.
|
147
|
+
# See also Run#get_output_refs.
|
148
|
+
def get_output(output, refs=false)
|
146
149
|
output.strip_path!
|
147
|
-
|
148
|
-
|
150
|
+
result = []
|
151
|
+
|
152
|
+
# look at the contents of the output port
|
153
|
+
lists, items = ls("out/#{output}")
|
154
|
+
|
155
|
+
# if lists and items are empty then it's a single value
|
156
|
+
if lists == [] and items == []
|
157
|
+
if refs
|
158
|
+
result << "#{@server.uri}/rest/runs/#{@uuid}/#{@links[:wdir]}/out/#{output}"
|
159
|
+
else
|
160
|
+
result << @server.get_run_attribute(@uuid, "#{@links[:wdir]}/out/#{output}")
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# for each list recurse into it and add the items to the result
|
165
|
+
lists.each {|list| result << get_output("#{output}/#{list}", refs)}
|
166
|
+
|
167
|
+
# for each item, add it to the output list
|
168
|
+
items.each do |item|
|
169
|
+
if refs
|
170
|
+
result << "#{@server.uri}/rest/runs/#{@uuid}/#{@links[:wdir]}/out/#{output}/#{item}"
|
171
|
+
else
|
172
|
+
result << @server.get_run_attribute(@uuid, "#{@links[:wdir]}/out/#{output}/#{item}")
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
result
|
177
|
+
end
|
178
|
+
|
179
|
+
# :call-seq:
|
180
|
+
# run.get_output_refs(output) -> list
|
181
|
+
#
|
182
|
+
# Return references (URIs) to the values of the workflow output port
|
183
|
+
# _output_. These are returned as a list of URIs. If the output port
|
184
|
+
# represents a singleton output then a one item list is returned.
|
185
|
+
def get_output_refs(output)
|
186
|
+
get_output(output, true)
|
149
187
|
end
|
150
188
|
|
151
189
|
# :call-seq:
|
@@ -355,19 +393,37 @@ module T2Server
|
|
355
393
|
# run.ls(dir="") -> [[dirs], [objects]]
|
356
394
|
#
|
357
395
|
# List a directory in the run's workspace on the server. If _dir_ is left
|
358
|
-
# blank then / is listed.
|
359
|
-
#
|
396
|
+
# blank then / is listed. As there is no concept of changing into a
|
397
|
+
# directory (_cd_) in Taverna Server then all paths passed into _ls_
|
398
|
+
# should be full paths starting at "root". The contents of a directory are
|
399
|
+
# returned as a list of two lists, "directories" and "objects"
|
400
|
+
# respectively. In the case of listing the contents of the "out"
|
401
|
+
# directory, the "directories" returned by _ls_ are actually output port
|
402
|
+
# names and their contents are the values held by these ports. If there
|
403
|
+
# are multiple values listed then that port represents a list. If there
|
404
|
+
# are further directories below a port name then it is a list of lists.
|
360
405
|
def ls(dir="")
|
361
406
|
dir.strip_path!
|
362
407
|
dir_list = @server.get_run_attribute(@uuid, "#{@links[:wdir]}/#{dir}")
|
363
|
-
doc = REXML::Document.new(dir_list)
|
364
408
|
|
365
409
|
# compile a list of directory entries stripping the
|
366
410
|
# directory name from the front of each filename
|
367
411
|
dirs = []
|
368
412
|
files = []
|
369
|
-
|
370
|
-
|
413
|
+
|
414
|
+
begin
|
415
|
+
doc = XML::Document.string(dir_list)
|
416
|
+
|
417
|
+
doc.find(XPaths::DIR, Namespaces::MAP).each {|e| dirs << e.content.split('/')[-1]}
|
418
|
+
doc.find(XPaths::FILE, Namespaces::MAP).each {|e| files << e.content.split('/')[-1]}
|
419
|
+
rescue XML::Error => xmle
|
420
|
+
# We expect to get a DOCUMENT_EMPTY error in some cases. All others
|
421
|
+
# should be re-raised.
|
422
|
+
if xmle.code != XML::Error::DOCUMENT_EMPTY
|
423
|
+
raise xmle
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
371
427
|
[dirs, files]
|
372
428
|
end
|
373
429
|
|
@@ -426,9 +482,9 @@ module T2Server
|
|
426
482
|
|
427
483
|
# get inputs
|
428
484
|
inputs = @server.get_run_attribute(@uuid, links[:inputs])
|
429
|
-
doc =
|
485
|
+
doc = XML::Document.string(inputs)
|
430
486
|
nsmap = Namespaces::MAP
|
431
|
-
links[:baclava] = "#{links[:inputs]}/" +
|
487
|
+
links[:baclava] = "#{links[:inputs]}/" + doc.find_first(XPaths::BACLAVA, nsmap).attributes["href"].split('/')[-1]
|
432
488
|
|
433
489
|
# set io properties
|
434
490
|
links[:io] = "#{links[:listeners]}/io"
|
@@ -440,20 +496,20 @@ module T2Server
|
|
440
496
|
end
|
441
497
|
|
442
498
|
def parse_description(desc)
|
443
|
-
doc =
|
499
|
+
doc = XML::Document.string(desc)
|
444
500
|
nsmap = Namespaces::MAP
|
445
501
|
{
|
446
|
-
:expiry =>
|
447
|
-
:workflow =>
|
448
|
-
:status =>
|
449
|
-
:createtime =>
|
450
|
-
:starttime =>
|
451
|
-
:finishtime =>
|
452
|
-
:wdir =>
|
453
|
-
:inputs =>
|
454
|
-
:output =>
|
455
|
-
:securectx =>
|
456
|
-
:listeners =>
|
502
|
+
:expiry => doc.find_first(XPaths::EXPIRY, nsmap).attributes["href"].split('/')[-1],
|
503
|
+
:workflow => doc.find_first(XPaths::WORKFLOW, nsmap).attributes["href"].split('/')[-1],
|
504
|
+
:status => doc.find_first(XPaths::STATUS, nsmap).attributes["href"].split('/')[-1],
|
505
|
+
:createtime => doc.find_first(XPaths::CREATETIME, nsmap).attributes["href"].split('/')[-1],
|
506
|
+
:starttime => doc.find_first(XPaths::STARTTIME, nsmap).attributes["href"].split('/')[-1],
|
507
|
+
:finishtime => doc.find_first(XPaths::FINISHTIME, nsmap).attributes["href"].split('/')[-1],
|
508
|
+
:wdir => doc.find_first(XPaths::WDIR, nsmap).attributes["href"].split('/')[-1],
|
509
|
+
:inputs => doc.find_first(XPaths::INPUTS, nsmap).attributes["href"].split('/')[-1],
|
510
|
+
:output => doc.find_first(XPaths::OUTPUT, nsmap).attributes["href"].split('/')[-1],
|
511
|
+
:securectx => doc.find_first(XPaths::SECURECTX, nsmap).attributes["href"].split('/')[-1],
|
512
|
+
:listeners => doc.find_first(XPaths::LISTENERS, nsmap).attributes["href"].split('/')[-1]
|
457
513
|
}
|
458
514
|
end
|
459
515
|
end
|
@@ -30,16 +30,19 @@
|
|
30
30
|
#
|
31
31
|
# Author: Robert Haines
|
32
32
|
|
33
|
+
require 'rubygems'
|
33
34
|
require 'base64'
|
34
35
|
require 'uri'
|
35
36
|
require 'net/https'
|
36
|
-
require '
|
37
|
+
require 'libxml'
|
37
38
|
|
38
39
|
module T2Server
|
39
40
|
|
40
41
|
# An interface for directly communicating with one or more Taverna 2 Server
|
41
42
|
# instances.
|
42
43
|
class Server
|
44
|
+
include LibXML
|
45
|
+
|
43
46
|
private_class_method :new
|
44
47
|
|
45
48
|
# The URI of this server instance as a String.
|
@@ -174,11 +177,17 @@ module T2Server
|
|
174
177
|
end
|
175
178
|
|
176
179
|
# :call-seq:
|
177
|
-
# server.delete_run(
|
180
|
+
# server.delete_run(run) -> bool
|
178
181
|
#
|
179
182
|
# Delete the specified run from the server, discarding all of its state.
|
180
|
-
|
181
|
-
|
183
|
+
# _run_ can be either a Run instance or a UUID.
|
184
|
+
def delete_run(run)
|
185
|
+
# get the uuid from the run if that is what is passed in
|
186
|
+
if run.instance_of? Run
|
187
|
+
run = run.uuid
|
188
|
+
end
|
189
|
+
|
190
|
+
request = Net::HTTP::Delete.new("#{@links[:runs]}/#{run}")
|
182
191
|
if ssl?
|
183
192
|
request.basic_auth @username, @password
|
184
193
|
end
|
@@ -191,12 +200,12 @@ module T2Server
|
|
191
200
|
case response
|
192
201
|
when Net::HTTPNoContent
|
193
202
|
# Success, carry on...
|
194
|
-
@runs.delete(
|
203
|
+
@runs.delete(run)
|
195
204
|
true
|
196
205
|
when Net::HTTPNotFound
|
197
|
-
raise RunNotFoundError.new(
|
206
|
+
raise RunNotFoundError.new(run)
|
198
207
|
when Net::HTTPForbidden
|
199
|
-
raise AccessForbiddenError.new("run #{
|
208
|
+
raise AccessForbiddenError.new("run #{run}")
|
200
209
|
when Net::HTTPUnauthorized
|
201
210
|
raise AuthorizationError.new(@username)
|
202
211
|
else
|
@@ -216,15 +225,21 @@ module T2Server
|
|
216
225
|
# :call-seq:
|
217
226
|
# server.set_run_input(run, input, value) -> bool
|
218
227
|
#
|
219
|
-
# Set the workflow input port _input_ on run _run_ to _value_.
|
228
|
+
# Set the workflow input port _input_ on run _run_ to _value_. _run_ can
|
229
|
+
# be either a Run instance or a UUID.
|
220
230
|
def set_run_input(run, input, value)
|
221
|
-
|
231
|
+
# get the run from the uuid if that is what is passed in
|
232
|
+
if not run.instance_of? Run
|
233
|
+
run = run(run)
|
234
|
+
end
|
235
|
+
|
236
|
+
path = "#{@links[:runs]}/#{run.run}/#{run.inputs}/input/#{input}"
|
222
237
|
set_attribute(path, Fragments::RUNINPUTVALUE % value, "application/xml")
|
223
238
|
rescue AttributeNotFoundError => e
|
224
|
-
if get_runs.has_key? uuid
|
239
|
+
if get_runs.has_key? run.uuid
|
225
240
|
raise e
|
226
241
|
else
|
227
|
-
raise RunNotFoundError.new(uuid)
|
242
|
+
raise RunNotFoundError.new(run.uuid)
|
228
243
|
end
|
229
244
|
end
|
230
245
|
|
@@ -232,26 +247,36 @@ module T2Server
|
|
232
247
|
# server.set_run_input_file(run, input, filename) -> bool
|
233
248
|
#
|
234
249
|
# Set the workflow input port _input_ on run _run_ to use the file at
|
235
|
-
# _filename_ for its input.
|
250
|
+
# _filename_ for its input. _run_ can be either a Run instance or a UUID.
|
236
251
|
def set_run_input_file(run, input, filename)
|
252
|
+
# get the run from the uuid if that is what is passed in
|
253
|
+
if not run.instance_of? Run
|
254
|
+
run = run(run)
|
255
|
+
end
|
256
|
+
|
237
257
|
path = "#{@links[:runs]}/#{run.uuid}/#{run.inputs}/input/#{input}"
|
238
258
|
set_attribute(path, Fragments::RUNINPUTFILE % filename, "application/xml")
|
239
259
|
rescue AttributeNotFoundError => e
|
240
|
-
if get_runs.has_key? uuid
|
260
|
+
if get_runs.has_key? run.uuid
|
241
261
|
raise e
|
242
262
|
else
|
243
|
-
raise RunNotFoundError.new(uuid)
|
263
|
+
raise RunNotFoundError.new(run.uuid)
|
244
264
|
end
|
245
265
|
end
|
246
266
|
|
247
267
|
# :call-seq:
|
248
|
-
# server.make_run_dir(
|
268
|
+
# server.make_run_dir(run, root, dir) -> bool
|
249
269
|
#
|
250
|
-
# Create a directory _dir_ within the directory _root_ on
|
251
|
-
#
|
252
|
-
def make_run_dir(
|
270
|
+
# Create a directory _dir_ within the directory _root_ on _run_. _run_ can
|
271
|
+
# be either a Run instance or a UUID. This is mainly for use by Run#mkdir.
|
272
|
+
def make_run_dir(run, root, dir)
|
273
|
+
# get the uuid from the run if that is what is passed in
|
274
|
+
if run.instance_of? Run
|
275
|
+
run = run.uuid
|
276
|
+
end
|
277
|
+
|
253
278
|
raise AccessForbiddenError.new("subdirectories (#{dir})") if dir.include? ?/
|
254
|
-
request = Net::HTTP::Post.new("#{@links[:runs]}/#{
|
279
|
+
request = Net::HTTP::Post.new("#{@links[:runs]}/#{run}/#{root}")
|
255
280
|
request.content_type = "application/xml"
|
256
281
|
if ssl?
|
257
282
|
request.basic_auth @username, @password
|
@@ -267,9 +292,9 @@ module T2Server
|
|
267
292
|
# OK, carry on...
|
268
293
|
true
|
269
294
|
when Net::HTTPNotFound
|
270
|
-
raise RunNotFoundError.new(
|
295
|
+
raise RunNotFoundError.new(run)
|
271
296
|
when Net::HTTPForbidden
|
272
|
-
raise AccessForbiddenError.new("#{dir} on run #{
|
297
|
+
raise AccessForbiddenError.new("#{dir} on run #{run}")
|
273
298
|
when Net::HTTPUnauthorized
|
274
299
|
raise AuthorizationError.new(@username)
|
275
300
|
else
|
@@ -278,14 +303,19 @@ module T2Server
|
|
278
303
|
end
|
279
304
|
|
280
305
|
# :call-seq:
|
281
|
-
# server.upload_run_file(
|
306
|
+
# server.upload_run_file(run, filename, location, rename) -> string
|
282
307
|
#
|
283
|
-
# Upload a file to
|
284
|
-
# by Run#upload_file.
|
285
|
-
def upload_run_file(
|
308
|
+
# Upload a file to _run_. _run_ can be either a Run instance or a UUID.
|
309
|
+
# Mainly for internal use by Run#upload_file.
|
310
|
+
def upload_run_file(run, filename, location, rename)
|
311
|
+
# get the uuid from the run if that is what is passed in
|
312
|
+
if run.instance_of? Run
|
313
|
+
run = run.uuid
|
314
|
+
end
|
315
|
+
|
286
316
|
contents = Base64.encode64(IO.read(filename))
|
287
317
|
rename = filename.split('/')[-1] if rename == ""
|
288
|
-
request = Net::HTTP::Post.new("#{@links[:runs]}/#{
|
318
|
+
request = Net::HTTP::Post.new("#{@links[:runs]}/#{run}/#{location}")
|
289
319
|
request.content_type = "application/xml"
|
290
320
|
if ssl?
|
291
321
|
request.basic_auth @username, @password
|
@@ -301,9 +331,9 @@ module T2Server
|
|
301
331
|
# Success, return remote name of uploaded file
|
302
332
|
rename
|
303
333
|
when Net::HTTPNotFound
|
304
|
-
raise RunNotFoundError.new(
|
334
|
+
raise RunNotFoundError.new(run)
|
305
335
|
when Net::HTTPForbidden
|
306
|
-
raise AccessForbiddenError.new("run #{
|
336
|
+
raise AccessForbiddenError.new("run #{run}")
|
307
337
|
when Net::HTTPUnauthorized
|
308
338
|
raise AuthorizationError.new(@username)
|
309
339
|
else
|
@@ -312,30 +342,42 @@ module T2Server
|
|
312
342
|
end
|
313
343
|
|
314
344
|
# :call-seq:
|
315
|
-
# server.get_run_attribute(
|
345
|
+
# server.get_run_attribute(run, path) -> string
|
316
346
|
#
|
317
|
-
# Get the attribute at _path_ in
|
318
|
-
|
319
|
-
|
347
|
+
# Get the attribute at _path_ in _run_. _run_ can be either a Run instance
|
348
|
+
# or a UUID.
|
349
|
+
def get_run_attribute(run, path)
|
350
|
+
# get the uuid from the run if that is what is passed in
|
351
|
+
if run.instance_of? Run
|
352
|
+
run = run.uuid
|
353
|
+
end
|
354
|
+
|
355
|
+
get_attribute("#{@links[:runs]}/#{run}/#{path}")
|
320
356
|
rescue AttributeNotFoundError => e
|
321
|
-
if get_runs.has_key?
|
357
|
+
if get_runs.has_key? run
|
322
358
|
raise e
|
323
359
|
else
|
324
|
-
raise RunNotFoundError.new(
|
360
|
+
raise RunNotFoundError.new(run)
|
325
361
|
end
|
326
362
|
end
|
327
363
|
|
328
364
|
# :call-seq:
|
329
|
-
# server.set_run_attribute(
|
365
|
+
# server.set_run_attribute(run, path, value) -> bool
|
330
366
|
#
|
331
|
-
# Set the attribute at _path_ in
|
332
|
-
|
333
|
-
|
367
|
+
# Set the attribute at _path_ in _run_ to _value_. _run_ can be either a
|
368
|
+
# Run instance or a UUID.
|
369
|
+
def set_run_attribute(run, path, value)
|
370
|
+
# get the uuid from the run if that is what is passed in
|
371
|
+
if run.instance_of? Run
|
372
|
+
run = run.uuid
|
373
|
+
end
|
374
|
+
|
375
|
+
set_attribute("#{@links[:runs]}/#{run}/#{path}", value, "text/plain")
|
334
376
|
rescue AttributeNotFoundError => e
|
335
|
-
if get_runs.has_key?
|
377
|
+
if get_runs.has_key? run
|
336
378
|
raise e
|
337
379
|
else
|
338
|
-
raise RunNotFoundError.new(
|
380
|
+
raise RunNotFoundError.new(run)
|
339
381
|
end
|
340
382
|
end
|
341
383
|
|
@@ -393,24 +435,24 @@ module T2Server
|
|
393
435
|
end
|
394
436
|
|
395
437
|
def parse_description(desc)
|
396
|
-
doc =
|
438
|
+
doc = XML::Document.string(desc)
|
397
439
|
nsmap = Namespaces::MAP
|
398
440
|
{
|
399
|
-
:runs => URI.parse(
|
400
|
-
:runlimit => URI.parse(
|
401
|
-
:permworkflows => URI.parse(
|
402
|
-
:permlisteners => URI.parse(
|
441
|
+
:runs => URI.parse(doc.find_first(XPaths::RUNS, nsmap).attributes["href"]).path,
|
442
|
+
:runlimit => URI.parse(doc.find_first(XPaths::RUNLIMIT, nsmap).attributes["href"]).path,
|
443
|
+
:permworkflows => URI.parse(doc.find_first(XPaths::PERMWKF, nsmap).attributes["href"]).path,
|
444
|
+
:permlisteners => URI.parse(doc.find_first(XPaths::PERMLSTN, nsmap).attributes["href"]).path
|
403
445
|
}
|
404
446
|
end
|
405
447
|
|
406
448
|
def get_runs
|
407
449
|
run_list = get_attribute("#{@links[:runs]}")
|
408
450
|
|
409
|
-
doc =
|
451
|
+
doc = XML::Document.string(run_list)
|
410
452
|
|
411
453
|
# get list of run uuids
|
412
454
|
uuids = []
|
413
|
-
|
455
|
+
doc.find(XPaths::RUN, Namespaces::MAP).each do |run|
|
414
456
|
uuids << run.attributes["href"].split('/')[-1]
|
415
457
|
end
|
416
458
|
|
@@ -30,7 +30,11 @@
|
|
30
30
|
#
|
31
31
|
# Author: Robert Haines
|
32
32
|
|
33
|
+
require 'rubygems'
|
34
|
+
require 'libxml'
|
35
|
+
|
33
36
|
module T2Server
|
37
|
+
# :stopdoc:
|
34
38
|
module Namespaces
|
35
39
|
SERVER = "http://ns.taverna.org.uk/2010/xml/server/"
|
36
40
|
REST = SERVER + "rest/"
|
@@ -39,7 +43,7 @@ module T2Server
|
|
39
43
|
"nsr" => Namespaces::REST
|
40
44
|
}
|
41
45
|
end
|
42
|
-
|
46
|
+
|
43
47
|
module Fragments
|
44
48
|
WORKFLOW = "<t2s:workflow xmlns:t2s=\"#{Namespaces::SERVER}\">\n %s\n</t2s:workflow>"
|
45
49
|
RUNINPUT = "<t2sr:runInput xmlns:t2sr=\"#{Namespaces::REST}\">\n %s\n</t2sr:runInput>"
|
@@ -48,4 +52,35 @@ module T2Server
|
|
48
52
|
UPLOAD = "<t2sr:upload xmlns:t2sr=\"#{Namespaces::REST}\" t2sr:name=\"%s\">\n %s\n</t2sr:upload>"
|
49
53
|
MKDIR = "<t2sr:mkdir xmlns:t2sr=\"#{Namespaces::REST}\" t2sr:name=\"%s\" />"
|
50
54
|
end
|
55
|
+
|
56
|
+
module XPaths
|
57
|
+
include LibXML
|
58
|
+
|
59
|
+
# Shut the libxml error handler up
|
60
|
+
XML::Error.set_handler(&XML::Error::QUIET_HANDLER)
|
61
|
+
|
62
|
+
# Server XPath queries
|
63
|
+
RUN = XML::XPath::Expression.new("//nsr:run")
|
64
|
+
RUNS = XML::XPath::Expression.new("//nsr:runs")
|
65
|
+
RUNLIMIT = XML::XPath::Expression.new("//nsr:runLimit")
|
66
|
+
PERMWKF = XML::XPath::Expression.new("//nsr:permittedWorkflows")
|
67
|
+
PERMLSTN = XML::XPath::Expression.new("//nsr:permittedListeners")
|
68
|
+
|
69
|
+
# Run XPath queries
|
70
|
+
DIR = XML::XPath::Expression.new("//nss:dir")
|
71
|
+
FILE = XML::XPath::Expression.new("//nss:file")
|
72
|
+
EXPIRY = XML::XPath::Expression.new("//nsr:expiry")
|
73
|
+
WORKFLOW = XML::XPath::Expression.new("//nsr:creationWorkflow")
|
74
|
+
STATUS = XML::XPath::Expression.new("//nsr:status")
|
75
|
+
CREATETIME = XML::XPath::Expression.new("//nsr:createTime")
|
76
|
+
STARTTIME = XML::XPath::Expression.new("//nsr:startTime")
|
77
|
+
FINISHTIME = XML::XPath::Expression.new("//nsr:finishTime")
|
78
|
+
WDIR = XML::XPath::Expression.new("//nsr:workingDirectory")
|
79
|
+
INPUTS = XML::XPath::Expression.new("//nsr:inputs")
|
80
|
+
OUTPUT = XML::XPath::Expression.new("//nsr:output")
|
81
|
+
SECURECTX = XML::XPath::Expression.new("//nsr:securityContext")
|
82
|
+
LISTENERS = XML::XPath::Expression.new("//nsr:listeners")
|
83
|
+
BACLAVA = XML::XPath::Expression.new("//nsr:baclava")
|
84
|
+
end
|
85
|
+
# :startdoc:
|
51
86
|
end
|
data/lib/t2server.rb
CHANGED
@@ -30,42 +30,6 @@
|
|
30
30
|
#
|
31
31
|
# Author: Robert Haines
|
32
32
|
|
33
|
-
|
34
|
-
require
|
35
|
-
require '
|
36
|
-
require 't2server/run'
|
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.
|
44
|
-
module T2Server
|
45
|
-
# The version of this library
|
46
|
-
GEM_VERSION = "0.2.1"
|
47
|
-
# The version of the Taverna 2 Server API that this library can interface with
|
48
|
-
API_VERSION = "2.2a1"
|
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
|
33
|
+
# This is simply here to provide backwards compatibility. Old versions had an
|
34
|
+
# inconsistancy between the gem name and the file to require to use it.
|
35
|
+
require 't2-server'
|
data/test/tc_paths.rb
CHANGED
data/test/tc_run.rb
CHANGED
@@ -30,7 +30,7 @@
|
|
30
30
|
#
|
31
31
|
# Author: Robert Haines
|
32
32
|
|
33
|
-
require '
|
33
|
+
require 't2-server'
|
34
34
|
|
35
35
|
class TestRun < Test::Unit::TestCase
|
36
36
|
|
@@ -41,9 +41,6 @@ class TestRun < Test::Unit::TestCase
|
|
41
41
|
end
|
42
42
|
|
43
43
|
# test bad state code
|
44
|
-
assert_raise(T2Server::RunStateError) do
|
45
|
-
@run.get_output("out")
|
46
|
-
end
|
47
44
|
assert_raise(T2Server::RunStateError) do
|
48
45
|
@run.wait
|
49
46
|
end
|
@@ -61,7 +58,7 @@ class TestRun < Test::Unit::TestCase
|
|
61
58
|
|
62
59
|
# exitcode and output
|
63
60
|
assert_instance_of(Fixnum, @run.exitcode)
|
64
|
-
assert_equal(@run.get_output("Message"), "Hello, World!")
|
61
|
+
assert_equal(@run.get_output("Message"), ["Hello, World!"])
|
65
62
|
assert_raise(T2Server::AccessForbiddenError) do
|
66
63
|
@run.get_output("wrong!")
|
67
64
|
end
|
data/test/tc_server.rb
CHANGED
data/test/ts_t2server.rb
CHANGED
@@ -31,10 +31,13 @@
|
|
31
31
|
# Author: Robert Haines
|
32
32
|
|
33
33
|
require 'test/unit'
|
34
|
-
require '
|
34
|
+
require 't2-server'
|
35
35
|
|
36
36
|
# get a server address to test - 30 second timeout
|
37
|
-
print "\nPlease supply a valid Taverna 2 Server address
|
37
|
+
print "\nPlease supply a valid Taverna 2 Server address.\n\nNOTE that these " +
|
38
|
+
"tests will fully load the server and then delete all the runs that it " +
|
39
|
+
"has permission to do so - if you are not using security ALL runs will be " +
|
40
|
+
"deleted!\n(leave blank to skip tests): "
|
38
41
|
$stdout.flush
|
39
42
|
if select([$stdin], [], [], 30)
|
40
43
|
$address = $stdin.gets.chomp
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: t2-server
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 11
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 5
|
9
|
+
- 0
|
10
|
+
version: 0.5.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Robert Haines
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-10-22 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -34,24 +34,43 @@ dependencies:
|
|
34
34
|
version: 0.8.7
|
35
35
|
type: :development
|
36
36
|
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: libxml-ruby
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 27
|
46
|
+
segments:
|
47
|
+
- 1
|
48
|
+
- 1
|
49
|
+
- 4
|
50
|
+
version: 1.1.4
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
37
53
|
description: This gem provides access to the Taverna 2 Server REST interface from Ruby.
|
38
54
|
email: rhaines@manchester.ac.uk
|
39
|
-
executables:
|
40
|
-
|
55
|
+
executables:
|
56
|
+
- t2-delete-runs
|
57
|
+
- t2-run-workflow
|
58
|
+
- t2-server-info
|
41
59
|
extensions: []
|
42
60
|
|
43
61
|
extra_rdoc_files:
|
44
62
|
- README.rdoc
|
45
63
|
- LICENCE
|
46
64
|
files:
|
47
|
-
- bin/
|
48
|
-
- bin/
|
49
|
-
- bin/
|
65
|
+
- bin/t2-server-info
|
66
|
+
- bin/t2-delete-runs
|
67
|
+
- bin/t2-run-workflow
|
50
68
|
- lib/t2server.rb
|
51
|
-
- lib/
|
52
|
-
- lib/
|
53
|
-
- lib/
|
54
|
-
- lib/
|
69
|
+
- lib/t2-server/server.rb
|
70
|
+
- lib/t2-server/exceptions.rb
|
71
|
+
- lib/t2-server/xml.rb
|
72
|
+
- lib/t2-server/run.rb
|
73
|
+
- lib/t2-server.rb
|
55
74
|
- test/tc_server.rb
|
56
75
|
- test/tc_paths.rb
|
57
76
|
- test/tc_run.rb
|
@@ -64,8 +83,10 @@ homepage: http://www.taverna.org.uk/
|
|
64
83
|
licenses: []
|
65
84
|
|
66
85
|
post_install_message:
|
67
|
-
rdoc_options:
|
68
|
-
|
86
|
+
rdoc_options:
|
87
|
+
- -N
|
88
|
+
- --tab-width=2
|
89
|
+
- --main=README.rdoc
|
69
90
|
require_paths:
|
70
91
|
- lib
|
71
92
|
required_ruby_version: !ruby/object:Gem::Requirement
|