rbbt-util 5.1.0 → 5.2.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/LICENSE +1 -1
- data/README.rdoc +2 -2
- data/bin/rbbt +45 -0
- data/bin/rbbt_dangling_locks.rb +9 -0
- data/bin/rbbt_monitor.rb +12 -10
- data/bin/run_workflow.rb +80 -18
- data/lib/rbbt.rb +1 -1
- data/lib/rbbt/annotations.rb +1 -19
- data/lib/rbbt/annotations/annotated_array.rb +23 -0
- data/lib/rbbt/fix_width_table.rb +2 -2
- data/lib/rbbt/persist.rb +13 -5
- data/lib/rbbt/persist/tsv.rb +2 -0
- data/lib/rbbt/resource.rb +4 -4
- data/lib/rbbt/resource/path.rb +35 -10
- data/lib/rbbt/resource/util.rb +54 -47
- data/lib/rbbt/tsv.rb +17 -15
- data/lib/rbbt/tsv/accessor.rb +35 -37
- data/lib/rbbt/tsv/excel.rb +3 -1
- data/lib/rbbt/tsv/manipulate.rb +27 -4
- data/lib/rbbt/tsv/parser.rb +13 -7
- data/lib/rbbt/util/R.rb +11 -1
- data/lib/rbbt/util/misc.rb +182 -26
- data/lib/rbbt/util/named_array.rb +14 -7
- data/lib/rbbt/util/open.rb +2 -1
- data/lib/rbbt/util/tmpfile.rb +16 -1
- data/lib/rbbt/workflow.rb +63 -101
- data/lib/rbbt/workflow/accessor.rb +19 -9
- data/lib/rbbt/workflow/annotate.rb +33 -64
- data/lib/rbbt/workflow/definition.rb +71 -0
- data/lib/rbbt/workflow/soap.rb +15 -5
- data/lib/rbbt/workflow/step.rb +57 -8
- data/lib/rbbt/workflow/usage.rb +72 -0
- data/share/lib/R/util.R +12 -0
- data/share/rbbt_commands/conf/web_user/add +26 -0
- data/share/rbbt_commands/conf/web_user/list +9 -0
- data/share/rbbt_commands/conf/web_user/remove +18 -0
- data/share/rbbt_commands/workflow/remote/add +11 -0
- data/share/rbbt_commands/workflow/remote/list +9 -0
- data/share/rbbt_commands/workflow/remote/remove +9 -0
- data/share/rbbt_commands/workflow/task +181 -0
- data/test/rbbt/test_resource.rb +2 -1
- data/test/rbbt/test_workflow.rb +13 -0
- data/test/rbbt/tsv/test_manipulate.rb +18 -0
- data/test/rbbt/util/test_misc.rb +19 -39
- data/test/rbbt/util/test_tmpfile.rb +8 -0
- data/test/rbbt/workflow/test_soap.rb +2 -0
- metadata +31 -2
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'rbbt-util'
|
2
|
+
require 'rbbt/workflow/annotate'
|
3
|
+
|
4
|
+
module Workflow
|
5
|
+
include AnnotatedModule
|
6
|
+
|
7
|
+
|
8
|
+
AnnotatedModule.add_consummable_annotation(self,
|
9
|
+
:result_description => "",
|
10
|
+
:result_type => nil,
|
11
|
+
:dependencies => [])
|
12
|
+
def helper(name, &block)
|
13
|
+
helpers[name] = block
|
14
|
+
end
|
15
|
+
|
16
|
+
def desc(description)
|
17
|
+
@description = description
|
18
|
+
end
|
19
|
+
|
20
|
+
def returns(description)
|
21
|
+
@result_description = description
|
22
|
+
end
|
23
|
+
|
24
|
+
def dep(*dependency_list, &block)
|
25
|
+
dependency_list << block if block_given?
|
26
|
+
dependencies.concat dependency_list
|
27
|
+
end
|
28
|
+
|
29
|
+
def task(name, &block)
|
30
|
+
if Hash === name
|
31
|
+
type = name.first.last
|
32
|
+
name = name.first.first
|
33
|
+
else
|
34
|
+
result_type = consume_result_type || :marshal
|
35
|
+
end
|
36
|
+
|
37
|
+
name = name.to_sym
|
38
|
+
|
39
|
+
block = self.method(name) unless block_given?
|
40
|
+
|
41
|
+
task_info = {
|
42
|
+
:name => name,
|
43
|
+
:inputs => consume_inputs,
|
44
|
+
:description => consume_description,
|
45
|
+
:input_types => consume_input_types,
|
46
|
+
:result_type => (Array === type ? type.to_sym : type),
|
47
|
+
:input_defaults => consume_input_defaults,
|
48
|
+
:input_descriptions => consume_input_descriptions,
|
49
|
+
:input_options => consume_input_options
|
50
|
+
}
|
51
|
+
|
52
|
+
task = Task.setup(task_info, &block)
|
53
|
+
|
54
|
+
last_task = task
|
55
|
+
|
56
|
+
tasks[name] = task
|
57
|
+
task_dependencies[name] = consume_dependencies
|
58
|
+
end
|
59
|
+
|
60
|
+
def export_exec(*names)
|
61
|
+
exec_exports.concat names
|
62
|
+
end
|
63
|
+
|
64
|
+
def export_asynchronous(*names)
|
65
|
+
asynchronous_exports.concat names
|
66
|
+
end
|
67
|
+
|
68
|
+
def export_synchronous(*names)
|
69
|
+
synchronous_exports.concat names
|
70
|
+
end
|
71
|
+
end
|
data/lib/rbbt/workflow/soap.rb
CHANGED
@@ -15,7 +15,7 @@ class WorkflowSOAP < SimpleWS
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def initialize(workflow, *args)
|
18
|
-
super(workflow.to_s
|
18
|
+
super(workflow.to_s, *args)
|
19
19
|
@workflow = workflow
|
20
20
|
@workflow.synchronous_exports.each do |name| synchronous name end
|
21
21
|
@workflow.asynchronous_exports.each do |name| asynchronous name end
|
@@ -38,6 +38,12 @@ class WorkflowSOAP < SimpleWS
|
|
38
38
|
job(jobid).info.to_yaml
|
39
39
|
end
|
40
40
|
|
41
|
+
desc "Job management: Load job result as string "
|
42
|
+
param_desc :jobid => "Job identifier", :return => "String containing the result of the job"
|
43
|
+
serve :load_string, %w(jobid), :jobid => :string, :return => :string do |jobid|
|
44
|
+
Open.read(job(jobid).path)
|
45
|
+
end
|
46
|
+
|
41
47
|
desc "Job management: Abort the job"
|
42
48
|
param_desc :jobid => "Job identifier"
|
43
49
|
serve :abort, %w(jobid), :jobid => :string, :return => false do |jobid|
|
@@ -56,15 +62,19 @@ class WorkflowSOAP < SimpleWS
|
|
56
62
|
job(jobid).status.to_sym == :error
|
57
63
|
end
|
58
64
|
|
59
|
-
desc "Job management:
|
60
|
-
param_desc :jobid => "Job identifier", :return => "
|
61
|
-
serve :
|
62
|
-
job(jobid).
|
65
|
+
desc "Job management: Check if the job has finished with error. The last message is the error message"
|
66
|
+
param_desc :jobid => "Job identifier", :return => "True if the job has status 'error'"
|
67
|
+
serve :clean, %w(jobid), :jobid => :string, :return => nil do |jobid|
|
68
|
+
job(jobid).clean
|
69
|
+
nil
|
63
70
|
end
|
71
|
+
|
72
|
+
|
64
73
|
end
|
65
74
|
|
66
75
|
def synchronous(*tasknames)
|
67
76
|
tasknames.each do |name|
|
77
|
+
name = name.to_sym
|
68
78
|
task = @workflow.tasks[name]
|
69
79
|
desc @workflow.task_description[name] if @workflow.task_description.include? name
|
70
80
|
|
data/lib/rbbt/workflow/step.rb
CHANGED
@@ -10,7 +10,7 @@ class Step
|
|
10
10
|
class Aborted < Exception; end
|
11
11
|
|
12
12
|
def initialize(path, task = nil, inputs = nil, dependencies = nil, bindings = nil)
|
13
|
-
@path = path
|
13
|
+
@path = Path.setup(path)
|
14
14
|
@task = task
|
15
15
|
@bindings = bindings
|
16
16
|
@dependencies = case
|
@@ -84,15 +84,17 @@ class Step
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def run(no_load = false)
|
87
|
-
result = Persist.persist "Job", @task.result_type, :file => @path, :check => rec_dependencies.collect{|dependency| dependency.path}.uniq, :no_load => no_load do
|
87
|
+
result = Persist.persist "Job", @task.result_type, :file => @path, :check => rec_dependencies.collect{|dependency| dependency.path }.uniq, :no_load => no_load do
|
88
88
|
if Step === Step.log_relay_step and not self == Step.log_relay_step
|
89
89
|
relay_log(Step.log_relay_step) unless self.respond_to? :relay_step and self.relay_step
|
90
90
|
end
|
91
91
|
|
92
92
|
FileUtils.rm info_file if File.exists? info_file
|
93
93
|
|
94
|
-
set_info :
|
95
|
-
|
94
|
+
set_info :pid, Process.pid
|
95
|
+
|
96
|
+
set_info :dependencies, dependencies.collect{|dep| [dep.task.name, dep.name]}
|
97
|
+
dependencies.each{|dependency|
|
96
98
|
begin
|
97
99
|
dependency.relay_log self
|
98
100
|
dependency.run true
|
@@ -106,7 +108,7 @@ class Step
|
|
106
108
|
end
|
107
109
|
}
|
108
110
|
|
109
|
-
log(:started, "Starting task #{task.name || ""}")
|
111
|
+
log(:started, "Starting task #{task.name || ""} [#{Process.pid}]")
|
110
112
|
|
111
113
|
set_info :started, Time.now
|
112
114
|
|
@@ -116,6 +118,20 @@ class Step
|
|
116
118
|
exec
|
117
119
|
rescue Step::Aborted
|
118
120
|
log(:error, "Aborted")
|
121
|
+
|
122
|
+
children_pids = info[:children_pids]
|
123
|
+
if children_pids and children_pids.any?
|
124
|
+
Log.medium("Killing children: #{ children_pids * ", " }")
|
125
|
+
children_pids.each do |pid|
|
126
|
+
Log.medium("Killing child #{ pid }")
|
127
|
+
begin
|
128
|
+
Process.kill "INT", pid
|
129
|
+
rescue Exception
|
130
|
+
Log.medium("Exception killing child #{ pid }: #{$!.message}")
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
119
135
|
raise $!
|
120
136
|
rescue Exception
|
121
137
|
backtrace = $!.backtrace
|
@@ -148,11 +164,25 @@ class Step
|
|
148
164
|
FileUtils.mkdir_p File.dirname(path) unless File.exists? File.dirname(path)
|
149
165
|
begin
|
150
166
|
run
|
151
|
-
|
167
|
+
children_pids = info[:children_pids]
|
168
|
+
if children_pids
|
169
|
+
children_pids.each do |pid|
|
170
|
+
if Misc.pid_exists? pid
|
171
|
+
begin
|
172
|
+
Process.waitpid pid
|
173
|
+
rescue Errno::ECHILD
|
174
|
+
Log.error "Waiting on #{ pid } failed: #{$!.message}"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
rescue Exception
|
180
|
+
Log.debug("Exception caught on forked process: #{$!.message}")
|
152
181
|
exit -1
|
153
182
|
end
|
183
|
+
set_info :pid, nil
|
184
|
+
exit 0
|
154
185
|
end
|
155
|
-
set_info :pid, @pid
|
156
186
|
Process.detach(@pid)
|
157
187
|
self
|
158
188
|
end
|
@@ -164,12 +194,30 @@ class Step
|
|
164
194
|
false
|
165
195
|
else
|
166
196
|
Log.medium "Aborting #{path}: #{ @pid }"
|
167
|
-
|
197
|
+
begin
|
198
|
+
Process.kill("INT", @pid)
|
199
|
+
Process.waitpid @pid
|
200
|
+
rescue Exception
|
201
|
+
Log.debug("Aborted job #{@pid} was not killed: #{$!.message}")
|
202
|
+
end
|
168
203
|
log(:aborted, "Job aborted by user")
|
169
204
|
true
|
170
205
|
end
|
171
206
|
end
|
172
207
|
|
208
|
+
def child(&block)
|
209
|
+
child_pid = Process.fork &block
|
210
|
+
children_pids = info[:children_pids]
|
211
|
+
if children_pids.nil?
|
212
|
+
children_pids = [child_pid]
|
213
|
+
else
|
214
|
+
children_pids << child_pid
|
215
|
+
end
|
216
|
+
#Process.detach(child_pid)
|
217
|
+
set_info :children_pids, children_pids
|
218
|
+
child_pid
|
219
|
+
end
|
220
|
+
|
173
221
|
def load
|
174
222
|
raise "Can not load: Step is waiting for proces #{@pid} to finish" if not done?
|
175
223
|
result = Persist.persist "Job", @task.result_type, :file => @path, :check => rec_dependencies.collect{|dependency| dependency.path} do
|
@@ -182,6 +230,7 @@ class Step
|
|
182
230
|
if File.exists?(path) or File.exists?(info_file)
|
183
231
|
begin
|
184
232
|
FileUtils.rm info_file if File.exists? info_file
|
233
|
+
FileUtils.rm info_file + '.lock' if File.exists? info_file + '.lock'
|
185
234
|
FileUtils.rm path if File.exists? path
|
186
235
|
FileUtils.rm path + '.lock' if File.exists? path + '.lock'
|
187
236
|
FileUtils.rm_rf files_dir if File.exists? files_dir
|
@@ -0,0 +1,72 @@
|
|
1
|
+
|
2
|
+
module Task
|
3
|
+
def doc(deps = nil)
|
4
|
+
|
5
|
+
puts "## #{ name }:"
|
6
|
+
puts "\n" << description if description and not description.empty?
|
7
|
+
puts
|
8
|
+
|
9
|
+
inputs.each do |name|
|
10
|
+
short = name.to_s.chars.first
|
11
|
+
|
12
|
+
description = input_descriptions[name]
|
13
|
+
default = input_defaults[name]
|
14
|
+
type = input_types[name]
|
15
|
+
|
16
|
+
puts " * -#{short}, --#{name}=<#{ type }>#{default ? " (default: #{default})" : ""}:"
|
17
|
+
puts " " << description if description and not description.empty?
|
18
|
+
puts
|
19
|
+
end
|
20
|
+
|
21
|
+
if deps and deps.any?
|
22
|
+
puts
|
23
|
+
puts "From dependencies:"
|
24
|
+
puts
|
25
|
+
deps.each do |dep|
|
26
|
+
puts " #{dep.name}:"
|
27
|
+
puts
|
28
|
+
dep.inputs.each do |name|
|
29
|
+
short = name.to_s.chars.first
|
30
|
+
|
31
|
+
description = dep.input_descriptions[name]
|
32
|
+
default = dep.input_defaults[name]
|
33
|
+
type = dep.input_types[name]
|
34
|
+
|
35
|
+
puts " * -#{short}, --#{name}=<#{ type }>#{default ? " (default: #{default})" : ""}:"
|
36
|
+
puts " " << description if description and not description.empty?
|
37
|
+
puts
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
module Workflow
|
45
|
+
def doc(task = nil)
|
46
|
+
|
47
|
+
if task.nil?
|
48
|
+
puts self.to_s
|
49
|
+
puts "=" * self.to_s.length
|
50
|
+
puts
|
51
|
+
|
52
|
+
puts "## TASKS"
|
53
|
+
puts
|
54
|
+
tasks.each do |name,task|
|
55
|
+
puts " * #{ name }:"
|
56
|
+
puts " " << task.description if task.description and not task.description.empty?
|
57
|
+
puts
|
58
|
+
end
|
59
|
+
else
|
60
|
+
|
61
|
+
if Task === task
|
62
|
+
task_name = task.name
|
63
|
+
else
|
64
|
+
task_name = task
|
65
|
+
task = self.tasks[task_name]
|
66
|
+
end
|
67
|
+
dependencies = self.rec_dependencies(task_name).collect{|dep_name| self.tasks[dep_name.to_sym]}
|
68
|
+
|
69
|
+
task.doc(dependencies)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/share/lib/R/util.R
CHANGED
@@ -22,6 +22,10 @@ rbbt.ruby <- function(code, load = TRUE, flat = FALSE, type = 'tsv', ...){
|
|
22
22
|
data = scan(file, ...)
|
23
23
|
return(data);
|
24
24
|
}
|
25
|
+
|
26
|
+
if(type == 'string'){
|
27
|
+
return(file);
|
28
|
+
}
|
25
29
|
|
26
30
|
return(NULL);
|
27
31
|
}else{
|
@@ -268,4 +272,12 @@ rbbt.plot.matrix <- function(x, ...){
|
|
268
272
|
layout(1);
|
269
273
|
}
|
270
274
|
|
275
|
+
rbbt.log <- function(m){
|
276
|
+
cat(paste(m,"\n"), file = stderr())
|
277
|
+
}
|
278
|
+
|
279
|
+
rbbt.ddd <- function(o){
|
280
|
+
cat(toString(o), file = stderr())
|
281
|
+
cat("\n", file = stderr())
|
282
|
+
}
|
271
283
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rbbt'
|
4
|
+
require 'highline/import'
|
5
|
+
|
6
|
+
if Rbbt.etc.web_users.exists?
|
7
|
+
web_users = Rbbt.etc.web_users.yaml
|
8
|
+
else
|
9
|
+
web_users = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
user = ARGV.shift
|
13
|
+
|
14
|
+
raise "No user provided" if user.nil?
|
15
|
+
|
16
|
+
password = ask("Enter your password: ") { |q| q.echo = "x" }
|
17
|
+
|
18
|
+
raise "No password provided" if password.nil?
|
19
|
+
|
20
|
+
password_check = ask("Re-enter your password: ") { |q| q.echo = "x" }
|
21
|
+
|
22
|
+
raise "Passwords don't match" if password != password_check
|
23
|
+
|
24
|
+
web_users[user] = password
|
25
|
+
|
26
|
+
Rbbt.etc.web_users.write(web_users.to_yaml)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rbbt'
|
4
|
+
require 'highline/import'
|
5
|
+
|
6
|
+
if Rbbt.etc.web_users.exists?
|
7
|
+
web_users = Rbbt.etc.web_users.yaml
|
8
|
+
else
|
9
|
+
web_users = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
user = ARGV.shift
|
13
|
+
|
14
|
+
raise "No user provided" if user.nil?
|
15
|
+
|
16
|
+
web_users.delete user
|
17
|
+
|
18
|
+
Rbbt.etc.web_users.write(web_users.to_yaml)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rbbt'
|
4
|
+
|
5
|
+
url, workflow = ARGV
|
6
|
+
url = File.join(url, workflow) unless url =~ /\/#{workflow}$/
|
7
|
+
config_file = Rbbt.etc.remote_workflows
|
8
|
+
remote_workflows = config_file.exists? ? config_file.yaml : {}
|
9
|
+
remote_workflows[workflow] = url
|
10
|
+
Open.write(config_file.find(:user), remote_workflows.to_yaml)
|
11
|
+
|
@@ -0,0 +1,9 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rbbt'
|
4
|
+
|
5
|
+
workflow = ARGV.shift
|
6
|
+
config_file = Rbbt.etc.remote_workflows
|
7
|
+
remote_workflows = config_file.exists? ? config_file.yaml : {}
|
8
|
+
remote_workflows.delete workflow
|
9
|
+
Open.write(config_file.find(:user), remote_workflows.to_yaml)
|
@@ -0,0 +1,181 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rbbt/util/simpleopt'
|
4
|
+
require 'rbbt/workflow'
|
5
|
+
require 'rbbt/workflow/usage'
|
6
|
+
|
7
|
+
def usage(workflow = nil, task = nil)
|
8
|
+
if workflow.nil?
|
9
|
+
puts "No workflow specified"
|
10
|
+
exit -1
|
11
|
+
end
|
12
|
+
|
13
|
+
if task.nil?
|
14
|
+
workflow.doc
|
15
|
+
else
|
16
|
+
workflow.doc(task)
|
17
|
+
end
|
18
|
+
exit 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def SOPT_options(workflow, task)
|
22
|
+
sopt_options = []
|
23
|
+
workflow.rec_inputs(task.name).each do |name|
|
24
|
+
short = name.to_s.chars.first
|
25
|
+
boolean = workflow.rec_input_types(task.name)[name].to_sym == :boolean
|
26
|
+
|
27
|
+
sopt_options << "-#{short}--#{name}#{boolean ? '' : '*'}"
|
28
|
+
end
|
29
|
+
|
30
|
+
sopt_options * ":"
|
31
|
+
end
|
32
|
+
|
33
|
+
def fix_options(workflow, task, job_options)
|
34
|
+
option_types = workflow.rec_input_types(task.name)
|
35
|
+
|
36
|
+
job_options_cleaned = {}
|
37
|
+
|
38
|
+
job_options.each do |name, value|
|
39
|
+
value = case option_types[name].to_sym
|
40
|
+
when :float
|
41
|
+
value.to_f
|
42
|
+
when :integer
|
43
|
+
value.to_i
|
44
|
+
when :string, :text
|
45
|
+
case
|
46
|
+
when value == '-'
|
47
|
+
STDIN.read
|
48
|
+
when (String === value and File.exists?(value))
|
49
|
+
Open.read(value)
|
50
|
+
else
|
51
|
+
value
|
52
|
+
end
|
53
|
+
when :array
|
54
|
+
if Array === value
|
55
|
+
value
|
56
|
+
else
|
57
|
+
case
|
58
|
+
when value == '-'
|
59
|
+
STDIN.read
|
60
|
+
when (String === value and File.exists?(value))
|
61
|
+
Open.read(value)
|
62
|
+
else
|
63
|
+
value
|
64
|
+
end.split(/[,|\s]/)
|
65
|
+
end
|
66
|
+
when :tsv
|
67
|
+
if TSV === value
|
68
|
+
value
|
69
|
+
else
|
70
|
+
begin
|
71
|
+
if value == '-'
|
72
|
+
TSV.open(STDIN).to_s :sort
|
73
|
+
else
|
74
|
+
TSV.new(value).to_s :sort
|
75
|
+
end
|
76
|
+
rescue
|
77
|
+
value
|
78
|
+
end
|
79
|
+
end
|
80
|
+
else
|
81
|
+
value
|
82
|
+
end
|
83
|
+
job_options_cleaned[name] = value
|
84
|
+
end
|
85
|
+
|
86
|
+
job_options_cleaned
|
87
|
+
end
|
88
|
+
|
89
|
+
options = SOPT.get "-t--task*:--profile:-l--log*:-h--help:-n--name*:-cl--clean:-rcl-recursive_clean:-pn--printname"
|
90
|
+
|
91
|
+
workflow = ARGV.shift
|
92
|
+
usage if workflow.nil?
|
93
|
+
|
94
|
+
task = ARGV.shift
|
95
|
+
|
96
|
+
|
97
|
+
# Set log, fork, clean, recursive_clean and help
|
98
|
+
Log.severity = options[:log].to_i if options.include? :log
|
99
|
+
help = !!options.delete(:help)
|
100
|
+
do_fork = !!options.delete(:fork)
|
101
|
+
clean = !!options.delete(:clean)
|
102
|
+
recursive_clean = !!options.delete(:recursive_clean)
|
103
|
+
|
104
|
+
# Get workflow
|
105
|
+
|
106
|
+
if Rbbt.etc.remote_workflows.exists?
|
107
|
+
remote_workflows = Rbbt.etc.remote_workflows.yaml
|
108
|
+
else
|
109
|
+
remote_workflows = {}
|
110
|
+
end
|
111
|
+
|
112
|
+
if remote_workflows.include? workflow
|
113
|
+
require 'rbbt/rest/client'
|
114
|
+
workflow = WorkflowRESTClient.new remote_workflows[workflow], workflow
|
115
|
+
else
|
116
|
+
Workflow.require_workflow workflow
|
117
|
+
workflow = Workflow.workflows.last
|
118
|
+
end
|
119
|
+
|
120
|
+
# Set task
|
121
|
+
namespace = nil, nil
|
122
|
+
|
123
|
+
case
|
124
|
+
when task.nil?
|
125
|
+
usage workflow
|
126
|
+
when (task =~ /\./)
|
127
|
+
namespace, task = options.delete(:task).split('.')
|
128
|
+
namespace = Misc.string2const(namespace)
|
129
|
+
else
|
130
|
+
task_name = task.to_sym
|
131
|
+
task = workflow.tasks[task_name]
|
132
|
+
raise "Task not found: #{ task_name }" if task.nil?
|
133
|
+
end
|
134
|
+
|
135
|
+
usage workflow, task if help
|
136
|
+
|
137
|
+
name = options.delete(:name) || "Default"
|
138
|
+
|
139
|
+
# get job args
|
140
|
+
sopt_option_string = SOPT_options(workflow, task)
|
141
|
+
job_options = SOPT.get sopt_option_string
|
142
|
+
job_options = fix_options(workflow,task, job_options)
|
143
|
+
|
144
|
+
#- get job
|
145
|
+
job = workflow.job(task.name, name, job_options)
|
146
|
+
|
147
|
+
# clean job
|
148
|
+
job.clean if clean
|
149
|
+
job.recursive_clean if recursive_clean
|
150
|
+
|
151
|
+
# run
|
152
|
+
if do_fork
|
153
|
+
job.fork
|
154
|
+
while not job.done?
|
155
|
+
Log.debug "#{job.step}: #{job.messages.last}"
|
156
|
+
sleep 2
|
157
|
+
end
|
158
|
+
raise job.messages.last if job.error?
|
159
|
+
res = job.load
|
160
|
+
else
|
161
|
+
res = job.run
|
162
|
+
end
|
163
|
+
|
164
|
+
if options.delete(:printname)
|
165
|
+
puts job.name
|
166
|
+
exit
|
167
|
+
else
|
168
|
+
Log.low "Job name: #{job.name}"
|
169
|
+
end
|
170
|
+
|
171
|
+
case
|
172
|
+
when Array === res
|
173
|
+
puts res * "\n"
|
174
|
+
when TSV === res
|
175
|
+
puts res
|
176
|
+
when Hash === res
|
177
|
+
puts res.to_yaml
|
178
|
+
else
|
179
|
+
puts res
|
180
|
+
end
|
181
|
+
|