rbbt-util 5.30.4 → 5.30.9
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/hpc/orchestrate.rb +123 -27
- 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 +1 -1
- 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/provenance.rb +8 -1
- data/share/Rlib/util.R +8 -2
- data/share/rbbt_commands/slurm/list +9 -1
- data/share/rbbt_commands/workflow/server +10 -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: 8985df2e0e2353224b5b075acb1bb04243d12351b8d904441009b93ccf490288
|
4
|
+
data.tar.gz: 3a1e7d8561fcc72a83c2b0006c49cf50f35a87cfa037c0186bdc3563435a0e8f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: baae9121f3d757bcda2add9f666c740e5647f38d4bbc511d3456e36d466fc443c8a04b0ae12431bbf226e4e0c75eec5700b28720c117954005fe836ad74b76e8
|
7
|
+
data.tar.gz: ea61b36cec82f6634546aecf5de356d7d3b3c9d28eccfad52282f309e5ad6e1e28c2bfb627a100970d6a553fdc90b3900a4247101210cfbaae461c35d8e0399a
|
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,62 +53,155 @@ 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)
|
76
77
|
|
77
|
-
|
78
|
+
input_deps = []
|
79
|
+
job.rec_dependencies.each do |dep|
|
80
|
+
input_deps.concat dep.input_dependencies
|
81
|
+
end
|
78
82
|
|
79
|
-
|
80
|
-
|
83
|
+
job_deps.each do |dep|
|
84
|
+
input_deps.concat dep.input_dependencies
|
85
|
+
get_chains(dep, rules, chains)
|
86
|
+
end
|
87
|
+
|
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
|
97
141
|
job_rules.delete :workflow
|
98
142
|
|
99
|
-
config_keys = job_rules.delete(:config_keys)
|
100
143
|
|
101
144
|
job_options = IndiferentHash.setup(options.merge(job_rules).merge(:slurm_dependencies => dep_ids))
|
102
145
|
job_options.delete :orchestration_rules
|
146
|
+
|
147
|
+
config_keys = job_rules.delete(:config_keys)
|
103
148
|
if config_keys
|
104
149
|
config_keys.gsub!(/,\s+/,',')
|
105
150
|
job_options[:config_keys] = job_options[:config_keys] ? config_keys + "," + job_options[:config_keys] : config_keys
|
106
151
|
end
|
107
152
|
|
108
|
-
|
153
|
+
if options[:piggyback]
|
154
|
+
manifest = options[:piggyback].uniq
|
155
|
+
manifest += [job]
|
156
|
+
manifest.concat chain if chain
|
157
|
+
|
158
|
+
job = options[:piggyback].first
|
159
|
+
|
160
|
+
job_rules = self.job_rules(rules, job)
|
161
|
+
new_config_keys = self.job_rules(rules, job)[:config_keys]
|
162
|
+
if new_config_keys
|
163
|
+
new_config_keys = new_config_keys.gsub(/,\s+/,',')
|
164
|
+
job_options[:config_keys] = job_options[:config_keys] ? new_config_keys + "," + job_options[:config_keys] : new_config_keys
|
165
|
+
end
|
166
|
+
|
167
|
+
job_options.delete :piggyback
|
168
|
+
else
|
169
|
+
manifest = [job]
|
170
|
+
manifest.concat chain if chain
|
171
|
+
end
|
172
|
+
|
173
|
+
manifest.uniq!
|
174
|
+
|
175
|
+
job_options[:manifest] = manifest.collect{|j| j.workflow_short_path }
|
176
|
+
|
177
|
+
job_options[:config_keys] = job_options[:config_keys].split(",").uniq * "," if job_options[:config_keys]
|
178
|
+
|
179
|
+
if options[:dry_run]
|
180
|
+
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]}"
|
181
|
+
puts Log.color(:yellow, "Deps: ") + Log.color(:blue, job_options[:slurm_dependencies]*", ")
|
182
|
+
job_options[:manifest].first
|
183
|
+
else
|
184
|
+
run_job(job, job_options)
|
185
|
+
end
|
109
186
|
end
|
187
|
+
|
188
|
+
|
189
|
+
def self.orchestrate_job(job, options)
|
190
|
+
options.delete "recursive_clean"
|
191
|
+
options.delete "clean_task"
|
192
|
+
options.delete "clean"
|
193
|
+
options.delete "tail"
|
194
|
+
options.delete "printfile"
|
195
|
+
options.delete "detach"
|
196
|
+
|
197
|
+
rules = YAML.load(Open.read(options[:orchestration_rules])) if options[:orchestration_rules]
|
198
|
+
rules ||= {}
|
199
|
+
IndiferentHash.setup(rules)
|
200
|
+
|
201
|
+
chains = get_chains(job, rules)
|
202
|
+
|
203
|
+
workload(job, rules, chains, options)
|
204
|
+
end
|
205
|
+
|
110
206
|
end
|
111
207
|
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
@@ -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
|
@@ -91,7 +91,14 @@ class Step
|
|
91
91
|
if expand_repeats
|
92
92
|
str << Log.color(:green, Log.uncolor(prov_report(dep, offset+1, task)))
|
93
93
|
else
|
94
|
-
|
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)))
|
95
102
|
end
|
96
103
|
end
|
97
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)
|
@@ -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
|
@@ -133,7 +140,7 @@ workdir.glob("**/command.slurm").sort_by{|f| File.mtime(f)}.each do |fcmd|
|
|
133
140
|
select = true if queued && deps && (running_jobs & deps).any? || queued && is_running && nodes.empty?
|
134
141
|
select = true if running && nodes.any? && (exit_status.nil? && running_jobs.include?(id)) && (!deps || (running_jobs & deps).empty?)
|
135
142
|
select = true if jobid && jobid.split(",").include?(id)
|
136
|
-
select
|
143
|
+
select = select && cmd.match(/#{search}/) if search
|
137
144
|
next unless select
|
138
145
|
elsif search
|
139
146
|
select = false
|
@@ -145,6 +152,7 @@ workdir.glob("**/command.slurm").sort_by{|f| File.mtime(f)}.each do |fcmd|
|
|
145
152
|
puts Log.color :blue, dir
|
146
153
|
puts Log.color(:magenta, "Creation: ") << File.mtime(File.join(dir, 'command.slurm')).to_s
|
147
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)
|
148
156
|
puts Log.color(:magenta, "Done: ") << File.mtime(File.join(dir, 'exit.status')).to_s if File.exist?(File.join(dir, 'exit.status'))
|
149
157
|
puts Log.color(:magenta, "Exec: ") << (exe || "Missing")
|
150
158
|
puts Log.color(:magenta, "CMD: ") << (Log.color(:yellow, cmd) || "Missing")
|
@@ -16,6 +16,8 @@ $ 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
|
+
-w--workers* Number of workers for cluster mode (puma)
|
20
|
+
-so--server_options* Additional options for server (e.g. option1=value1;option2=value2)
|
19
21
|
-f--finder Start server with finder functionality
|
20
22
|
-RS--Rserve_session* Rserve session to use, otherwise start new one
|
21
23
|
-wd--workdir* Change the working directory of the workflow
|
@@ -32,7 +34,6 @@ $ rbbt workflow server [options] <Workflow>
|
|
32
34
|
--export_synchronous* Export workflow tasks as synchronous
|
33
35
|
--export_exec* Export workflow tasks as exec
|
34
36
|
--export_stream* Export workflow tasks as stream
|
35
|
-
--options* Additional options for server (e.g. option1=value1;option2=value2)
|
36
37
|
EOF
|
37
38
|
|
38
39
|
if options[:help]
|
@@ -108,20 +109,24 @@ TmpFile.with_file do |app_dir|
|
|
108
109
|
config_ru_file = File.exist?('./workflow_config.ru') ? './workflow_config.ru' : Rbbt.share['workflow_config.ru'].find
|
109
110
|
|
110
111
|
|
111
|
-
if options[:
|
112
|
-
options[:
|
112
|
+
if options[:server_options]
|
113
|
+
options[:server_options].split(";").each do |pair|
|
113
114
|
name, _sep, value = pair.partition("=")
|
114
115
|
name = name[1..-1].to_sym if name[0] == ':'
|
116
|
+
value = value.to_i if value =~ /^\d+$/
|
117
|
+
value = true if value == "true"
|
118
|
+
value = false if value == "false"
|
115
119
|
options[name] = value
|
116
120
|
end
|
121
|
+
options.delete :server_options
|
117
122
|
end
|
118
123
|
|
119
124
|
case server
|
120
125
|
when 'unicorn'
|
121
126
|
`env RBBT_LOG=#{Log.severity.to_s} unicorn -c #{ Rbbt.share['unicorn.rb'].find } '#{config_ru_file}' -p #{options[:Port] || "2887"}`
|
122
|
-
when '
|
127
|
+
when 'puma_production'
|
123
128
|
#`puma '#{config_ru_file}' -p #{options[:Port] || "2887"} -w 3 -t 8:32 --preload`
|
124
|
-
|
129
|
+
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
130
|
else
|
126
131
|
options[:config] = config_ru_file
|
127
132
|
|
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.9
|
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
|