scout-gear 7.1.0 → 7.3.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.
- checksums.yaml +4 -4
- data/.vimproject +65 -2
- data/VERSION +1 -1
- data/bin/scout +5 -1
- data/lib/rbbt-scout.rb +5 -0
- data/lib/scout/concurrent_stream.rb +13 -8
- data/lib/scout/config.rb +168 -0
- data/lib/scout/exceptions.rb +5 -3
- data/lib/scout/indiferent_hash/options.rb +1 -0
- data/lib/scout/indiferent_hash.rb +4 -2
- data/lib/scout/log/color.rb +3 -2
- data/lib/scout/log/progress/report.rb +1 -0
- data/lib/scout/log/progress/util.rb +66 -1
- data/lib/scout/log/progress.rb +5 -3
- data/lib/scout/log.rb +3 -2
- data/lib/scout/misc/helper.rb +31 -0
- data/lib/scout/misc/monitor.rb +4 -1
- data/lib/scout/misc/system.rb +15 -0
- data/lib/scout/misc.rb +2 -0
- data/lib/scout/named_array.rb +68 -0
- data/lib/scout/open/stream.rb +58 -33
- data/lib/scout/path/find.rb +27 -3
- data/lib/scout/path/util.rb +7 -4
- data/lib/scout/persist/serialize.rb +7 -14
- data/lib/scout/persist.rb +46 -12
- data/lib/scout/resource/produce.rb +7 -94
- data/lib/scout/resource/software.rb +176 -0
- data/lib/scout/semaphore.rb +8 -1
- data/lib/scout/tsv/dumper.rb +112 -0
- data/lib/scout/tsv/index.rb +161 -0
- data/lib/scout/tsv/open.rb +128 -0
- data/lib/scout/tsv/parser.rb +230 -30
- data/lib/scout/tsv/path.rb +13 -0
- data/lib/scout/tsv/persist/adapter.rb +367 -0
- data/lib/scout/tsv/persist/fix_width_table.rb +324 -0
- data/lib/scout/tsv/persist/serialize.rb +117 -0
- data/lib/scout/tsv/persist/tokyocabinet.rb +113 -0
- data/lib/scout/tsv/persist.rb +13 -0
- data/lib/scout/tsv/traverse.rb +143 -0
- data/lib/scout/tsv/util/filter.rb +303 -0
- data/lib/scout/tsv/util/process.rb +73 -0
- data/lib/scout/tsv/util/select.rb +220 -0
- data/lib/scout/tsv/util.rb +82 -0
- data/lib/scout/tsv.rb +16 -3
- data/lib/scout/work_queue/worker.rb +4 -4
- data/lib/scout/work_queue.rb +22 -7
- data/lib/scout/workflow/definition.rb +101 -4
- data/lib/scout/workflow/step/config.rb +18 -0
- data/lib/scout/workflow/step/dependencies.rb +40 -0
- data/lib/scout/workflow/step/file.rb +15 -0
- data/lib/scout/workflow/step/info.rb +35 -4
- data/lib/scout/workflow/step/progress.rb +14 -0
- data/lib/scout/workflow/step/provenance.rb +148 -0
- data/lib/scout/workflow/step.rb +71 -17
- data/lib/scout/workflow/task.rb +10 -5
- data/lib/scout/workflow/usage.rb +3 -1
- data/lib/scout/workflow.rb +11 -3
- data/lib/scout-gear.rb +1 -0
- data/lib/scout.rb +1 -0
- data/scout-gear.gemspec +64 -10
- data/scout_commands/find +1 -1
- data/scout_commands/workflow/task +16 -9
- data/scout_commands/workflow/task_old +2 -2
- data/share/software/install_helpers +523 -0
- data/test/scout/log/test_progress.rb +0 -2
- data/test/scout/misc/test_system.rb +21 -0
- data/test/scout/open/test_stream.rb +160 -1
- data/test/scout/path/test_find.rb +14 -7
- data/test/scout/resource/test_software.rb +24 -0
- data/test/scout/test_config.rb +66 -0
- data/test/scout/test_meta_extension.rb +10 -0
- data/test/scout/test_named_array.rb +19 -0
- data/test/scout/test_persist.rb +96 -0
- data/test/scout/test_tmpfile.rb +1 -1
- data/test/scout/test_tsv.rb +50 -1
- data/test/scout/test_work_queue.rb +41 -13
- data/test/scout/tsv/persist/test_adapter.rb +44 -0
- data/test/scout/tsv/persist/test_fix_width_table.rb +134 -0
- data/test/scout/tsv/persist/test_tokyocabinet.rb +92 -0
- data/test/scout/tsv/test_dumper.rb +44 -0
- data/test/scout/tsv/test_index.rb +156 -0
- data/test/scout/tsv/test_open.rb +9 -0
- data/test/scout/tsv/test_parser.rb +114 -3
- data/test/scout/tsv/test_persist.rb +43 -0
- data/test/scout/tsv/test_traverse.rb +116 -0
- data/test/scout/tsv/test_util.rb +23 -0
- data/test/scout/tsv/util/test_filter.rb +188 -0
- data/test/scout/tsv/util/test_process.rb +47 -0
- data/test/scout/tsv/util/test_select.rb +44 -0
- data/test/scout/work_queue/test_worker.rb +66 -9
- data/test/scout/workflow/step/test_dependencies.rb +25 -0
- data/test/scout/workflow/step/test_info.rb +15 -17
- data/test/scout/workflow/step/test_load.rb +19 -21
- data/test/scout/workflow/step/test_provenance.rb +25 -0
- data/test/scout/workflow/test_step.rb +206 -10
- data/test/scout/workflow/test_task.rb +0 -3
- data/test/test_helper.rb +9 -1
- metadata +50 -6
@@ -21,27 +21,27 @@ class WorkQueue
|
|
21
21
|
raise obj
|
22
22
|
end
|
23
23
|
res = block.call obj
|
24
|
-
output.write res unless
|
24
|
+
output.write res unless ignore_ouput || res == :ignore
|
25
25
|
end
|
26
26
|
rescue DoneProcessing
|
27
27
|
rescue Interrupt
|
28
28
|
rescue Exception
|
29
29
|
output.write WorkerException.new($!, Process.pid)
|
30
|
-
exit -1
|
30
|
+
Kernel.exit -1
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
35
|
def abort
|
36
36
|
begin
|
37
|
-
Log.
|
37
|
+
Log.debug "Aborting worker #{@pid}"
|
38
38
|
Process.kill "INT", @pid
|
39
39
|
rescue Errno::ECHILD
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
43
|
def join
|
44
|
-
Log.
|
44
|
+
Log.debug "Joining worker #{@pid}"
|
45
45
|
Process.waitpid @pid
|
46
46
|
end
|
47
47
|
|
data/lib/scout/work_queue.rb
CHANGED
@@ -36,8 +36,12 @@ class WorkQueue
|
|
36
36
|
|
37
37
|
def remove_worker(pid)
|
38
38
|
@worker_mutex.synchronize do
|
39
|
-
@workers.
|
40
|
-
|
39
|
+
worker = @workers.index{|w| w.pid == pid}
|
40
|
+
if worker
|
41
|
+
Log.debug "Removed worker #{pid}"
|
42
|
+
@workers.delete_at(worker)
|
43
|
+
@removed_workers << pid
|
44
|
+
end
|
41
45
|
end
|
42
46
|
end
|
43
47
|
|
@@ -50,11 +54,13 @@ class WorkQueue
|
|
50
54
|
while true
|
51
55
|
obj = @output.read
|
52
56
|
if DoneProcessing === obj
|
57
|
+
|
53
58
|
done = @worker_mutex.synchronize do
|
54
59
|
Log.low "Worker #{obj.pid} done"
|
55
60
|
@done_workers << obj.pid
|
56
|
-
@done_workers.length == @removed_workers.length + @workers.length
|
61
|
+
@closed && @done_workers.length == @removed_workers.length + @workers.length
|
57
62
|
end
|
63
|
+
|
58
64
|
break if done
|
59
65
|
elsif Exception === obj
|
60
66
|
raise obj
|
@@ -65,9 +71,13 @@ class WorkQueue
|
|
65
71
|
rescue DoneProcessing
|
66
72
|
rescue Aborted
|
67
73
|
rescue WorkerException
|
68
|
-
Log.error "Exception in worker #{obj.pid} #{
|
74
|
+
Log.error "Exception in worker #{obj.pid} in queue #{Process.pid}: #{obj.message}"
|
69
75
|
self.abort
|
70
|
-
raise obj.
|
76
|
+
raise obj.worker_exception
|
77
|
+
rescue
|
78
|
+
Log.error "Exception processing output in queue #{Process.pid}: #{$!.message}"
|
79
|
+
self.abort
|
80
|
+
raise $!
|
71
81
|
end
|
72
82
|
end
|
73
83
|
|
@@ -84,11 +94,12 @@ class WorkQueue
|
|
84
94
|
while true
|
85
95
|
pid = Process.wait
|
86
96
|
remove_worker(pid)
|
87
|
-
break if workers.empty?
|
97
|
+
break if @worker_mutex.synchronize{ @workers.empty? }
|
88
98
|
end
|
89
99
|
end
|
90
100
|
end
|
91
101
|
|
102
|
+
Thread.pass until @worker_mutex.synchronize{ @workers.select{|w| w.pid.nil? }.empty? }
|
92
103
|
Thread.pass until @waiter["name"]
|
93
104
|
end
|
94
105
|
|
@@ -97,10 +108,14 @@ class WorkQueue
|
|
97
108
|
end
|
98
109
|
|
99
110
|
def abort
|
100
|
-
workers.
|
111
|
+
Log.low "Aborting #{@workers.length} workers in queue #{Process.pid}"
|
112
|
+
@worker_mutex.synchronize do
|
113
|
+
@workers.each{|w| w.abort }
|
114
|
+
end
|
101
115
|
end
|
102
116
|
|
103
117
|
def close
|
118
|
+
@closed = true
|
104
119
|
@worker_mutex.synchronize{ @workers.length }.times do
|
105
120
|
@input.write DoneProcessing.new()
|
106
121
|
end
|
@@ -2,7 +2,7 @@ require_relative '../meta_extension'
|
|
2
2
|
|
3
3
|
module Workflow
|
4
4
|
extend MetaExtension
|
5
|
-
extension_attr :name, :tasks
|
5
|
+
extension_attr :name, :tasks, :helpers
|
6
6
|
|
7
7
|
class << self
|
8
8
|
attr_accessor :directory
|
@@ -17,6 +17,32 @@ module Workflow
|
|
17
17
|
@name ||= self.to_s
|
18
18
|
end
|
19
19
|
|
20
|
+
def helpers
|
21
|
+
@helpers ||= {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def helper(name, *args, &block)
|
25
|
+
if block_given?
|
26
|
+
helpers[name] = block
|
27
|
+
else
|
28
|
+
raise RbbtException, "helper #{name} unkown in #{self} workflow" unless helpers[name]
|
29
|
+
helpers[name].call(*args)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def step_module
|
34
|
+
@_m ||= begin
|
35
|
+
m = Module.new
|
36
|
+
|
37
|
+
helpers.each do |name,block|
|
38
|
+
m.send(:define_method, name, &block)
|
39
|
+
end
|
40
|
+
|
41
|
+
m
|
42
|
+
end
|
43
|
+
@_m
|
44
|
+
end
|
45
|
+
|
20
46
|
attr_accessor :directory
|
21
47
|
def directory
|
22
48
|
@directory ||= Workflow.directory[name]
|
@@ -60,19 +86,90 @@ module Workflow
|
|
60
86
|
annotate_next_task(:inputs, args)
|
61
87
|
end
|
62
88
|
|
89
|
+
def desc(description)
|
90
|
+
annotate_next_task_single(:description, description)
|
91
|
+
end
|
92
|
+
|
93
|
+
def returns(type)
|
94
|
+
annotate_next_task_single(:returns, type)
|
95
|
+
end
|
96
|
+
|
97
|
+
def extension(extension)
|
98
|
+
annotate_next_task_single(:extension, extension)
|
99
|
+
end
|
100
|
+
|
63
101
|
def task(name_and_type, &block)
|
64
102
|
name, type = name_and_type.collect.first
|
65
103
|
@tasks ||= IndiferentHash.setup({})
|
66
104
|
begin
|
67
105
|
@annotate_next_task ||= {}
|
68
|
-
task = Task.setup(block, @annotate_next_task.merge(name: name, type: type, directory: directory[name]))
|
106
|
+
task = Task.setup(block, @annotate_next_task.merge(name: name, type: type, directory: directory[name], workflow: self))
|
69
107
|
@tasks[name] = task
|
70
108
|
ensure
|
71
109
|
@annotate_next_task = {}
|
72
110
|
end
|
73
111
|
end
|
74
112
|
|
75
|
-
def
|
76
|
-
|
113
|
+
def task_alias(name, workflow, oname, *rest, &block)
|
114
|
+
dep(workflow, oname, *rest, &block)
|
115
|
+
extension :dep_task unless @extension
|
116
|
+
returns workflow.tasks[oname].returns if workflow.tasks.include?(oname) unless @returns
|
117
|
+
task name => nil do
|
118
|
+
raise RbbtException, "dep_task does not have any dependencies" if dependencies.empty?
|
119
|
+
Step.wait_for_jobs dependencies.select{|d| d.streaming? }
|
120
|
+
dep = dependencies.last
|
121
|
+
dep.join
|
122
|
+
raise dep.get_exception if dep.error?
|
123
|
+
raise Aborted, "Aborted dependency #{dep.path}" if dep.aborted?
|
124
|
+
set_info :result_type, dep.info[:result_type]
|
125
|
+
forget = config :forget_dep_tasks, "forget_dep_tasks", :default => FORGET_DEP_TASKS
|
126
|
+
if forget
|
127
|
+
remove = config :remove_dep_tasks, "remove_dep_tasks", :default => REMOVE_DEP_TASKS
|
128
|
+
|
129
|
+
self.archive_deps
|
130
|
+
self.copy_files_dir
|
131
|
+
self.dependencies = self.dependencies - [dep]
|
132
|
+
Open.rm_rf self.files_dir if Open.exist? self.files_dir
|
133
|
+
FileUtils.cp_r dep.files_dir, self.files_dir if Open.exist?(dep.files_dir)
|
134
|
+
|
135
|
+
if dep.overriden || ! Workflow.job_path?(dep.path)
|
136
|
+
Open.link dep.path, self.tmp_path
|
137
|
+
else
|
138
|
+
Open.ln_h dep.path, self.tmp_path
|
139
|
+
|
140
|
+
case remove.to_s
|
141
|
+
when 'true'
|
142
|
+
dep.clean
|
143
|
+
when 'recursive'
|
144
|
+
(dep.dependencies + dep.rec_dependencies).uniq.each do |d|
|
145
|
+
next if d.overriden
|
146
|
+
d.clean unless config(:remove_dep, d.task_signature, d.task_name, d.workflow.to_s, :default => true).to_s == 'false'
|
147
|
+
end
|
148
|
+
dep.clean unless config(:remove_dep, dep.task_signature, dep.task_name, dep.workflow.to_s, :default => true).to_s == 'false'
|
149
|
+
end
|
150
|
+
end
|
151
|
+
else
|
152
|
+
if Open.exists?(dep.files_dir)
|
153
|
+
Open.rm_rf self.files_dir
|
154
|
+
Open.link dep.files_dir, self.files_dir
|
155
|
+
end
|
156
|
+
if defined?(RemoteStep) && RemoteStep === dep
|
157
|
+
Open.write(self.tmp_path, Open.read(dep.path))
|
158
|
+
else
|
159
|
+
Open.link dep.path, self.path
|
160
|
+
end
|
161
|
+
end
|
162
|
+
nil
|
163
|
+
end
|
77
164
|
end
|
165
|
+
|
166
|
+
alias dep_task task_alias
|
167
|
+
|
168
|
+
def export(*args)
|
169
|
+
end
|
170
|
+
|
171
|
+
alias export_synchronous export
|
172
|
+
alias export_asynchronous export
|
173
|
+
alias export_exec export
|
174
|
+
alias export_stream export
|
78
175
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative '../../config'
|
2
|
+
|
3
|
+
class Step
|
4
|
+
def config(key, *tokens)
|
5
|
+
options = tokens.pop if Hash === tokens.last
|
6
|
+
options ||= {}
|
7
|
+
|
8
|
+
new_tokens = []
|
9
|
+
if workflow
|
10
|
+
workflow_name = workflow.to_s
|
11
|
+
new_tokens << ("workflow:" << workflow_name)
|
12
|
+
new_tokens << ("task:" << workflow_name << "#" << task_name.to_s)
|
13
|
+
end
|
14
|
+
new_tokens << ("task:" << task_name.to_s)
|
15
|
+
|
16
|
+
Scout::Config.get(key, tokens + new_tokens, options)
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Step
|
2
|
+
def recursive_inputs
|
3
|
+
dependencies.inject(@inputs.annotate(@inputs.dup)) do |acc,dep|
|
4
|
+
acc.concat(dep.inputs) if dep.inputs
|
5
|
+
acc
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def input_dependencies
|
10
|
+
return [] unless inputs
|
11
|
+
inputs.select do |d|
|
12
|
+
Step === d
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def prepare_dependencies
|
17
|
+
inverse_dep = {}
|
18
|
+
dependencies.each{|dep|
|
19
|
+
next if dep.done?
|
20
|
+
if dep.dependencies
|
21
|
+
dep.dependencies.each do |d|
|
22
|
+
inverse_dep[d] ||= []
|
23
|
+
inverse_dep[d] << dep
|
24
|
+
end
|
25
|
+
end
|
26
|
+
input_dependencies.each do |d|
|
27
|
+
inverse_dep[d] ||= []
|
28
|
+
inverse_dep[d] << dep
|
29
|
+
end
|
30
|
+
}
|
31
|
+
inverse_dep.each do |dep,list|
|
32
|
+
dep.tee_copies = list.length
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def run_dependencies
|
37
|
+
dependencies.each{|dep| dep.run unless dep.running? || dep.done? }
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class Step
|
2
|
-
SERIALIZER = :
|
2
|
+
SERIALIZER = :marshal
|
3
3
|
def info_file
|
4
4
|
@info_file ||= begin
|
5
5
|
info_file = @path + ".info"
|
@@ -20,7 +20,11 @@ class Step
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def info
|
23
|
-
outdated =
|
23
|
+
outdated = begin
|
24
|
+
@info_load_time && (mtime = Open.mtime(info_file)) && mtime > @info_load_time
|
25
|
+
rescue
|
26
|
+
true
|
27
|
+
end
|
24
28
|
|
25
29
|
if @info.nil? || outdated
|
26
30
|
load_info
|
@@ -33,6 +37,19 @@ class Step
|
|
33
37
|
info = self.info
|
34
38
|
new_info.each do |key,value|
|
35
39
|
report_status new_info[:status], new_info[:message] if key == :status
|
40
|
+
if Exception === value
|
41
|
+
begin
|
42
|
+
Marshal.dump(value)
|
43
|
+
rescue TypeError
|
44
|
+
if ScoutException === value
|
45
|
+
new = ScoutException.new value.message
|
46
|
+
else
|
47
|
+
new = Exception.new value.message
|
48
|
+
end
|
49
|
+
new.set_backtrace(value.backtrace)
|
50
|
+
value = new
|
51
|
+
end
|
52
|
+
end
|
36
53
|
if info.include?(key)
|
37
54
|
case info[key]
|
38
55
|
when Array
|
@@ -62,7 +79,6 @@ class Step
|
|
62
79
|
end
|
63
80
|
|
64
81
|
def log(status, message = nil)
|
65
|
-
report_status status, message
|
66
82
|
if message
|
67
83
|
merge_info :status => status, :messages => [message]
|
68
84
|
else
|
@@ -71,7 +87,22 @@ class Step
|
|
71
87
|
end
|
72
88
|
|
73
89
|
def status
|
74
|
-
info[:status]
|
90
|
+
info[:status].tap{|s| s.nil? ? s : s.to_sym }
|
75
91
|
end
|
76
92
|
|
93
|
+
def error?
|
94
|
+
status == :error
|
95
|
+
end
|
96
|
+
|
97
|
+
def aborted?
|
98
|
+
status == :aborted
|
99
|
+
end
|
100
|
+
|
101
|
+
def running?
|
102
|
+
! done? && (info[:pid] && Misc.pid_alive?(info[:pid]))
|
103
|
+
end
|
104
|
+
|
105
|
+
def exception
|
106
|
+
info[:exception]
|
107
|
+
end
|
77
108
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Step
|
2
|
+
def progress_bar(msg = "Progress", options = nil)
|
3
|
+
if Hash === msg and options.nil?
|
4
|
+
options = msg
|
5
|
+
msg = nil
|
6
|
+
end
|
7
|
+
options = {} if options.nil?
|
8
|
+
|
9
|
+
max = options[:max]
|
10
|
+
Open.mkdir files_dir
|
11
|
+
Log::ProgressBar.new_bar(max, {:desc => msg, :file => (@exec ? nil : file(:progress))}.merge(options))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,148 @@
|
|
1
|
+
class Step
|
2
|
+
def self.job_path?(path)
|
3
|
+
path.split("/")[-4] == "jobs"
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.status_color(status)
|
7
|
+
case status.to_sym
|
8
|
+
when :error, :aborted, :missing, :dead, :unsync
|
9
|
+
:red
|
10
|
+
when :streaming, :started
|
11
|
+
:cyan
|
12
|
+
when :done, :noinfo
|
13
|
+
:green
|
14
|
+
when :dependencies, :waiting, :setup
|
15
|
+
:yellow
|
16
|
+
when :notfound, :cleaned
|
17
|
+
:blue
|
18
|
+
else
|
19
|
+
if status.to_s.index ">"
|
20
|
+
:cyan
|
21
|
+
else
|
22
|
+
:cyan
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.prov_status_msg(status)
|
28
|
+
color = status_color(status)
|
29
|
+
Log.color(color, status.to_s)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.prov_report_msg(status, name, path, info, input = nil)
|
33
|
+
parts = path.sub(/\{.*/,'').split "/"
|
34
|
+
|
35
|
+
parts.pop
|
36
|
+
|
37
|
+
task = Log.color(:yellow, parts.pop)
|
38
|
+
workflow = Log.color(:magenta, parts.pop)
|
39
|
+
|
40
|
+
if ! Step.job_path?(path)
|
41
|
+
task, status, workflow = Log.color(:yellow, info[:task_name]), Log.color(:green, "file"), Log.color(:magenta, "-")
|
42
|
+
end
|
43
|
+
|
44
|
+
path_mtime = begin
|
45
|
+
Open.mtime(path)
|
46
|
+
rescue Exception
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
if input.nil? || input.empty?
|
51
|
+
input_str = nil
|
52
|
+
else
|
53
|
+
input = input.reject{|dep,name| (input & dep.dependencies.collect{|d| [d,name]}).any? }
|
54
|
+
input = input.reject{|dep,name| (input & dep.input_dependencies.collect{|d| [d,name]}).any? }
|
55
|
+
input_str = Log.color(:magenta, "-> ") + input.collect{|dep,name| Log.color(:yellow, dep.task_name.to_s) + ":" + Log.color(:yellow, name) }.uniq * " "
|
56
|
+
end
|
57
|
+
|
58
|
+
str = if ! (Open.remote?(path) || Open.ssh?(path)) && (Open.exists?(path) && $main_mtime && path_mtime && ($main_mtime - path_mtime) < -2)
|
59
|
+
prov_status_msg(status.to_s) << " " << [workflow, task, path, input_str].compact * " " << " (#{Log.color(:red, "Mtime out of sync") })"
|
60
|
+
else
|
61
|
+
prov_status_msg(status.to_s) << " " << [workflow, task, path, input_str].compact * " "
|
62
|
+
end
|
63
|
+
|
64
|
+
if $inputs and $inputs.any?
|
65
|
+
job_inputs = Workflow.load_step(path).recursive_inputs.to_hash
|
66
|
+
IndiferentHash.setup(job_inputs)
|
67
|
+
|
68
|
+
$inputs.each do |input|
|
69
|
+
value = job_inputs[input]
|
70
|
+
next if value.nil?
|
71
|
+
value_str = Misc.fingerprint(value)
|
72
|
+
str << "\t#{Log.color :magenta, input}=#{value_str}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
if $info_fields and $info_fields.any?
|
77
|
+
$info_fields.each do |field|
|
78
|
+
IndiferentHash.setup(info)
|
79
|
+
value = info[field]
|
80
|
+
next if value.nil?
|
81
|
+
value_str = Misc.fingerprint(value)
|
82
|
+
str << "\t#{Log.color :magenta, field}=#{value_str}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
str << "\n"
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.prov_report(step, offset = 0, task = nil, seen = [], expand_repeats = false, input = nil)
|
90
|
+
info = step.info || {}
|
91
|
+
info[:task_name] = task
|
92
|
+
path = step.path
|
93
|
+
status = info[:status] || :missing
|
94
|
+
status = "remote" if Open.remote?(path) || Open.ssh?(path)
|
95
|
+
name = info[:name] || File.basename(path)
|
96
|
+
status = :unsync if status == :done and not Open.exist?(path)
|
97
|
+
status = :notfound if status == :noinfo and not Open.exist?(path)
|
98
|
+
|
99
|
+
|
100
|
+
this_step_msg = prov_report_msg(status, name, path, info, input)
|
101
|
+
|
102
|
+
input_dependencies = {}
|
103
|
+
step.dependencies.each do |dep|
|
104
|
+
if dep.input_dependencies.any?
|
105
|
+
dep.input_dependencies.each do |id|
|
106
|
+
input_name, _dep = dep.recursive_inputs.fields.zip(dep.recursive_inputs).select{|f,d|
|
107
|
+
d == id || (String === d && d.start_with?(id.files_dir)) || (Array === d && d.include?(id))
|
108
|
+
}.last
|
109
|
+
if input_name
|
110
|
+
input_dependencies[id] ||= []
|
111
|
+
input_dependencies[id] << [dep, input_name]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end if step.dependencies
|
116
|
+
|
117
|
+
str = ""
|
118
|
+
str = " " * offset + this_step_msg if ENV["RBBT_ORIGINAL_STACK"] == 'true'
|
119
|
+
|
120
|
+
step.dependencies.dup.tap{|l|
|
121
|
+
l.reverse! if ENV["RBBT_ORIGINAL_STACK"] == 'true'
|
122
|
+
}.each do |dep|
|
123
|
+
path = dep.path
|
124
|
+
new = ! seen.include?(path)
|
125
|
+
if new
|
126
|
+
seen << path
|
127
|
+
str << prov_report(dep, offset + 1, task, seen, expand_repeats, input_dependencies[dep])
|
128
|
+
else
|
129
|
+
if expand_repeats
|
130
|
+
str << Log.color(Step.status_color(dep.status), Log.uncolor(prov_report(dep, offset+1, task)))
|
131
|
+
else
|
132
|
+
info = dep.info || {}
|
133
|
+
status = info[:status] || :missing
|
134
|
+
status = "remote" if Open.remote?(path) || Open.ssh?(path)
|
135
|
+
name = info[:name] || File.basename(path)
|
136
|
+
status = :unsync if status == :done and not Open.exist?(path)
|
137
|
+
status = :notfound if status == :noinfo and not Open.exist?(path)
|
138
|
+
|
139
|
+
str << Log.color(Step.status_color(status), " " * (offset + 1) + Log.uncolor(prov_report_msg(status, name, path, info, input_dependencies[dep])))
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end if step.dependencies
|
143
|
+
|
144
|
+
str += (" " * offset) + this_step_msg unless ENV["RBBT_ORIGINAL_STACK"] == 'true'
|
145
|
+
|
146
|
+
str
|
147
|
+
end
|
148
|
+
end
|