rbbt-util 5.26.77 → 5.26.78
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.
- checksums.yaml +4 -4
- data/lib/rbbt/annotations.rb +1 -1
- data/lib/rbbt/monitor.rb +21 -16
- data/lib/rbbt/resource.rb +17 -0
- data/lib/rbbt/resource/util.rb +2 -4
- data/lib/rbbt/util/cmd.rb +5 -1
- data/lib/rbbt/util/misc/concurrent_stream.rb +12 -3
- data/lib/rbbt/util/open.rb +22 -3
- data/lib/rbbt/workflow.rb +16 -3
- data/lib/rbbt/workflow/accessor.rb +0 -680
- data/lib/rbbt/workflow/definition.rb +2 -0
- data/lib/rbbt/workflow/integration/nextflow.rb +37 -0
- data/lib/rbbt/workflow/remote/client.rb +69 -0
- data/lib/rbbt/workflow/remote/remote_step.rb +308 -0
- data/lib/rbbt/workflow/remote/rest/adaptor.rb +158 -0
- data/lib/rbbt/workflow/remote/rest/get.rb +305 -0
- data/lib/rbbt/workflow/remote/ssh/adaptor.rb +78 -0
- data/lib/rbbt/workflow/remote/ssh/get.rb +281 -0
- data/lib/rbbt/workflow/step.rb +42 -2
- data/lib/rbbt/workflow/step/accessor.rb +685 -0
- data/lib/rbbt/workflow/{prepare.rb → step/prepare.rb} +0 -0
- data/lib/rbbt/workflow/{archive.rb → util/archive.rb} +47 -22
- data/lib/rbbt/workflow/{provenance.rb → util/provenance.rb} +0 -0
- data/share/rbbt_commands/migrate +105 -0
- data/share/rbbt_commands/migrate_job +132 -0
- data/share/rbbt_commands/workflow/prov +1 -1
- data/share/rbbt_commands/workflow/task +7 -4
- data/test/rbbt/test_resource.rb +5 -0
- data/test/rbbt/test_workflow.rb +18 -2
- metadata +15 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fa385d029073f92c7d003f8dd139ffd76f256cf50e8b6f9eb48146b8624c1d0f
|
|
4
|
+
data.tar.gz: 1e9d23cd39e36dcebf0d2e61f269593f031cb7a8c8b4ff900993aa10fd7b11a6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3f7f0f8aef95c5f79832f18c741f6751e24ff78aa59e739fa44b38d5ae88c5be7f77ae1c293fb07c025e6ed9ed6030354b8b279ed379a01bf970a0efb9d5bd99
|
|
7
|
+
data.tar.gz: 02070acbc4a9ab3925f0bbf85bc2b07069241d46e8ffdf72085e09bd952b3e24d73eceed255c267d2b1de9ed63fb214142413a9d3e0badb3f19b409c5880a4b6
|
data/lib/rbbt/annotations.rb
CHANGED
data/lib/rbbt/monitor.rb
CHANGED
|
@@ -138,28 +138,32 @@ module Rbbt
|
|
|
138
138
|
dirs.collect do |dir|
|
|
139
139
|
next unless Open.exists? dir
|
|
140
140
|
|
|
141
|
+
task_dir_workflows = {}
|
|
141
142
|
tasks_dirs = if dir == '.'
|
|
142
143
|
["."]
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
else
|
|
145
|
+
workflowdirs = if (dir_sub_path = Open.find_repo_dir(workflowdir))
|
|
146
|
+
repo_dir, sub_path = dir_sub_path
|
|
147
|
+
Open.list_repo_files(*dir_sub_path).collect{|f| f.split("/").first}.uniq.collect{|f| File.join(repo_dir, f)}.uniq
|
|
148
|
+
else
|
|
149
|
+
dir.glob("*")
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
workflowdirs.collect do |workflowdir|
|
|
153
|
+
workflow = File.basename(workflowdir)
|
|
154
|
+
next if workflows and not workflows.include? workflow
|
|
155
|
+
|
|
156
|
+
task_dirs = if (dir_sub_path = Open.find_repo_dir(workflowdir))
|
|
145
157
|
repo_dir, sub_path = dir_sub_path
|
|
146
158
|
Open.list_repo_files(*dir_sub_path).collect{|f| f.split("/").first}.uniq.collect{|f| File.join(repo_dir, f)}.uniq
|
|
147
159
|
else
|
|
148
|
-
|
|
160
|
+
workflowdir.glob("*")
|
|
149
161
|
end
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (dir_sub_path = Open.find_repo_dir(workflowdir))
|
|
156
|
-
repo_dir, sub_path = dir_sub_path
|
|
157
|
-
Open.list_repo_files(*dir_sub_path).collect{|f| f.split("/").first}.uniq.collect{|f| File.join(repo_dir, f)}.uniq
|
|
158
|
-
else
|
|
159
|
-
workflowdir.glob("*")
|
|
160
|
-
end
|
|
161
|
-
end.compact.flatten
|
|
162
|
-
end
|
|
162
|
+
task_dirs.each do |tasks_dir|
|
|
163
|
+
task_dir_workflows[tasks_dir] = workflow
|
|
164
|
+
end
|
|
165
|
+
end.compact.flatten
|
|
166
|
+
end
|
|
163
167
|
|
|
164
168
|
tasks_dirs.collect do |taskdir|
|
|
165
169
|
task = File.basename(taskdir)
|
|
@@ -184,6 +188,7 @@ module Rbbt
|
|
|
184
188
|
end
|
|
185
189
|
|
|
186
190
|
files = files.sort_by{|f| Open.mtime(f) || Time.now}
|
|
191
|
+
workflow = task_dir_workflows[taskdir]
|
|
187
192
|
TSV.traverse files, :type => :array, :into => jobs, :_bar => "Finding jobs in #{ taskdir }" do |file|
|
|
188
193
|
_files << file
|
|
189
194
|
if m = file.match(/(.*)\.(info|pid|files)$/)
|
data/lib/rbbt/resource.rb
CHANGED
|
@@ -281,5 +281,22 @@ url='#{url}'
|
|
|
281
281
|
|
|
282
282
|
path
|
|
283
283
|
end
|
|
284
|
+
|
|
285
|
+
def identify(path)
|
|
286
|
+
path = File.expand_path(path)
|
|
287
|
+
resource ||= Rbbt
|
|
288
|
+
(Path::STANDARD_SEARCH + resource.search_order + resource.search_paths.keys).uniq.each do |name|
|
|
289
|
+
pattern = resource.search_paths[name]
|
|
290
|
+
next if patterns.nil?
|
|
291
|
+
if String === pattern and pattern.include?('{')
|
|
292
|
+
regexp = "^" + pattern.gsub(/{([^}]+)}/,'(?<\1>[^/]+)') + "(?:/(?<REST>.*))?/?$"
|
|
293
|
+
if m = path.match(regexp)
|
|
294
|
+
if m["PKGDIR"] == resource.pkgdir
|
|
295
|
+
return self[m["TOPLEVEL"]][m["SUBPATH"]][m["REST"]]
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|
|
284
301
|
end
|
|
285
302
|
|
data/lib/rbbt/resource/util.rb
CHANGED
|
@@ -83,10 +83,8 @@ module Resource
|
|
|
83
83
|
Misc.env_add('CLASSPATH', "#{dir}")
|
|
84
84
|
end if File.exist? File.join(opt_dir, '.java-classpaths')
|
|
85
85
|
|
|
86
|
-
Dir.glob(File.join opt_dir, 'jars', '
|
|
87
|
-
|
|
88
|
-
dir = File.join(opt_dir, dir) unless dir[0] == "/"
|
|
89
|
-
Misc.env_add('CLASSPATH', "#{dir}")
|
|
86
|
+
Dir.glob(File.join opt_dir, 'jars', '*.jar').each do |file|
|
|
87
|
+
Misc.env_add('CLASSPATH', "#{file}")
|
|
90
88
|
end
|
|
91
89
|
|
|
92
90
|
if File.exist?(File.join(opt_dir, '.post_install')) and File.directory?(File.join(opt_dir, '.post_install'))
|
data/lib/rbbt/util/cmd.rb
CHANGED
|
@@ -150,14 +150,18 @@ module CMD
|
|
|
150
150
|
pids = [pid]
|
|
151
151
|
|
|
152
152
|
if pipe
|
|
153
|
+
|
|
154
|
+
ConcurrentStream.setup sout, :pids => pids, :autojoin => no_wait, :no_fail => no_fail
|
|
155
|
+
|
|
153
156
|
err_thread = Thread.new do
|
|
154
157
|
while line = serr.gets
|
|
158
|
+
sout.log = line
|
|
155
159
|
Log.log "STDERR [#{pid}]: " + line, stderr
|
|
156
160
|
end if Integer === stderr and log
|
|
157
161
|
serr.close
|
|
158
162
|
end
|
|
159
163
|
|
|
160
|
-
|
|
164
|
+
sout.threads = [in_thread, err_thread, wait_thr].compact
|
|
161
165
|
|
|
162
166
|
sout
|
|
163
167
|
else
|
|
@@ -7,7 +7,7 @@ module AbortedStream
|
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
module ConcurrentStream
|
|
10
|
-
attr_accessor :threads, :pids, :callback, :abort_callback, :filename, :joined, :aborted, :autojoin, :lockfile, :no_fail, :pair, :thread, :stream_exception
|
|
10
|
+
attr_accessor :threads, :pids, :callback, :abort_callback, :filename, :joined, :aborted, :autojoin, :lockfile, :no_fail, :pair, :thread, :stream_exception, :log
|
|
11
11
|
|
|
12
12
|
def self.setup(stream, options = {}, &block)
|
|
13
13
|
|
|
@@ -81,7 +81,12 @@ module ConcurrentStream
|
|
|
81
81
|
begin
|
|
82
82
|
t.join
|
|
83
83
|
if Process::Status === t.value
|
|
84
|
-
|
|
84
|
+
if log
|
|
85
|
+
raise ProcessFailed.new "Error joining process #{t.pid} in #{self.filename || self.inspect}. Last log line: #{log}" if ! (t.value.success? || no_fail)
|
|
86
|
+
else
|
|
87
|
+
raise ProcessFailed.new "Error joining process #{t.pid} in #{self.filename || self.inspect}" if ! (t.value.success? || no_fail)
|
|
88
|
+
end
|
|
89
|
+
raise ProcessFailed.new "Error joining process #{t.pid} in #{self.filename || self.inspect}. Last log line: #{log}" if ! (t.value.success? || no_fail)
|
|
85
90
|
end
|
|
86
91
|
rescue Exception
|
|
87
92
|
if no_fail
|
|
@@ -101,7 +106,11 @@ module ConcurrentStream
|
|
|
101
106
|
@pids.each do |pid|
|
|
102
107
|
begin
|
|
103
108
|
Process.waitpid(pid, Process::WUNTRACED)
|
|
104
|
-
|
|
109
|
+
if log
|
|
110
|
+
stream_raise_exception ProcessFailed.new "Error joining process #{pid} in #{self.filename || self.inspect}. Last log line: #{log}" unless $?.success? or no_fail
|
|
111
|
+
else
|
|
112
|
+
stream_raise_exception ProcessFailed.new "Error joining process #{pid} in #{self.filename || self.inspect}" unless $?.success? or no_fail
|
|
113
|
+
end
|
|
105
114
|
rescue Errno::ECHILD
|
|
106
115
|
end
|
|
107
116
|
end
|
data/lib/rbbt/util/open.rb
CHANGED
|
@@ -299,6 +299,13 @@ module Open
|
|
|
299
299
|
end
|
|
300
300
|
end
|
|
301
301
|
|
|
302
|
+
def self.ssh_open(file)
|
|
303
|
+
m = file.match(/ssh:\/\/([^:]+):(.*)/)
|
|
304
|
+
server = m[1]
|
|
305
|
+
file = m[2]
|
|
306
|
+
CMD.cmd("ssh '#{server}' cat '#{file}'", :pipe => true)
|
|
307
|
+
end
|
|
308
|
+
|
|
302
309
|
def self.file_write(file, content, mode = 'w')
|
|
303
310
|
if (dir_sub_path = find_repo_dir(file))
|
|
304
311
|
dir_sub_path.push content
|
|
@@ -507,6 +514,10 @@ module Open
|
|
|
507
514
|
!! (file =~ /^(?:https?|ftp):\/\//)
|
|
508
515
|
end
|
|
509
516
|
|
|
517
|
+
def self.ssh?(file)
|
|
518
|
+
!! (file =~ /^ssh:\/\//)
|
|
519
|
+
end
|
|
520
|
+
|
|
510
521
|
def self.gzip?(file)
|
|
511
522
|
file = file.find if Path === file
|
|
512
523
|
!! (file =~ /\.gz$/)
|
|
@@ -571,15 +582,23 @@ module Open
|
|
|
571
582
|
io = case
|
|
572
583
|
when (IO === url or StringIO === url)
|
|
573
584
|
url
|
|
574
|
-
when (not remote?(url))
|
|
585
|
+
when (not remote?(url) and not ssh?(url))
|
|
575
586
|
file_open(url, options[:grep], mode, options[:invert_grep])
|
|
576
587
|
when (options[:nocache] and options[:nocache] != :update)
|
|
577
588
|
# What about grep?
|
|
578
|
-
|
|
589
|
+
if ssh?(url)
|
|
590
|
+
ssh_open(url)
|
|
591
|
+
else
|
|
592
|
+
wget(url, wget_options)
|
|
593
|
+
end
|
|
579
594
|
when (options[:nocache] != :update and in_cache(url, wget_options))
|
|
580
595
|
file_open(in_cache(url, wget_options), options[:grep], mode, options[:invert_grep])
|
|
581
596
|
else
|
|
582
|
-
io =
|
|
597
|
+
io = if ssh?(url)
|
|
598
|
+
ssh_open(url)
|
|
599
|
+
else
|
|
600
|
+
wget(url, wget_options)
|
|
601
|
+
end
|
|
583
602
|
add_cache(url, io, wget_options)
|
|
584
603
|
file_open(in_cache(url, wget_options), options[:grep], mode, options[:invert_grep])
|
|
585
604
|
end
|
data/lib/rbbt/workflow.rb
CHANGED
|
@@ -4,7 +4,9 @@ require 'rbbt/workflow/step'
|
|
|
4
4
|
require 'rbbt/workflow/accessor'
|
|
5
5
|
require 'rbbt/workflow/doc'
|
|
6
6
|
require 'rbbt/workflow/examples'
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
require 'rbbt/workflow/util/archive'
|
|
9
|
+
require 'rbbt/workflow/util/provenance'
|
|
8
10
|
|
|
9
11
|
module Workflow
|
|
10
12
|
|
|
@@ -48,6 +50,11 @@ module Workflow
|
|
|
48
50
|
eval "Object::#{wf_name} = WorkflowRESTClient.new '#{ url }', '#{wf_name}'"
|
|
49
51
|
end
|
|
50
52
|
|
|
53
|
+
def self.require_remote_workflow(wf_name, url)
|
|
54
|
+
require 'rbbt/workflow/remote/client'
|
|
55
|
+
eval "Object::#{wf_name} = WorkflowRemoteClient.new '#{ url }', '#{wf_name}'"
|
|
56
|
+
end
|
|
57
|
+
|
|
51
58
|
def self.load_workflow_libdir(filename)
|
|
52
59
|
workflow_lib_dir = File.join(File.dirname(File.expand_path(filename)), 'lib')
|
|
53
60
|
if File.directory? workflow_lib_dir
|
|
@@ -159,9 +166,15 @@ module Workflow
|
|
|
159
166
|
end
|
|
160
167
|
end
|
|
161
168
|
|
|
162
|
-
if Open.remote? wf_name
|
|
169
|
+
if Open.remote?(wf_name) or Open.ssh?(wf_name)
|
|
163
170
|
url = wf_name
|
|
164
|
-
|
|
171
|
+
|
|
172
|
+
if Open.ssh?(wf_name)
|
|
173
|
+
wf_name = File.basename(url.split(":").last)
|
|
174
|
+
else
|
|
175
|
+
wf_name = File.basename(url)
|
|
176
|
+
end
|
|
177
|
+
|
|
165
178
|
begin
|
|
166
179
|
return require_remote_workflow(wf_name, url)
|
|
167
180
|
ensure
|
|
@@ -13,684 +13,6 @@ module ComputeDependency
|
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
class Step
|
|
17
|
-
|
|
18
|
-
INFO_SERIALIAZER = Marshal
|
|
19
|
-
|
|
20
|
-
def self.wait_for_jobs(jobs)
|
|
21
|
-
jobs = [jobs] if Step === jobs
|
|
22
|
-
begin
|
|
23
|
-
threads = []
|
|
24
|
-
|
|
25
|
-
threads = jobs.collect do |j|
|
|
26
|
-
Thread.new do
|
|
27
|
-
begin
|
|
28
|
-
j.join unless j.done?
|
|
29
|
-
rescue Exception
|
|
30
|
-
Log.error "Exception waiting for job: #{Log.color :blue, j.path}"
|
|
31
|
-
raise $!
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
threads.each{|t| t.join }
|
|
37
|
-
rescue Exception
|
|
38
|
-
threads.each{|t| t.exit }
|
|
39
|
-
jobs.each do |j| j.abort end
|
|
40
|
-
raise $!
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def self.files_dir(path)
|
|
45
|
-
path.nil? ? nil : path + '.files'
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def self.info_file(path)
|
|
49
|
-
path.nil? ? nil : path + '.info'
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def self.tmp_path(path)
|
|
53
|
-
path = path.find if Path === path
|
|
54
|
-
path = File.expand_path(path)
|
|
55
|
-
dir = File.dirname(path)
|
|
56
|
-
filename = File.basename(path)
|
|
57
|
-
File.join(dir, '.' << filename)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def self.md5_file(path)
|
|
61
|
-
path.nil? ? nil : path + '.md5'
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def self.pid_file(path)
|
|
65
|
-
path.nil? ? nil : path + '.pid'
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def self.step_info(path)
|
|
69
|
-
begin
|
|
70
|
-
Open.open(info_file(path), :mode => 'rb') do |f|
|
|
71
|
-
INFO_SERIALIAZER.load(f)
|
|
72
|
-
end
|
|
73
|
-
rescue Exception
|
|
74
|
-
Log.exception $!
|
|
75
|
-
{}
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def self.job_name_for_info_file(info_file, extension = nil)
|
|
80
|
-
if extension and not extension.empty?
|
|
81
|
-
info_file.sub(/\.#{extension}\.info$/,'')
|
|
82
|
-
else
|
|
83
|
-
info_file.sub(/\.info$/,'')
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def self.save_job_inputs(job, dir, options = nil)
|
|
88
|
-
options = IndiferentHash.setup options.dup if options
|
|
89
|
-
|
|
90
|
-
task_name = job.task_name
|
|
91
|
-
workflow = job.workflow
|
|
92
|
-
workflow = Kernel.const_get workflow if String === workflow
|
|
93
|
-
task_info = workflow.task_info(task_name)
|
|
94
|
-
input_types = task_info[:input_types]
|
|
95
|
-
task_inputs = task_info[:inputs]
|
|
96
|
-
|
|
97
|
-
saved = false
|
|
98
|
-
job.recursive_inputs.zip(job.recursive_inputs.fields).each do |value,name|
|
|
99
|
-
next unless task_inputs.include? name.to_sym
|
|
100
|
-
next if options and ! options.include?(name)
|
|
101
|
-
next if value.nil?
|
|
102
|
-
saved = true
|
|
103
|
-
path = File.join(dir, name.to_s)
|
|
104
|
-
type = input_types[name].to_s
|
|
105
|
-
Log.debug "Saving job input #{name} (#{type}) into #{path}"
|
|
106
|
-
case
|
|
107
|
-
when Array === value
|
|
108
|
-
Open.write(path, value * "\n")
|
|
109
|
-
when IO === value
|
|
110
|
-
Open.write(path, value)
|
|
111
|
-
when type == "file"
|
|
112
|
-
if String === value && File.exists?(value)
|
|
113
|
-
Open.link(value, path)
|
|
114
|
-
else
|
|
115
|
-
Open.write(path + '.read', value.to_s)
|
|
116
|
-
end
|
|
117
|
-
else
|
|
118
|
-
Open.write(path, value.to_s)
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
saved
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def name
|
|
126
|
-
@name ||= path.sub(/.*\/#{Regexp.quote task_name.to_s}\/(.*)/, '\1')
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def short_path
|
|
130
|
-
[task_name, name] * "/"
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
def task_name
|
|
134
|
-
@task_name ||= task.name
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
# {{{ INFO
|
|
138
|
-
|
|
139
|
-
def info_file
|
|
140
|
-
@info_file ||= Step.info_file(path)
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def pid_file
|
|
144
|
-
@pid_file ||= Step.pid_file(path)
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
def info_lock
|
|
148
|
-
@info_lock = begin
|
|
149
|
-
path = Persist.persistence_path(info_file + '.lock', {:dir => Step.lock_dir})
|
|
150
|
-
#Lockfile.new path, :refresh => false, :dont_use_lock_id => true
|
|
151
|
-
Lockfile.new path
|
|
152
|
-
end if @info_lock.nil?
|
|
153
|
-
@info_lock
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
def status_lock
|
|
157
|
-
return @mutex
|
|
158
|
-
#@status_lock = begin
|
|
159
|
-
# path = Persist.persistence_path(info_file + '.status.lock', {:dir => Step.lock_dir})
|
|
160
|
-
# Lockfile.new path, :refresh => false, :dont_use_lock_id => true
|
|
161
|
-
# end if @status_lock.nil?
|
|
162
|
-
#@status_lock
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
def info(check_lock = true)
|
|
166
|
-
return {:status => :noinfo} if info_file.nil? or not Open.exists? info_file
|
|
167
|
-
begin
|
|
168
|
-
Misc.insist do
|
|
169
|
-
begin
|
|
170
|
-
return @info_cache if @info_cache and @info_cache_time and Open.ctime(info_file) < @info_cache_time
|
|
171
|
-
rescue Exception
|
|
172
|
-
raise $!
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
begin
|
|
176
|
-
@info_cache = Misc.insist(3, 1.6, info_file) do
|
|
177
|
-
Misc.insist(2, 1, info_file) do
|
|
178
|
-
Misc.insist(3, 0.2, info_file) do
|
|
179
|
-
raise TryAgain, "Info locked" if check_lock and info_lock.locked?
|
|
180
|
-
info_lock.lock if check_lock and false
|
|
181
|
-
begin
|
|
182
|
-
Open.open(info_file, :mode => 'rb') do |file|
|
|
183
|
-
INFO_SERIALIAZER.load(file) #|| {}
|
|
184
|
-
end
|
|
185
|
-
ensure
|
|
186
|
-
info_lock.unlock if check_lock and false
|
|
187
|
-
end
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
end
|
|
191
|
-
@info_cache_time = Time.now
|
|
192
|
-
@info_cache
|
|
193
|
-
end
|
|
194
|
-
end
|
|
195
|
-
rescue Exception
|
|
196
|
-
Log.debug{"Error loading info file: " + info_file}
|
|
197
|
-
Log.exception $!
|
|
198
|
-
Open.rm info_file
|
|
199
|
-
Misc.sensiblewrite(info_file, INFO_SERIALIAZER.dump({:status => :error, :messages => ["Info file lost"]}))
|
|
200
|
-
raise $!
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
def init_info(force = false)
|
|
205
|
-
return nil if @exec or info_file.nil? or (Open.exists?(info_file) and ! force)
|
|
206
|
-
Open.lock(info_file, :lock => info_lock) do
|
|
207
|
-
i = {:status => :waiting, :pid => Process.pid, :path => path}
|
|
208
|
-
i[:dependencies] = dependencies.collect{|dep| [dep.task_name, dep.name, dep.path]} if dependencies
|
|
209
|
-
@info_cache = i
|
|
210
|
-
Misc.sensiblewrite(info_file, INFO_SERIALIAZER.dump(i), :force => true, :lock => false)
|
|
211
|
-
@info_cache_time = Time.now
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
def set_info(key, value)
|
|
216
|
-
return nil if @exec or info_file.nil?
|
|
217
|
-
return nil if ! writable?
|
|
218
|
-
value = Annotated.purge value if defined? Annotated
|
|
219
|
-
Open.lock(info_file, :lock => info_lock) do
|
|
220
|
-
i = info(false).dup
|
|
221
|
-
i[key] = value
|
|
222
|
-
@info_cache = i
|
|
223
|
-
dump = INFO_SERIALIAZER.dump(i)
|
|
224
|
-
Misc.sensiblewrite(info_file, dump, :force => true, :lock => false)
|
|
225
|
-
@info_cache_time = Time.now
|
|
226
|
-
value
|
|
227
|
-
end
|
|
228
|
-
end
|
|
229
|
-
|
|
230
|
-
def merge_info(hash)
|
|
231
|
-
return nil if @exec or info_file.nil?
|
|
232
|
-
return nil if ! writable?
|
|
233
|
-
value = Annotated.purge value if defined? Annotated
|
|
234
|
-
Open.lock(info_file, :lock => info_lock) do
|
|
235
|
-
i = info(false)
|
|
236
|
-
i.merge! hash
|
|
237
|
-
@info_cache = i
|
|
238
|
-
dump = INFO_SERIALIAZER.dump(i)
|
|
239
|
-
Misc.sensiblewrite(info_file, dump, :force => true, :lock => false)
|
|
240
|
-
@info_cache_time = Time.now
|
|
241
|
-
value
|
|
242
|
-
end
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
def status
|
|
246
|
-
begin
|
|
247
|
-
info[:status]
|
|
248
|
-
rescue Exception
|
|
249
|
-
Log.error "Exception reading status: #{$!.message}"
|
|
250
|
-
:error
|
|
251
|
-
end
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
def status=(status)
|
|
255
|
-
set_info(:status, status)
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
def messages
|
|
259
|
-
if messages = info[:messages]
|
|
260
|
-
messages
|
|
261
|
-
else
|
|
262
|
-
set_info(:messages, []) if self.respond_to?(:set_info)
|
|
263
|
-
end
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
def message(message)
|
|
267
|
-
message = Log.uncolor(message)
|
|
268
|
-
set_info(:messages, (messages || []) << message)
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
def self.status_color(status)
|
|
272
|
-
status = status.split(">").last
|
|
273
|
-
case status
|
|
274
|
-
when "starting"
|
|
275
|
-
:yellow
|
|
276
|
-
when "error", "aborted"
|
|
277
|
-
:red
|
|
278
|
-
when "done"
|
|
279
|
-
:green
|
|
280
|
-
else
|
|
281
|
-
:cyan
|
|
282
|
-
end
|
|
283
|
-
end
|
|
284
|
-
|
|
285
|
-
def self.log_block(status, message, path, &block)
|
|
286
|
-
start = Time.now
|
|
287
|
-
status = status.to_s
|
|
288
|
-
status_color = self.status_color status
|
|
289
|
-
|
|
290
|
-
Log.info do
|
|
291
|
-
now = Time.now
|
|
292
|
-
str = Log.color :reset
|
|
293
|
-
str << "#{ Log.color status_color, status}"
|
|
294
|
-
str << ": #{ message }" if message
|
|
295
|
-
str << " -- #{Log.color :blue, path.to_s}" if path
|
|
296
|
-
str << " #{Log.color :yellow, Process.pid}"
|
|
297
|
-
str
|
|
298
|
-
end
|
|
299
|
-
res = yield
|
|
300
|
-
eend = Time.now
|
|
301
|
-
Log.info do
|
|
302
|
-
now = Time.now
|
|
303
|
-
str = "#{ Log.color :cyan, status.to_s } +#{Log.color :green, "%.2f" % (eend - start)}"
|
|
304
|
-
str << " -- #{Log.color :blue, path.to_s}" if path
|
|
305
|
-
str << " #{Log.color :yellow, Process.pid}"
|
|
306
|
-
str
|
|
307
|
-
end
|
|
308
|
-
res
|
|
309
|
-
end
|
|
310
|
-
|
|
311
|
-
def self.log_string(status, message, path)
|
|
312
|
-
Log.info do
|
|
313
|
-
|
|
314
|
-
status = status.to_s
|
|
315
|
-
status_color = self.status_color status
|
|
316
|
-
|
|
317
|
-
str = Log.color :reset
|
|
318
|
-
str << "#{ Log.color status_color, status}"
|
|
319
|
-
str << ": #{ message }" if message
|
|
320
|
-
str << " -- #{Log.color :blue, path.to_s}" if path
|
|
321
|
-
str << " #{Log.color :yellow, Process.pid}"
|
|
322
|
-
str
|
|
323
|
-
end
|
|
324
|
-
end
|
|
325
|
-
|
|
326
|
-
def self.log_progress(status, options = {}, path = nil, &block)
|
|
327
|
-
options = Misc.add_defaults options, :severity => Log::INFO, :file => path
|
|
328
|
-
max = Misc.process_options options, :max
|
|
329
|
-
Log::ProgressBar.with_bar(max, options) do |bar|
|
|
330
|
-
begin
|
|
331
|
-
res = yield bar
|
|
332
|
-
raise KeepBar.new res if IO === res
|
|
333
|
-
res
|
|
334
|
-
rescue
|
|
335
|
-
Log.exception $!
|
|
336
|
-
raise $!
|
|
337
|
-
end
|
|
338
|
-
end
|
|
339
|
-
end
|
|
340
|
-
|
|
341
|
-
def log_progress(status, options = {}, &block)
|
|
342
|
-
Step.log_progress(status, options, file(:progress), &block)
|
|
343
|
-
end
|
|
344
|
-
|
|
345
|
-
def progress_bar(msg = "Progress", options = nil)
|
|
346
|
-
if Hash === msg and options.nil?
|
|
347
|
-
options = msg
|
|
348
|
-
msg = nil
|
|
349
|
-
end
|
|
350
|
-
options = {} if options.nil?
|
|
351
|
-
|
|
352
|
-
max = options[:max]
|
|
353
|
-
Log::ProgressBar.new_bar(max, {:desc => msg, :file => file(:progress)}.merge(options))
|
|
354
|
-
end
|
|
355
|
-
|
|
356
|
-
def self.log(status, message, path, &block)
|
|
357
|
-
if block
|
|
358
|
-
if Hash === message
|
|
359
|
-
log_progress(status, message, path, &block)
|
|
360
|
-
else
|
|
361
|
-
log_block(status, message, path, &block)
|
|
362
|
-
end
|
|
363
|
-
else
|
|
364
|
-
log_string(status, message, path)
|
|
365
|
-
end
|
|
366
|
-
end
|
|
367
|
-
|
|
368
|
-
def log(status, message = nil, &block)
|
|
369
|
-
self.status = status
|
|
370
|
-
if message
|
|
371
|
-
self.message Log.uncolor(message)
|
|
372
|
-
end
|
|
373
|
-
Step.log(status, message, path, &block)
|
|
374
|
-
end
|
|
375
|
-
|
|
376
|
-
def exception(ex, msg = nil)
|
|
377
|
-
ex_class = ex.class.to_s
|
|
378
|
-
backtrace = ex.backtrace if ex.respond_to?(:backtrace)
|
|
379
|
-
message = ex.message if ex.respond_to?(:message)
|
|
380
|
-
set_info :backtrace, backtrace
|
|
381
|
-
set_info :exception, {:class => ex_class, :message => message, :backtrace => backtrace}
|
|
382
|
-
if msg.nil?
|
|
383
|
-
log :error, "#{ex_class} -- #{message}"
|
|
384
|
-
else
|
|
385
|
-
log :error, "#{msg} -- #{message}"
|
|
386
|
-
end
|
|
387
|
-
self._abort
|
|
388
|
-
end
|
|
389
|
-
|
|
390
|
-
def get_exception
|
|
391
|
-
if info[:exception].nil?
|
|
392
|
-
return Aborted if aborted?
|
|
393
|
-
return Exception.new(messages.last) if error?
|
|
394
|
-
Exception.new ""
|
|
395
|
-
else
|
|
396
|
-
ex_class, ex_message, ex_backtrace = info[:exception].values_at :class, :message, :backtrace
|
|
397
|
-
begin
|
|
398
|
-
klass = Kernel.const_get(ex_class)
|
|
399
|
-
ex = klass.new ex_message
|
|
400
|
-
ex.set_backtrace ex_backtrace unless ex_backtrace.nil? or ex_backtrace.empty?
|
|
401
|
-
ex
|
|
402
|
-
rescue
|
|
403
|
-
Log.exception $!
|
|
404
|
-
Exception.new ex_message
|
|
405
|
-
end
|
|
406
|
-
end
|
|
407
|
-
end
|
|
408
|
-
|
|
409
|
-
def recoverable_error?
|
|
410
|
-
return true if aborted?
|
|
411
|
-
return false unless error?
|
|
412
|
-
begin
|
|
413
|
-
return true unless info[:exception]
|
|
414
|
-
klass = Kernel.const_get(info[:exception][:class])
|
|
415
|
-
! (klass <= RbbtException)
|
|
416
|
-
rescue Exception
|
|
417
|
-
true
|
|
418
|
-
end
|
|
419
|
-
end
|
|
420
|
-
|
|
421
|
-
def started?
|
|
422
|
-
Open.exists?(path) or (Open.exists?(pid_file) && Open.exists?(info_file))
|
|
423
|
-
end
|
|
424
|
-
|
|
425
|
-
def waiting?
|
|
426
|
-
Open.exists?(info_file) and not started?
|
|
427
|
-
end
|
|
428
|
-
|
|
429
|
-
def dirty_files
|
|
430
|
-
rec_dependencies = self.rec_dependencies
|
|
431
|
-
return [] if rec_dependencies.empty?
|
|
432
|
-
canfail_paths = self.canfail_paths
|
|
433
|
-
dirty_files = rec_dependencies.reject{|dep|
|
|
434
|
-
(defined?(WorkflowRESTClient) && WorkflowRESTClient::RemoteStep === dep) ||
|
|
435
|
-
! Open.exists?(dep.info_file) ||
|
|
436
|
-
(dep.path && (Open.exists?(dep.path) || Open.remote?(dep.path))) ||
|
|
437
|
-
((dep.error? || dep.aborted? || dep.waiting?) && (! dep.recoverable_error? || canfail_paths.include?(dep.path)))
|
|
438
|
-
}
|
|
439
|
-
end
|
|
440
|
-
|
|
441
|
-
def dirty?
|
|
442
|
-
return true if Open.exists?(pid_file) && ! ( Open.exists?(info_file) || done? )
|
|
443
|
-
return false unless done? || status == :done
|
|
444
|
-
return false unless ENV["RBBT_UPDATE"] == "true"
|
|
445
|
-
|
|
446
|
-
status = self.status
|
|
447
|
-
|
|
448
|
-
if done? and not (status == :done or status == :ending or status == :producing) and not status == :noinfo
|
|
449
|
-
return true
|
|
450
|
-
end
|
|
451
|
-
|
|
452
|
-
if status == :done and not done?
|
|
453
|
-
return true
|
|
454
|
-
end
|
|
455
|
-
|
|
456
|
-
if dirty_files.any?
|
|
457
|
-
Log.low "Some dirty files found for #{self.path}: #{Misc.fingerprint dirty_files}"
|
|
458
|
-
true
|
|
459
|
-
else
|
|
460
|
-
! self.updated?
|
|
461
|
-
end
|
|
462
|
-
end
|
|
463
|
-
|
|
464
|
-
def done?
|
|
465
|
-
path and Open.exists? path
|
|
466
|
-
end
|
|
467
|
-
|
|
468
|
-
def streaming?
|
|
469
|
-
(IO === @result) or (not @saved_stream.nil?) or status == :streaming
|
|
470
|
-
end
|
|
471
|
-
|
|
472
|
-
def noinfo?
|
|
473
|
-
status == :noinfo
|
|
474
|
-
end
|
|
475
|
-
|
|
476
|
-
def running?
|
|
477
|
-
return false if ! (started? || status == :ending)
|
|
478
|
-
pid = info[:pid]
|
|
479
|
-
return nil if pid.nil?
|
|
480
|
-
|
|
481
|
-
return false if done? or error? or aborted?
|
|
482
|
-
|
|
483
|
-
if Misc.pid_exists?(pid)
|
|
484
|
-
pid
|
|
485
|
-
else
|
|
486
|
-
done? or error? or aborted?
|
|
487
|
-
end
|
|
488
|
-
end
|
|
489
|
-
|
|
490
|
-
def stalled?
|
|
491
|
-
started? && ! (done? || running? || done? || error? || aborted?)
|
|
492
|
-
end
|
|
493
|
-
|
|
494
|
-
def missing?
|
|
495
|
-
status == :done && ! Open.exists?(path)
|
|
496
|
-
end
|
|
497
|
-
|
|
498
|
-
def error?
|
|
499
|
-
status == :error
|
|
500
|
-
end
|
|
501
|
-
|
|
502
|
-
def nopid?
|
|
503
|
-
pid = info[:pid] || Open.exists?(pid_file)
|
|
504
|
-
! pid && ! (status.nil? || status == :aborted || status == :done || status == :error)
|
|
505
|
-
end
|
|
506
|
-
|
|
507
|
-
def aborted?
|
|
508
|
-
status = self.status
|
|
509
|
-
status == :aborted || ((status != :noinfo && status != :setup && status != :noinfo) && nopid?)
|
|
510
|
-
end
|
|
511
|
-
|
|
512
|
-
# {{{ INFO
|
|
513
|
-
|
|
514
|
-
def files_dir
|
|
515
|
-
@files_dir ||= Step.files_dir path
|
|
516
|
-
end
|
|
517
|
-
|
|
518
|
-
def tmp_path
|
|
519
|
-
@tmp_path ||= Step.tmp_path path
|
|
520
|
-
end
|
|
521
|
-
|
|
522
|
-
def files
|
|
523
|
-
files = Dir.glob(File.join(files_dir, '**', '*')).reject{|path| File.directory? path}.collect do |path|
|
|
524
|
-
Misc.path_relative_to(files_dir, path)
|
|
525
|
-
end
|
|
526
|
-
files
|
|
527
|
-
end
|
|
528
|
-
|
|
529
|
-
def file(name)
|
|
530
|
-
Path.setup(File.join(files_dir, name.to_s))
|
|
531
|
-
end
|
|
532
|
-
|
|
533
|
-
def save_file(name, content)
|
|
534
|
-
content = case
|
|
535
|
-
when String === content
|
|
536
|
-
content
|
|
537
|
-
when Array === content
|
|
538
|
-
content * "\n"
|
|
539
|
-
when TSV === content
|
|
540
|
-
content.to_s
|
|
541
|
-
when Hash === content
|
|
542
|
-
content.collect{|*p| p * "\t"} * "\n"
|
|
543
|
-
else
|
|
544
|
-
content.to_s
|
|
545
|
-
end
|
|
546
|
-
Open.write(file(name), content)
|
|
547
|
-
end
|
|
548
|
-
|
|
549
|
-
def load_file(name, type = nil, options = {})
|
|
550
|
-
if type.nil? and name =~ /.*\.(\w+)$/
|
|
551
|
-
extension = name.match(/.*\.(\w+)$/)[1]
|
|
552
|
-
case extension
|
|
553
|
-
when "tc"
|
|
554
|
-
type = :tc
|
|
555
|
-
when "tsv"
|
|
556
|
-
type = :tsv
|
|
557
|
-
when "list", "ary", "array"
|
|
558
|
-
type = :array
|
|
559
|
-
when "yaml"
|
|
560
|
-
type = :yaml
|
|
561
|
-
when "marshal"
|
|
562
|
-
type = :marshal
|
|
563
|
-
else
|
|
564
|
-
type = :other
|
|
565
|
-
end
|
|
566
|
-
else
|
|
567
|
-
type ||= :other
|
|
568
|
-
end
|
|
569
|
-
|
|
570
|
-
case type.to_sym
|
|
571
|
-
when :tc
|
|
572
|
-
Persist.open_tokyocabinet(file(name), false)
|
|
573
|
-
when :tsv
|
|
574
|
-
TSV.open Open.open(file(name)), options
|
|
575
|
-
when :array
|
|
576
|
-
#Open.read(file(name)).split /\n|,\s*/
|
|
577
|
-
Open.read(file(name)).split "\n"
|
|
578
|
-
when :yaml
|
|
579
|
-
YAML.load(Open.open(file(name)))
|
|
580
|
-
when :marshal
|
|
581
|
-
Marshal.load(Open.open(file(name)))
|
|
582
|
-
else
|
|
583
|
-
Open.read(file(name))
|
|
584
|
-
end
|
|
585
|
-
end
|
|
586
|
-
|
|
587
|
-
def provenance
|
|
588
|
-
provenance = {}
|
|
589
|
-
dependencies.each do |dep|
|
|
590
|
-
next unless dep.path.exists?
|
|
591
|
-
if Open.exists? dep.info_file
|
|
592
|
-
provenance[dep.path] = dep.provenance if Open.exists? dep.path
|
|
593
|
-
else
|
|
594
|
-
provenance[dep.path] = nil
|
|
595
|
-
end
|
|
596
|
-
end
|
|
597
|
-
{:inputs => info[:inputs], :provenance => provenance}
|
|
598
|
-
end
|
|
599
|
-
|
|
600
|
-
def provenance_paths
|
|
601
|
-
provenance = {}
|
|
602
|
-
dependencies.each do |dep|
|
|
603
|
-
provenance[dep.path] = dep.provenance_paths if Open.exists? dep.path
|
|
604
|
-
end
|
|
605
|
-
provenance
|
|
606
|
-
end
|
|
607
|
-
|
|
608
|
-
def config(key, *tokens)
|
|
609
|
-
options = tokens.pop if Hash === tokens.last
|
|
610
|
-
options ||= {}
|
|
611
|
-
|
|
612
|
-
new_tokens = []
|
|
613
|
-
if workflow
|
|
614
|
-
workflow_name = workflow.to_s
|
|
615
|
-
new_tokens << ("workflow:" << workflow_name)
|
|
616
|
-
new_tokens << ("task:" << workflow_name << "#" << task_name.to_s)
|
|
617
|
-
end
|
|
618
|
-
new_tokens << ("task:" << task_name.to_s)
|
|
619
|
-
|
|
620
|
-
Rbbt::Config.get(key, tokens + new_tokens, options)
|
|
621
|
-
end
|
|
622
|
-
|
|
623
|
-
def access
|
|
624
|
-
CMD.cmd("touch -c -h -a #{self.path} #{self.info_file}")
|
|
625
|
-
end
|
|
626
|
-
|
|
627
|
-
def rec_access
|
|
628
|
-
access
|
|
629
|
-
rec_dependencies.each do |dep|
|
|
630
|
-
dep.access
|
|
631
|
-
end
|
|
632
|
-
end
|
|
633
|
-
|
|
634
|
-
def monitor_stream(stream, options = {}, &block)
|
|
635
|
-
case options[:bar]
|
|
636
|
-
when TrueClass
|
|
637
|
-
bar = progress_bar
|
|
638
|
-
when Hash
|
|
639
|
-
bar = progress_bar options[:bar]
|
|
640
|
-
when Numeric
|
|
641
|
-
bar = progress_bar :max => options[:bar]
|
|
642
|
-
else
|
|
643
|
-
bar = options[:bar]
|
|
644
|
-
end
|
|
645
|
-
|
|
646
|
-
out = if bar.nil?
|
|
647
|
-
Misc.line_monitor_stream stream, &block
|
|
648
|
-
elsif (block.nil? || block.arity == 0)
|
|
649
|
-
Misc.line_monitor_stream stream do
|
|
650
|
-
bar.tick
|
|
651
|
-
end
|
|
652
|
-
elsif block.arity == 1
|
|
653
|
-
Misc.line_monitor_stream stream do |line|
|
|
654
|
-
bar.tick
|
|
655
|
-
block.call line
|
|
656
|
-
end
|
|
657
|
-
elsif block.arity == 2
|
|
658
|
-
Misc.line_monitor_stream stream do |line|
|
|
659
|
-
block.call line, bar
|
|
660
|
-
end
|
|
661
|
-
end
|
|
662
|
-
|
|
663
|
-
ConcurrentStream.setup(out, :abort_callback => Proc.new{
|
|
664
|
-
Log::ProgressBar.remove_bar(bar, true) if bar
|
|
665
|
-
}, :callback => Proc.new{
|
|
666
|
-
Log::ProgressBar.remove_bar(bar) if bar
|
|
667
|
-
})
|
|
668
|
-
|
|
669
|
-
bgzip = (options[:compress] || options[:gzip]).to_s == 'bgzip'
|
|
670
|
-
bgzip = true if options[:bgzip]
|
|
671
|
-
|
|
672
|
-
gzip = true if options[:compress] || options[:gzip]
|
|
673
|
-
if bgzip
|
|
674
|
-
Open.bgzip(out)
|
|
675
|
-
elsif gzip
|
|
676
|
-
Open.gzip(out)
|
|
677
|
-
else
|
|
678
|
-
out
|
|
679
|
-
end
|
|
680
|
-
end
|
|
681
|
-
|
|
682
|
-
def relocated?
|
|
683
|
-
done? && info[:path] && info[:path] != path
|
|
684
|
-
end
|
|
685
|
-
|
|
686
|
-
def knowledge_base(organism = nil)
|
|
687
|
-
@_kb ||= begin
|
|
688
|
-
kb_dir = self.file('knowledge_base')
|
|
689
|
-
KnowledgeBase.new kb_dir, organism
|
|
690
|
-
end
|
|
691
|
-
end
|
|
692
|
-
|
|
693
|
-
end
|
|
694
16
|
|
|
695
17
|
module Workflow
|
|
696
18
|
|
|
@@ -1162,6 +484,4 @@ module Workflow
|
|
|
1162
484
|
def task_exports
|
|
1163
485
|
[exec_exports, synchronous_exports, asynchronous_exports, stream_exports].compact.flatten.uniq
|
|
1164
486
|
end
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
487
|
end
|