rbbt-util 5.30.3 → 5.30.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rbbt/hpc/orchestrate.rb +111 -26
- data/lib/rbbt/hpc/slurm.rb +21 -11
- data/lib/rbbt/persist.rb +1 -1
- data/lib/rbbt/resource/path.rb +8 -2
- data/lib/rbbt/tsv/manipulate.rb +1 -1
- data/lib/rbbt/util/open.rb +3 -1
- data/lib/rbbt/workflow.rb +2 -2
- data/lib/rbbt/workflow/accessor.rb +4 -4
- data/lib/rbbt/workflow/examples.rb +5 -1
- data/lib/rbbt/workflow/remote_workflow/remote_step.rb +5 -0
- data/lib/rbbt/workflow/step.rb +13 -6
- data/lib/rbbt/workflow/step/accessor.rb +11 -1
- data/lib/rbbt/workflow/step/run.rb +11 -6
- data/lib/rbbt/workflow/usage.rb +1 -1
- data/lib/rbbt/workflow/util/archive.rb +1 -1
- data/lib/rbbt/workflow/util/provenance.rb +9 -1
- data/share/Rlib/util.R +8 -2
- data/share/rbbt_commands/migrate +1 -1
- data/share/rbbt_commands/slurm/list +33 -6
- data/share/rbbt_commands/workflow/server +9 -5
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: be64e4af9e06d88f1188ab447f63ea37296d562663ed05945de890d4addd4ce1
|
4
|
+
data.tar.gz: c3c984994184f2b980dfb699b5809d88f41eda8f16201c5c403a20850fc4e9e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd1e8251c15b80c44c36e9b270db74aa1aadcc2d2c01ed1b613e715a0b1cc3ca23ecd4d936afd37697de1c1dbb476afd0efecf57a2ddefbbddec5eb81a902ff6
|
7
|
+
data.tar.gz: 33e7e4a1c9a22c9900da0dbb2e4530c4b360fc3ef2f3b3abb8fbc72fd657f4d10f63d1064e721c227b7900760b98e6d98acbc776e4cf476107635c96d64bd006
|
data/lib/rbbt/hpc/orchestrate.rb
CHANGED
@@ -5,7 +5,10 @@ module HPC
|
|
5
5
|
def self.job_rules(rules, job)
|
6
6
|
workflow = job.workflow.to_s
|
7
7
|
task_name = job.task_name.to_s
|
8
|
+
task_name = job.overriden.to_s if Symbol === job.overriden
|
9
|
+
|
8
10
|
defaults = rules["defaults"] || {}
|
11
|
+
defaults = defaults.merge(rules[workflow]["defaults"] || {}) if rules[workflow]
|
9
12
|
|
10
13
|
job_rules = IndiferentHash.setup(defaults.dup)
|
11
14
|
|
@@ -50,47 +53,88 @@ module HPC
|
|
50
53
|
job_rules
|
51
54
|
end
|
52
55
|
|
53
|
-
def self.get_job_dependencies(job, job_rules)
|
56
|
+
def self.get_job_dependencies(job, job_rules = nil)
|
54
57
|
deps = job.dependencies || []
|
55
58
|
deps += job.input_dependencies || []
|
56
59
|
deps
|
57
60
|
end
|
58
61
|
|
59
|
-
def self.
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
options.delete "recursive_clean"
|
65
|
-
options.delete "clean_task"
|
66
|
-
options.delete "clean"
|
67
|
-
options.delete "tail"
|
68
|
-
options.delete "printfile"
|
69
|
-
options.delete "detach"
|
62
|
+
def self.get_recursive_job_dependencies(job)
|
63
|
+
deps = get_job_dependencies(job)
|
64
|
+
(deps + deps.collect{|dep| get_recursive_job_dependencies(dep) }).flatten
|
65
|
+
end
|
70
66
|
|
71
|
-
|
72
|
-
|
73
|
-
|
67
|
+
def self.piggyback(job, job_rules, job_deps)
|
68
|
+
return false unless job_rules["skip"]
|
69
|
+
final_deps = job_deps - job_deps.collect{|dep| get_recursive_job_dependencies(dep)}.flatten.uniq
|
70
|
+
return final_deps.first if final_deps.length == 1
|
71
|
+
return false
|
72
|
+
end
|
74
73
|
|
74
|
+
def self.get_chains(job, rules, chains = {})
|
75
75
|
job_rules = self.job_rules(rules, job)
|
76
|
+
job_deps = get_job_dependencies(job)
|
77
|
+
|
78
|
+
input_deps = []
|
79
|
+
job.rec_dependencies.each do |dep|
|
80
|
+
input_deps.concat dep.input_dependencies
|
81
|
+
end
|
76
82
|
|
77
|
-
|
83
|
+
job_deps.each do |dep|
|
84
|
+
input_deps.concat dep.input_dependencies
|
85
|
+
get_chains(dep, rules, chains)
|
86
|
+
end
|
78
87
|
|
79
|
-
|
80
|
-
|
88
|
+
job_deps.select do |dep|
|
89
|
+
chained = job_rules["chain_tasks"] &&
|
81
90
|
job_rules["chain_tasks"][job.workflow.to_s] && job_rules["chain_tasks"][job.workflow.to_s].include?(job.task_name.to_s) &&
|
82
91
|
job_rules["chain_tasks"][dep.workflow.to_s] && job_rules["chain_tasks"][dep.workflow.to_s].include?(dep.task_name.to_s)
|
83
92
|
|
84
|
-
|
85
|
-
|
86
|
-
|
93
|
+
dep_skip = dep.done? && ! input_deps.include?(dep) && self.job_rules(rules, dep)["skip"]
|
94
|
+
chained || dep_skip
|
95
|
+
end.each do |dep|
|
96
|
+
chains[job] ||= []
|
97
|
+
chains[job] << dep
|
98
|
+
chains[job].concat chains[dep] if chains[dep]
|
99
|
+
end
|
100
|
+
|
101
|
+
chains
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.workload(job, rules, chains, options, seen = nil)
|
105
|
+
return [] if job.done?
|
106
|
+
if seen.nil?
|
107
|
+
seen = {}
|
108
|
+
target_job = true
|
109
|
+
end
|
110
|
+
|
111
|
+
job_rules = self.job_rules(rules, job)
|
112
|
+
job_deps = get_job_dependencies(job)
|
113
|
+
|
114
|
+
|
115
|
+
chain = chains[job]
|
116
|
+
chain -= seen.keys if chain
|
117
|
+
piggyback = piggyback(job, job_rules, job_deps)
|
118
|
+
dep_ids = job_deps.collect do |dep|
|
119
|
+
seen[dep] = nil if chain && chain.include?(dep) #&& ! job.input_dependencies.include?(dep)
|
120
|
+
next_options = IndiferentHash.setup(options.dup)
|
121
|
+
if piggyback and piggyback == dep
|
122
|
+
next_options[:piggyback] ||= []
|
123
|
+
next_options[:piggyback].push job
|
124
|
+
ids = workload(dep, rules, chains, next_options, seen)
|
87
125
|
else
|
88
|
-
|
126
|
+
next_options.delete :piggyback
|
127
|
+
ids = workload(dep, rules, chains, next_options, seen)
|
89
128
|
end
|
90
|
-
end.flatten.compact.uniq
|
91
129
|
|
92
|
-
|
93
|
-
|
130
|
+
ids = [ids].flatten.compact.collect{|id| ['canfail', id] * ":"} if job.canfail_paths.include? dep.path
|
131
|
+
|
132
|
+
seen[dep] = ids
|
133
|
+
ids
|
134
|
+
end.compact.flatten.uniq
|
135
|
+
|
136
|
+
return seen[job] || dep_ids if seen.include?(job)
|
137
|
+
return seen[piggyback] if piggyback
|
94
138
|
|
95
139
|
job_rules.delete :chain_tasks
|
96
140
|
job_rules.delete :tasks
|
@@ -105,7 +149,48 @@ module HPC
|
|
105
149
|
job_options[:config_keys] = job_options[:config_keys] ? config_keys + "," + job_options[:config_keys] : config_keys
|
106
150
|
end
|
107
151
|
|
108
|
-
|
152
|
+
|
153
|
+
if options[:piggyback]
|
154
|
+
manifest = options[:piggyback].uniq
|
155
|
+
manifest += [job]
|
156
|
+
manifest.concat chain if chain
|
157
|
+
job = options[:piggyback].first
|
158
|
+
job_options.delete :piggyback
|
159
|
+
else
|
160
|
+
manifest = [job]
|
161
|
+
manifest.concat chain if chain
|
162
|
+
end
|
163
|
+
|
164
|
+
manifest.uniq!
|
165
|
+
|
166
|
+
job_options[:manifest] = manifest.collect{|j| j.workflow_short_path }
|
167
|
+
|
168
|
+
if options[:dry_run]
|
169
|
+
puts Log.color(:magenta, "Manifest: ") + Log.color(:blue, job_options[:manifest] * ", ") + " - tasks: #{job_options[:task_cpus] || 1} - time: #{job_options[:time]} - config: #{job_options[:config_keys]}"
|
170
|
+
puts Log.color(:yellow, "Deps: ") + Log.color(:blue, job_options[:slurm_dependencies]*", ")
|
171
|
+
job_options[:manifest].first
|
172
|
+
else
|
173
|
+
run_job(job, job_options)
|
174
|
+
end
|
109
175
|
end
|
176
|
+
|
177
|
+
|
178
|
+
def self.orchestrate_job(job, options)
|
179
|
+
options.delete "recursive_clean"
|
180
|
+
options.delete "clean_task"
|
181
|
+
options.delete "clean"
|
182
|
+
options.delete "tail"
|
183
|
+
options.delete "printfile"
|
184
|
+
options.delete "detach"
|
185
|
+
|
186
|
+
rules = YAML.load(Open.read(options[:orchestration_rules])) if options[:orchestration_rules]
|
187
|
+
rules ||= {}
|
188
|
+
IndiferentHash.setup(rules)
|
189
|
+
|
190
|
+
chains = get_chains(job, rules)
|
191
|
+
|
192
|
+
workload(job, rules, chains, options)
|
193
|
+
end
|
194
|
+
|
110
195
|
end
|
111
196
|
end
|
data/lib/rbbt/hpc/slurm.rb
CHANGED
@@ -21,10 +21,12 @@ module HPC
|
|
21
21
|
exclusive = options.delete :exclusive
|
22
22
|
highmem = options.delete :highmem
|
23
23
|
|
24
|
-
|
24
|
+
manifest = options.delete :manifest
|
25
|
+
|
26
|
+
queue = options.delete(:queue) || Rbbt::Config.get('queue', :slurm_queue, :slurm, :SLURM, :default => 'bsc_ls')
|
25
27
|
task_cpus = options.delete(:task_cpus) || 1
|
26
28
|
nodes = options.delete(:nodes) || 1
|
27
|
-
time = options.delete(:time) || "0:00
|
29
|
+
time = options.delete(:time) || "0:02:00"
|
28
30
|
|
29
31
|
inputs_dir = options.delete :inputs_dir
|
30
32
|
config_keys = options.delete :config_keys
|
@@ -258,6 +260,10 @@ EOF
|
|
258
260
|
workflow write_info --recursive --force=false --check_pid "$step_path" slurm_job $SLURM_JOB_ID
|
259
261
|
EOF
|
260
262
|
|
263
|
+
header +=<<-EOF if manifest
|
264
|
+
#MANIFEST: #{manifest * ", "}
|
265
|
+
EOF
|
266
|
+
|
261
267
|
header +=<<-EOF
|
262
268
|
#CMD: #{rbbt_cmd}
|
263
269
|
EOF
|
@@ -301,11 +307,15 @@ EOF
|
|
301
307
|
coda +=<<-EOF
|
302
308
|
|
303
309
|
# Sync data to target location
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
310
|
+
if [ $exit_status == '0' ]; then
|
311
|
+
mkdir -p "$(dirname '#{target}')"
|
312
|
+
rsync -avztAXHP --copy-unsafe-links "#{source}/" "#{target}/" &>> #{fsync}
|
313
|
+
sync_es="$?"
|
314
|
+
echo $sync_es > #{fsyncexit}
|
315
|
+
find '#{target}' -type l -ls | awk '$13 ~ /^#{target.gsub('/','\/')}/ { sub("#{source}", "#{target}", $13); print $11, $13 }' | while read A B; do rm $A; ln -s $B $A; done
|
316
|
+
else
|
317
|
+
sync_es="$exit_status"
|
318
|
+
fi
|
309
319
|
EOF
|
310
320
|
|
311
321
|
if contain && (wipe_container == "post" || wipe_container == "both")
|
@@ -331,11 +341,11 @@ EOF
|
|
331
341
|
else
|
332
342
|
coda +=<<-EOF
|
333
343
|
##{exec_cmd} system clean
|
334
|
-
if [ $exit_status == '0' -a $sync_es == '0' ]; then
|
344
|
+
#if [ $exit_status == '0' -a $sync_es == '0' ]; then
|
335
345
|
rm -Rfv #{contain} &>> #{fsync}
|
336
|
-
else
|
337
|
-
echo "ERROR: Process failed or results could not sync correctly. Contain directory not purged" &>> #{fsync}
|
338
|
-
fi
|
346
|
+
#else
|
347
|
+
# echo "ERROR: Process failed or results could not sync correctly. Contain directory not purged" &>> #{fsync}
|
348
|
+
#fi
|
339
349
|
EOF
|
340
350
|
|
341
351
|
end
|
data/lib/rbbt/persist.rb
CHANGED
data/lib/rbbt/resource/path.rb
CHANGED
@@ -218,7 +218,14 @@ module Path
|
|
218
218
|
|
219
219
|
else
|
220
220
|
where = where.to_sym
|
221
|
-
|
221
|
+
|
222
|
+
if paths.include? where
|
223
|
+
path = paths[where]
|
224
|
+
elsif where.to_s.include?("/")
|
225
|
+
path = where.to_s
|
226
|
+
else
|
227
|
+
raise "Did not recognize the 'where' tag: #{where}. Options: #{paths.keys}" unless paths.include? where
|
228
|
+
end
|
222
229
|
|
223
230
|
if where == :lib
|
224
231
|
libdir = @libdir || Path.caller_lib_dir(caller_lib) || "NOLIBDIR"
|
@@ -227,7 +234,6 @@ module Path
|
|
227
234
|
end
|
228
235
|
|
229
236
|
pwd = FileUtils.pwd
|
230
|
-
path = paths[where]
|
231
237
|
path = File.join(path, "{PATH}") unless path.include? "PATH}" or path.include? "{BASENAME}"
|
232
238
|
path = path.
|
233
239
|
sub('{PKGDIR}', pkgdir).
|
data/lib/rbbt/tsv/manipulate.rb
CHANGED
data/lib/rbbt/util/open.rb
CHANGED
@@ -748,7 +748,9 @@ module Open
|
|
748
748
|
if (dir_sub_path = find_repo_dir(path))
|
749
749
|
writable_repo?(*dir_sub_path)
|
750
750
|
else
|
751
|
-
if File.
|
751
|
+
if File.symlink?(path)
|
752
|
+
File.writable?(File.dirname(path))
|
753
|
+
elsif File.exist?(path)
|
752
754
|
File.writable?(path)
|
753
755
|
else
|
754
756
|
File.writable?(File.dirname(File.expand_path(path)))
|
data/lib/rbbt/workflow.rb
CHANGED
@@ -190,7 +190,7 @@ module Workflow
|
|
190
190
|
return Misc.string2const Misc.camel_case(wf_name)
|
191
191
|
end
|
192
192
|
|
193
|
-
Log.
|
193
|
+
Log.high{"Loading workflow #{wf_name}"}
|
194
194
|
require_local_workflow(wf_name) or
|
195
195
|
(Workflow.autoinstall and `rbbt workflow install #{Misc.snake_case(wf_name)} || rbbt workflow install #{wf_name}` and require_local_workflow(wf_name)) or raise("Workflow not found or could not be loaded: #{ wf_name }")
|
196
196
|
begin
|
@@ -379,7 +379,7 @@ module Workflow
|
|
379
379
|
has_overriden_inputs = false
|
380
380
|
|
381
381
|
inputs.each do |k,v|
|
382
|
-
has_overriden_inputs = true if String === k and k.include? "#"
|
382
|
+
#has_overriden_inputs = true if String === k and k.include? "#"
|
383
383
|
next unless (task_inputs.include?(k.to_sym) or task_inputs.include?(k.to_s))
|
384
384
|
default = all_defaults[k]
|
385
385
|
next if default == v
|
@@ -382,8 +382,8 @@ module Workflow
|
|
382
382
|
else
|
383
383
|
task_info = d[:workflow].task_info(d[:task])
|
384
384
|
|
385
|
-
|
386
|
-
d[:workflow]._job(d[:task], d[:jobname],
|
385
|
+
_inputs = assign_dep_inputs({}, options.merge(d[:inputs] || {}), real_dependencies, task_info)
|
386
|
+
d[:workflow]._job(d[:task], d[:jobname], _inputs)
|
387
387
|
end
|
388
388
|
end
|
389
389
|
ComputeDependency.setup(d, compute) if compute
|
@@ -400,8 +400,8 @@ module Workflow
|
|
400
400
|
setup_override_dependency(value, dep[:workflow], dep[:task])
|
401
401
|
else
|
402
402
|
task_info = (dep[:task] && dep[:workflow]) ? dep[:workflow].task_info(dep[:task]) : nil
|
403
|
-
|
404
|
-
dep = dep[:workflow]._job(dep[:task], dep[:jobname],
|
403
|
+
_inputs = assign_dep_inputs({}, dep[:inputs], real_dependencies, task_info)
|
404
|
+
dep = dep[:workflow]._job(dep[:task], dep[:jobname], _inputs)
|
405
405
|
end
|
406
406
|
end
|
407
407
|
end
|
@@ -53,7 +53,11 @@ module Workflow
|
|
53
53
|
if file =~ /\.yaml/
|
54
54
|
inputs[input.to_sym] = YAML.load(Open.read(file))
|
55
55
|
else
|
56
|
-
|
56
|
+
if File.symlink?(file)
|
57
|
+
inputs[input.to_sym] = File.readlink(file)
|
58
|
+
else
|
59
|
+
inputs[input.to_sym] = Open.realpath(file)
|
60
|
+
end
|
57
61
|
end
|
58
62
|
when :text
|
59
63
|
Log.debug "Reading #{ input } from #{file}"
|
data/lib/rbbt/workflow/step.rb
CHANGED
@@ -114,9 +114,13 @@ class Step
|
|
114
114
|
|
115
115
|
def copy_files_dir
|
116
116
|
if File.symlink?(self.files_dir)
|
117
|
-
|
118
|
-
|
119
|
-
|
117
|
+
begin
|
118
|
+
realpath = Open.realpath(self.files_dir)
|
119
|
+
Open.rm self.files_dir
|
120
|
+
Open.cp realpath, self.files_dir
|
121
|
+
rescue
|
122
|
+
Log.warn "Copy files_dir for #{self.workflow_short_path}: " + $!.message
|
123
|
+
end
|
120
124
|
end
|
121
125
|
end
|
122
126
|
|
@@ -465,7 +469,10 @@ class Step
|
|
465
469
|
self
|
466
470
|
end
|
467
471
|
|
468
|
-
|
472
|
+
#connected = true means that dependency searching ends when a result is done
|
473
|
+
#but dependencies are absent, meanining that the file could have been dropped
|
474
|
+
#in
|
475
|
+
def rec_dependencies(connected = false, seen = [])
|
469
476
|
|
470
477
|
# A step result with no info_file means that it was manually
|
471
478
|
# placed. In that case, do not consider its dependencies
|
@@ -480,9 +487,9 @@ class Step
|
|
480
487
|
#next if self.done? && Open.exists?(info_file) && info[:dependencies] && info[:dependencies].select{|task,name,path| path == step.path }.empty?
|
481
488
|
next if archived_deps.include? step.path
|
482
489
|
next if seen.include? step.path
|
483
|
-
next if self.done? &&
|
490
|
+
next if self.done? && connected && ! updatable?
|
484
491
|
|
485
|
-
r = step.rec_dependencies(
|
492
|
+
r = step.rec_dependencies(connected, new_dependencies.collect{|d| d.path})
|
486
493
|
new_dependencies.concat r
|
487
494
|
new_dependencies << step
|
488
495
|
}
|
@@ -154,14 +154,24 @@ class Step
|
|
154
154
|
@name ||= path.sub(/.*\/#{Regexp.quote task_name.to_s}\/(.*)/, '\1')
|
155
155
|
end
|
156
156
|
|
157
|
+
|
157
158
|
def short_path
|
158
159
|
[task_name, name] * "/"
|
159
160
|
end
|
160
161
|
|
162
|
+
def workflow_short_path
|
163
|
+
return short_path unless workflow
|
164
|
+
workflow.to_s + "#" + short_path
|
165
|
+
end
|
166
|
+
|
161
167
|
def task_name
|
162
168
|
@task_name ||= task.name
|
163
169
|
end
|
164
170
|
|
171
|
+
def task_signature
|
172
|
+
[workflow.to_s, task_name] * "#"
|
173
|
+
end
|
174
|
+
|
165
175
|
# {{{ INFO
|
166
176
|
|
167
177
|
def info_file
|
@@ -456,7 +466,7 @@ class Step
|
|
456
466
|
end
|
457
467
|
|
458
468
|
def dirty_files
|
459
|
-
rec_dependencies = self.rec_dependencies
|
469
|
+
rec_dependencies = self.rec_dependencies(true)
|
460
470
|
return [] if rec_dependencies.empty?
|
461
471
|
canfail_paths = self.canfail_paths
|
462
472
|
|
@@ -112,23 +112,27 @@ class Step
|
|
112
112
|
end
|
113
113
|
|
114
114
|
def updatable?
|
115
|
-
|
115
|
+
return true if ENV["RBBT_UPDATE_ALL_JOBS"] == 'true'
|
116
|
+
return false unless ENV["RBBT_UPDATE"] == "true"
|
117
|
+
return false unless Open.exists?(info_file)
|
118
|
+
return true if status != :noinfo && ! (relocated? && done?)
|
119
|
+
false
|
116
120
|
end
|
117
121
|
|
118
122
|
def dependency_checks
|
119
123
|
return [] if ENV["RBBT_UPDATE"] != "true"
|
120
124
|
|
121
|
-
rec_dependencies.
|
125
|
+
rec_dependencies(true).
|
122
126
|
reject{|dependency| (defined?(WorkflowRemoteClient) && WorkflowRemoteClient::RemoteStep === dependency) || Open.remote?(dependency.path) }.
|
123
127
|
reject{|dependency| dependency.error? }.
|
124
128
|
#select{|dependency| Open.exists?(dependency.path) || ((Open.exists?(dependency.info_file) && (dependency.status == :cleaned) || dependency.status == :waiting)) }.
|
125
|
-
select{|dependency| dependency.updatable? }.
|
129
|
+
#select{|dependency| dependency.updatable? }.
|
126
130
|
collect{|dependency| Workflow.relocate_dependency(self, dependency)}
|
127
131
|
end
|
128
132
|
|
129
133
|
def input_checks
|
130
|
-
(inputs.select{|i| Step === i } + inputs.select{|i| Path === i && Step === i.resource}.collect{|i| i.resource})
|
131
|
-
select{|dependency| dependency.updatable? }
|
134
|
+
(inputs.select{|i| Step === i } + inputs.select{|i| Path === i && Step === i.resource}.collect{|i| i.resource})
|
135
|
+
#select{|dependency| dependency.updatable? }
|
132
136
|
end
|
133
137
|
|
134
138
|
def checks
|
@@ -153,7 +157,8 @@ class Step
|
|
153
157
|
canfail_paths = self.canfail_paths
|
154
158
|
this_mtime = Open.mtime(self.path) if Open.exists?(self.path)
|
155
159
|
|
156
|
-
outdated_time = checks.select{|dep| dep.updatable? && dep.done? && Persist.newer?(path, dep.path) }
|
160
|
+
#outdated_time = checks.select{|dep| dep.updatable? && dep.done? && Persist.newer?(path, dep.path) }
|
161
|
+
outdated_time = checks.select{|dep| dep.done? && Persist.newer?(path, dep.path) }
|
157
162
|
outdated_dep = checks.reject{|dep| dep.done? || (dep.error? && ! dep.recoverable_error? && canfail_paths.include?(dep.path)) }
|
158
163
|
|
159
164
|
#checks.each do |dep|
|
data/lib/rbbt/workflow/usage.rb
CHANGED
@@ -21,7 +21,7 @@ module Task
|
|
21
21
|
|
22
22
|
selects = []
|
23
23
|
if inputs.any?
|
24
|
-
inputs.zip(input_types.values_at(*inputs)).select{|i,t| t.to_sym == :select
|
24
|
+
inputs.zip(input_types.values_at(*inputs)).select{|i,t| t.to_sym == :select && input_options[i] && input_options[i][:select_options] }.each{|i,t| selects << [i, input_options[i][:select_options]] }
|
25
25
|
puts SOPT.input_doc(inputs, input_types, input_descriptions, input_defaults, true)
|
26
26
|
puts
|
27
27
|
end
|
@@ -78,6 +78,7 @@ class Step
|
|
78
78
|
name = info[:name] || File.basename(path)
|
79
79
|
status = :unsync if status == :done and not Open.exist?(path)
|
80
80
|
status = :notfound if status == :noinfo and not Open.exist?(path)
|
81
|
+
|
81
82
|
str = " " * offset
|
82
83
|
str << prov_report_msg(status, name, path, info)
|
83
84
|
step.dependencies.reverse.each do |dep|
|
@@ -90,7 +91,14 @@ class Step
|
|
90
91
|
if expand_repeats
|
91
92
|
str << Log.color(:green, Log.uncolor(prov_report(dep, offset+1, task)))
|
92
93
|
else
|
93
|
-
|
94
|
+
info = dep.info || {}
|
95
|
+
status = info[:status] || :missing
|
96
|
+
status = "remote" if Open.remote?(path) || Open.ssh?(path)
|
97
|
+
name = info[:name] || File.basename(path)
|
98
|
+
status = :unsync if status == :done and not Open.exist?(path)
|
99
|
+
status = :notfound if status == :noinfo and not Open.exist?(path)
|
100
|
+
|
101
|
+
str << Log.color(status == :notfound ? :blue : :green, " " * (offset + 1) + Log.uncolor(prov_report_msg(status, name, path, info)))
|
94
102
|
end
|
95
103
|
end
|
96
104
|
end if step.dependencies
|
data/share/Rlib/util.R
CHANGED
@@ -484,7 +484,7 @@ rbbt.model.inpute <- function(data, formula, ...){
|
|
484
484
|
data
|
485
485
|
}
|
486
486
|
|
487
|
-
rbbt.tsv.melt <- function(tsv, variable = NULL, value = NULL, key.field = NULL){
|
487
|
+
rbbt.tsv.melt <- function(tsv, variable = NULL, value = NULL, key.field = NULL, ...){
|
488
488
|
rbbt.require('reshape2')
|
489
489
|
if (is.null(key.field)){ key.field = attributes(data)$key.field;}
|
490
490
|
if (is.null(key.field)){ key.field = "ID" }
|
@@ -494,7 +494,7 @@ rbbt.tsv.melt <- function(tsv, variable = NULL, value = NULL, key.field = NULL){
|
|
494
494
|
|
495
495
|
tsv[key.field] = rownames(tsv)
|
496
496
|
|
497
|
-
m <- melt(tsv)
|
497
|
+
m <- melt(tsv, id.vars=c(key.field), ...)
|
498
498
|
|
499
499
|
names(m) <- c(key.field, variable, value)
|
500
500
|
|
@@ -784,6 +784,12 @@ rbbt.plot.venn <- function(data, a=NULL, category=NULL, fill=NULL, ...) {
|
|
784
784
|
return(out)
|
785
785
|
}
|
786
786
|
|
787
|
+
rbbt.plot.upset <- function(data, variable = NULL, ...){
|
788
|
+
rbbt.require('UpSetR')
|
789
|
+
data[data == TRUE] = 1
|
790
|
+
return(upset(data, ...))
|
791
|
+
}
|
792
|
+
|
787
793
|
rbbt.plot.pca <- function(data, center = TRUE, scale. = TRUE, ...) {
|
788
794
|
rbbt.require('vqv/ggbiplot')
|
789
795
|
data <- rbbt.impute(data)
|
data/share/rbbt_commands/migrate
CHANGED
@@ -70,6 +70,13 @@ workdir.glob("**/command.slurm").sort_by{|f| File.mtime(f)}.each do |fcmd|
|
|
70
70
|
cmd = nil
|
71
71
|
end
|
72
72
|
|
73
|
+
if m = Open.read(fcmd).match(/#MANIFEST: (.*)/)
|
74
|
+
manifest = m[1]
|
75
|
+
else
|
76
|
+
manifest = nil
|
77
|
+
end
|
78
|
+
|
79
|
+
|
73
80
|
if m = Open.read(fcmd).match(/# Run command\n(.*?)\n/im)
|
74
81
|
exe = m[1].sub('step_path=$(','')
|
75
82
|
else
|
@@ -98,15 +105,24 @@ workdir.glob("**/command.slurm").sort_by{|f| File.mtime(f)}.each do |fcmd|
|
|
98
105
|
if File.exists?(fstatus = File.join(dir, 'job.status'))
|
99
106
|
nodes = Open.read(fstatus).split("\n").last.split(/\s+/).last.split(",")
|
100
107
|
elsif job_nodes[id]
|
101
|
-
nodes = job_nodes[id]
|
108
|
+
nodes = job_nodes[id].reject{|n| n.include? "("}
|
102
109
|
else
|
103
110
|
nodes = []
|
104
111
|
end
|
105
112
|
|
113
|
+
if File.exists?(File.join(dir, 'exit.status'))
|
114
|
+
now = File.ctime(File.join(dir, 'exit.status'))
|
115
|
+
else
|
116
|
+
now = Time.now
|
117
|
+
end
|
118
|
+
|
106
119
|
if File.exists?(File.join(dir, 'std.out'))
|
120
|
+
cerrt = File.ctime File.join(dir, 'std.err')
|
121
|
+
coutt = File.ctime File.join(dir, 'std.out')
|
107
122
|
outt = File.mtime File.join(dir, 'std.out')
|
108
123
|
errt = File.mtime File.join(dir, 'std.err')
|
109
|
-
time_diff =
|
124
|
+
time_diff = now - [outt, errt].max
|
125
|
+
time_elapsed = now - [cerrt, coutt].min
|
110
126
|
end
|
111
127
|
|
112
128
|
fdep = File.join(dir, 'dependencies.list')
|
@@ -115,14 +131,19 @@ workdir.glob("**/command.slurm").sort_by{|f| File.mtime(f)}.each do |fcmd|
|
|
115
131
|
fcadep = File.join(dir, 'canfail_dependencies.list')
|
116
132
|
cadeps = Open.read(fcadep).split("\n") if File.exists?(fcadep)
|
117
133
|
|
118
|
-
if done || error || aborted || running || queued || jobid
|
134
|
+
if done || error || aborted || running || queued || jobid
|
119
135
|
select = false
|
120
136
|
select = true if done && exit_status == 0
|
121
137
|
select = true if error && exit_status && exit_status != 0
|
122
138
|
select = true if aborted && (exit_status.nil? && ! running_jobs.include?(id))
|
123
|
-
|
124
|
-
select = true if
|
139
|
+
is_running = exit_status.nil? && running_jobs.include?(id) && (!deps || (running_jobs & deps).empty?)
|
140
|
+
select = true if queued && deps && (running_jobs & deps).any? || queued && is_running && nodes.empty?
|
141
|
+
select = true if running && nodes.any? && (exit_status.nil? && running_jobs.include?(id)) && (!deps || (running_jobs & deps).empty?)
|
125
142
|
select = true if jobid && jobid.split(",").include?(id)
|
143
|
+
select = select && cmd.match(/#{search}/) if search
|
144
|
+
next unless select
|
145
|
+
elsif search
|
146
|
+
select = false
|
126
147
|
select = true if search && cmd.match(/#{search}/)
|
127
148
|
next unless select
|
128
149
|
end
|
@@ -130,6 +151,8 @@ workdir.glob("**/command.slurm").sort_by{|f| File.mtime(f)}.each do |fcmd|
|
|
130
151
|
|
131
152
|
puts Log.color :blue, dir
|
132
153
|
puts Log.color(:magenta, "Creation: ") << File.mtime(File.join(dir, 'command.slurm')).to_s
|
154
|
+
puts Log.color(:magenta, "Started: ") << File.ctime(File.join(dir, 'std.err')).to_s if File.exist?(File.join(dir, 'std.err'))
|
155
|
+
puts Log.color(:magenta, "Manifest: ") << Log.color(:yellow, manifest)
|
133
156
|
puts Log.color(:magenta, "Done: ") << File.mtime(File.join(dir, 'exit.status')).to_s if File.exist?(File.join(dir, 'exit.status'))
|
134
157
|
puts Log.color(:magenta, "Exec: ") << (exe || "Missing")
|
135
158
|
puts Log.color(:magenta, "CMD: ") << (Log.color(:yellow, cmd) || "Missing")
|
@@ -138,7 +161,8 @@ workdir.glob("**/command.slurm").sort_by{|f| File.mtime(f)}.each do |fcmd|
|
|
138
161
|
puts Log.color(:magenta, "Dependencies: ") << deps * ", " if deps
|
139
162
|
puts Log.color(:magenta, "Dependencies (can fail): ") << cadeps * ", " if cadeps
|
140
163
|
puts Log.color(:magenta, "Nodes: ") << nodes * ", "
|
141
|
-
puts Log.color(:magenta, "
|
164
|
+
puts Log.color(:magenta, "Time elapsed: ") << Misc.format_seconds(time_elapsed) if time_elapsed
|
165
|
+
puts Log.color(:magenta, "Output: ") << File.exists?(File.join(dir, 'std.out')).to_s << (id.nil? || File.exists?(File.join(dir, 'exit.status')) ? "" : " (last update " + Misc.format_seconds(time_diff) + " ago)")
|
142
166
|
|
143
167
|
if options[:sbatch_parameters]
|
144
168
|
puts Log.color(:magenta, "SBATCH parameters: ")
|
@@ -180,8 +204,11 @@ workdir.glob("**/command.slurm").sort_by{|f| File.mtime(f)}.each do |fcmd|
|
|
180
204
|
start = rss_average.keys.sort.first
|
181
205
|
eend = rss_average.keys.sort.last
|
182
206
|
time_elapsed = eend - start
|
207
|
+
ticks = 1 if ticks == 0
|
208
|
+
time_elapsed = 1 if time_elapsed == 0
|
183
209
|
puts Log.color(:yellow, "CPU average: ") + "%.2f" % ( ticks / clock_ticks / time_elapsed * 100).to_s
|
184
210
|
puts Log.color(:yellow, "RSS average: ") + "%.2f GB" % Misc.mean(rss_average.collect{|t,l| Misc.sum(l) / (1024 * 1024 * 1024)}).to_s
|
211
|
+
puts Log.color(:yellow, "Time: ") + Misc.format_seconds((eend - start))
|
185
212
|
|
186
213
|
end
|
187
214
|
|
@@ -16,6 +16,7 @@ $ rbbt workflow server [options] <Workflow>
|
|
16
16
|
-B--Bind* Bind IP
|
17
17
|
-p--port* TCP port
|
18
18
|
-s--server* Server type: thin, webrick, unicorn, etc
|
19
|
+
-so--server_options* Additional options for server (e.g. option1=value1;option2=value2)
|
19
20
|
-f--finder Start server with finder functionality
|
20
21
|
-RS--Rserve_session* Rserve session to use, otherwise start new one
|
21
22
|
-wd--workdir* Change the working directory of the workflow
|
@@ -32,7 +33,6 @@ $ rbbt workflow server [options] <Workflow>
|
|
32
33
|
--export_synchronous* Export workflow tasks as synchronous
|
33
34
|
--export_exec* Export workflow tasks as exec
|
34
35
|
--export_stream* Export workflow tasks as stream
|
35
|
-
--options* Additional options for server (e.g. option1=value1;option2=value2)
|
36
36
|
EOF
|
37
37
|
|
38
38
|
if options[:help]
|
@@ -108,20 +108,24 @@ TmpFile.with_file do |app_dir|
|
|
108
108
|
config_ru_file = File.exist?('./workflow_config.ru') ? './workflow_config.ru' : Rbbt.share['workflow_config.ru'].find
|
109
109
|
|
110
110
|
|
111
|
-
if options[:
|
112
|
-
options[:
|
111
|
+
if options[:server_options]
|
112
|
+
options[:server_options].split(";").each do |pair|
|
113
113
|
name, _sep, value = pair.partition("=")
|
114
114
|
name = name[1..-1].to_sym if name[0] == ':'
|
115
|
+
value = value.to_i if value =~ /^\d+$/
|
116
|
+
value = true if value == "true"
|
117
|
+
value = false if value == "false"
|
115
118
|
options[name] = value
|
116
119
|
end
|
120
|
+
options.delete :server_options
|
117
121
|
end
|
118
122
|
|
119
123
|
case server
|
120
124
|
when 'unicorn'
|
121
125
|
`env RBBT_LOG=#{Log.severity.to_s} unicorn -c #{ Rbbt.share['unicorn.rb'].find } '#{config_ru_file}' -p #{options[:Port] || "2887"}`
|
122
|
-
when '
|
126
|
+
when 'puma_production'
|
123
127
|
#`puma '#{config_ru_file}' -p #{options[:Port] || "2887"} -w 3 -t 8:32 --preload`
|
124
|
-
|
128
|
+
CMD.cmd_log("env RBBT_LOG=#{Log.severity.to_s} puma '#{config_ru_file}' -p #{options[:Port] || "2887"} -w 20 -t 10:160 --preload")
|
125
129
|
else
|
126
130
|
options[:config] = config_ru_file
|
127
131
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbbt-util
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.30.
|
4
|
+
version: 5.30.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miguel Vazquez
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-02-
|
11
|
+
date: 2021-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|