rbbt-util 5.30.5 → 5.30.10
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 +125 -28
- data/lib/rbbt/hpc/slurm.rb +6 -0
- 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/config.rb +2 -2
- data/lib/rbbt/workflow.rb +1 -1
- data/lib/rbbt/workflow/accessor.rb +4 -4
- data/lib/rbbt/workflow/definition.rb +7 -3
- 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 +5 -3
- data/lib/rbbt/workflow/util/provenance.rb +8 -1
- data/share/Rlib/util.R +8 -2
- data/share/rbbt_commands/slurm/list +8 -0
- data/share/rbbt_commands/workflow/server +10 -5
- data/test/rbbt/util/test_config.rb +13 -3
- 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: 48bec783cd5a61ffb37cb7cd80379ed9c90bbcfd2cecdb756cff0f2efd6240ed
|
|
4
|
+
data.tar.gz: 9da9e93fc5c89be3ca8f57f87ca2808f298e6a300cd13dfff4dd602a2bf1b4b0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 23976e1fcc0a216a822fa19ec9f4510d87f5d19d334245f6cea87746d3b7b85cf3c41110ce2d36f3a793f6e5af1bd08ad2299ad0acb08f11efe711f3417da590
|
|
7
|
+
data.tar.gz: 2fe9f8dbea015d105076926f0407c1029a400f6eafce7f17edca075e4975ef5a4bd455f416cad4e2d4deadb2d7486988c00500687fc41352020ba71fa07a0f0c
|
data/lib/rbbt/hpc/orchestrate.rb
CHANGED
|
@@ -8,7 +8,7 @@ module HPC
|
|
|
8
8
|
task_name = job.overriden.to_s if Symbol === job.overriden
|
|
9
9
|
|
|
10
10
|
defaults = rules["defaults"] || {}
|
|
11
|
-
defaults.merge(rules[workflow]["defaults"] || {}) if rules[workflow]
|
|
11
|
+
defaults = defaults.merge(rules[workflow]["defaults"] || {}) if rules[workflow]
|
|
12
12
|
|
|
13
13
|
job_rules = IndiferentHash.setup(defaults.dup)
|
|
14
14
|
|
|
@@ -53,62 +53,159 @@ module HPC
|
|
|
53
53
|
job_rules
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
def self.get_job_dependencies(job, job_rules)
|
|
56
|
+
def self.get_job_dependencies(job, job_rules = nil)
|
|
57
57
|
deps = job.dependencies || []
|
|
58
58
|
deps += job.input_dependencies || []
|
|
59
59
|
deps
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
-
def self.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
options.delete "recursive_clean"
|
|
68
|
-
options.delete "clean_task"
|
|
69
|
-
options.delete "clean"
|
|
70
|
-
options.delete "tail"
|
|
71
|
-
options.delete "printfile"
|
|
72
|
-
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
|
|
73
66
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
+
final_deps = final_deps.reject{|dep| dep.done? && dep.status == :noinfo }
|
|
71
|
+
return final_deps.first if final_deps.length == 1
|
|
72
|
+
return false
|
|
73
|
+
end
|
|
77
74
|
|
|
75
|
+
def self.get_chains(job, rules, chains = {})
|
|
78
76
|
job_rules = self.job_rules(rules, job)
|
|
77
|
+
job_deps = get_job_dependencies(job)
|
|
78
|
+
|
|
79
|
+
input_deps = []
|
|
80
|
+
job.rec_dependencies.each do |dep|
|
|
81
|
+
input_deps.concat dep.input_dependencies
|
|
82
|
+
end
|
|
79
83
|
|
|
80
|
-
|
|
84
|
+
job_deps.each do |dep|
|
|
85
|
+
input_deps.concat dep.input_dependencies
|
|
86
|
+
get_chains(dep, rules, chains)
|
|
87
|
+
end
|
|
81
88
|
|
|
82
|
-
|
|
83
|
-
|
|
89
|
+
job_deps.select do |dep|
|
|
90
|
+
chained = job_rules["chain_tasks"] &&
|
|
84
91
|
job_rules["chain_tasks"][job.workflow.to_s] && job_rules["chain_tasks"][job.workflow.to_s].include?(job.task_name.to_s) &&
|
|
85
92
|
job_rules["chain_tasks"][dep.workflow.to_s] && job_rules["chain_tasks"][dep.workflow.to_s].include?(dep.task_name.to_s)
|
|
86
93
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
94
|
+
dep_skip = dep.done? && ! input_deps.include?(dep) && self.job_rules(rules, dep)["skip"]
|
|
95
|
+
chained || dep_skip
|
|
96
|
+
end.each do |dep|
|
|
97
|
+
chains[job] ||= []
|
|
98
|
+
chains[job] << dep
|
|
99
|
+
chains[job].concat chains[dep] if chains[dep]
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
chains
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def self.workload(job, rules, chains, options, seen = nil)
|
|
106
|
+
return [] if job.done?
|
|
107
|
+
if seen.nil?
|
|
108
|
+
seen = {}
|
|
109
|
+
target_job = true
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
job_rules = self.job_rules(rules, job)
|
|
113
|
+
job_deps = get_job_dependencies(job)
|
|
114
|
+
|
|
115
|
+
chain = chains[job]
|
|
116
|
+
chain = chain.reject{|j| seen.include? j.path} if chain
|
|
117
|
+
chain = chain.reject{|dep| dep.done? } if chain
|
|
118
|
+
piggyback = piggyback(job, job_rules, job_deps)
|
|
119
|
+
dep_ids = job_deps.collect do |dep|
|
|
120
|
+
seen[dep.path] ||= nil if chain && chain.include?(dep) #&& ! job.input_dependencies.include?(dep)
|
|
121
|
+
next_options = IndiferentHash.setup(options.dup)
|
|
122
|
+
if piggyback and piggyback == dep
|
|
123
|
+
next_options[:piggyback] ||= []
|
|
124
|
+
next_options[:piggyback].push job
|
|
125
|
+
ids = workload(dep, rules, chains, next_options, seen)
|
|
90
126
|
else
|
|
91
|
-
|
|
127
|
+
next_options.delete :piggyback
|
|
128
|
+
ids = workload(dep, rules, chains, next_options, seen)
|
|
92
129
|
end
|
|
93
|
-
end.flatten.compact.uniq
|
|
94
130
|
|
|
95
|
-
|
|
96
|
-
|
|
131
|
+
ids = [ids].flatten.compact.collect{|id| ['canfail', id] * ":"} if job.canfail_paths.include? dep.path
|
|
132
|
+
|
|
133
|
+
seen[dep.path] = ids
|
|
134
|
+
ids
|
|
135
|
+
end.compact.flatten.uniq
|
|
136
|
+
|
|
137
|
+
return seen[job.path] || dep_ids if seen.include?(job.path)
|
|
138
|
+
|
|
139
|
+
if piggyback and seen[piggyback.path]
|
|
140
|
+
return seen[job.path] = seen[piggyback.path]
|
|
141
|
+
end
|
|
97
142
|
|
|
98
143
|
job_rules.delete :chain_tasks
|
|
99
144
|
job_rules.delete :tasks
|
|
100
145
|
job_rules.delete :workflow
|
|
101
146
|
|
|
102
|
-
config_keys = job_rules.delete(:config_keys)
|
|
103
147
|
|
|
104
148
|
job_options = IndiferentHash.setup(options.merge(job_rules).merge(:slurm_dependencies => dep_ids))
|
|
105
149
|
job_options.delete :orchestration_rules
|
|
150
|
+
|
|
151
|
+
config_keys = job_rules.delete(:config_keys)
|
|
106
152
|
if config_keys
|
|
107
153
|
config_keys.gsub!(/,\s+/,',')
|
|
108
154
|
job_options[:config_keys] = job_options[:config_keys] ? config_keys + "," + job_options[:config_keys] : config_keys
|
|
109
155
|
end
|
|
110
156
|
|
|
111
|
-
|
|
157
|
+
if options[:piggyback]
|
|
158
|
+
manifest = options[:piggyback].uniq
|
|
159
|
+
manifest += [job]
|
|
160
|
+
manifest.concat chain if chain
|
|
161
|
+
|
|
162
|
+
job = options[:piggyback].first
|
|
163
|
+
|
|
164
|
+
job_rules = self.job_rules(rules, job)
|
|
165
|
+
new_config_keys = self.job_rules(rules, job)[:config_keys]
|
|
166
|
+
if new_config_keys
|
|
167
|
+
new_config_keys = new_config_keys.gsub(/,\s+/,',')
|
|
168
|
+
job_options[:config_keys] = job_options[:config_keys] ? new_config_keys + "," + job_options[:config_keys] : new_config_keys
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
job_options.delete :piggyback
|
|
172
|
+
else
|
|
173
|
+
manifest = [job]
|
|
174
|
+
manifest.concat chain if chain
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
manifest.uniq!
|
|
178
|
+
|
|
179
|
+
job_options[:manifest] = manifest.collect{|j| j.task_signature }
|
|
180
|
+
|
|
181
|
+
job_options[:config_keys] = job_options[:config_keys].split(",").uniq * "," if job_options[:config_keys]
|
|
182
|
+
|
|
183
|
+
if options[:dry_run]
|
|
184
|
+
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]}"
|
|
185
|
+
puts Log.color(:yellow, "Deps: ") + Log.color(:blue, job_options[:slurm_dependencies]*", ")
|
|
186
|
+
job_options[:manifest].first
|
|
187
|
+
else
|
|
188
|
+
run_job(job, job_options)
|
|
189
|
+
end
|
|
112
190
|
end
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def self.orchestrate_job(job, options)
|
|
194
|
+
options.delete "recursive_clean"
|
|
195
|
+
options.delete "clean_task"
|
|
196
|
+
options.delete "clean"
|
|
197
|
+
options.delete "tail"
|
|
198
|
+
options.delete "printfile"
|
|
199
|
+
options.delete "detach"
|
|
200
|
+
|
|
201
|
+
rules = YAML.load(Open.read(options[:orchestration_rules])) if options[:orchestration_rules]
|
|
202
|
+
rules ||= {}
|
|
203
|
+
IndiferentHash.setup(rules)
|
|
204
|
+
|
|
205
|
+
chains = get_chains(job, rules)
|
|
206
|
+
|
|
207
|
+
workload(job, rules, chains, options)
|
|
208
|
+
end
|
|
209
|
+
|
|
113
210
|
end
|
|
114
211
|
end
|
data/lib/rbbt/hpc/slurm.rb
CHANGED
|
@@ -21,6 +21,8 @@ module HPC
|
|
|
21
21
|
exclusive = options.delete :exclusive
|
|
22
22
|
highmem = options.delete :highmem
|
|
23
23
|
|
|
24
|
+
manifest = options.delete :manifest
|
|
25
|
+
|
|
24
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
|
|
@@ -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
|
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/config.rb
CHANGED
|
@@ -90,6 +90,8 @@ module Rbbt::Config
|
|
|
90
90
|
options = tokens.pop if Hash === tokens.last
|
|
91
91
|
default = options.nil? ? nil : options[:default]
|
|
92
92
|
|
|
93
|
+
tokens = ["key:" + key] if tokens.empty?
|
|
94
|
+
|
|
93
95
|
tokens = tokens.flatten
|
|
94
96
|
file, _sep, line = caller.reject{|l|
|
|
95
97
|
l =~ /rbbt\/(?:resource\.rb|workflow\.rb)/ or
|
|
@@ -106,7 +108,6 @@ module Rbbt::Config
|
|
|
106
108
|
|
|
107
109
|
entries = CACHE[key.to_s]
|
|
108
110
|
priorities = {}
|
|
109
|
-
tokens = tokens + ["key:" << key.to_s]
|
|
110
111
|
tokens.each do |token|
|
|
111
112
|
token_prio = match entries, token.to_s
|
|
112
113
|
token_prio.each do |prio, values|
|
|
@@ -145,7 +146,6 @@ module Rbbt::Config
|
|
|
145
146
|
Rbbt::Config.load_file(Rbbt.etc.config_profile[config].find)
|
|
146
147
|
else
|
|
147
148
|
key, value, *tokens = config.split(/\s/)
|
|
148
|
-
tokens = ['key:' << key << '::0'] if tokens.empty?
|
|
149
149
|
tokens = tokens.collect do |tok|
|
|
150
150
|
tok, _sep, prio = tok.partition("::")
|
|
151
151
|
prio = "0" if prio.nil? or prio.empty?
|
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
|
|
@@ -79,9 +79,10 @@ module Workflow
|
|
|
79
79
|
dep = dependencies.last.join
|
|
80
80
|
raise dep.get_exception if dep.error?
|
|
81
81
|
set_info :result_type, dep.info[:result_type]
|
|
82
|
-
forget = config :forget_dep_tasks, :forget_dep_tasks, :default => FORGET_DEP_TASKS
|
|
82
|
+
forget = config :forget_dep_tasks, "key:forget_dep_tasks", :default => FORGET_DEP_TASKS
|
|
83
83
|
if forget
|
|
84
|
-
remove = config :remove_dep_tasks, :remove_dep_tasks, :default => REMOVE_DEP_TASKS
|
|
84
|
+
remove = config :remove_dep_tasks, "key:remove_dep_tasks", :default => REMOVE_DEP_TASKS
|
|
85
|
+
|
|
85
86
|
self.archive_deps
|
|
86
87
|
self.copy_files_dir
|
|
87
88
|
self.dependencies = self.dependencies - [dep]
|
|
@@ -92,7 +93,10 @@ module Workflow
|
|
|
92
93
|
when 'true'
|
|
93
94
|
dep.clean
|
|
94
95
|
when 'recursive'
|
|
95
|
-
dep.
|
|
96
|
+
dep.rec_dependencies.each do |d|
|
|
97
|
+
d.clean unless config(:remove_dep, d.task_signature, d.task_name, d.workflow.to_s, :default => true).to_s == 'false'
|
|
98
|
+
end
|
|
99
|
+
dep.clean unless config(:remove_dep, dep.task_signature, dep.task_name, dep.workflow.to_s, :default => true).to_s == 'false'
|
|
96
100
|
end
|
|
97
101
|
else
|
|
98
102
|
if Open.exists?(dep.files_dir)
|
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
|
|
@@ -51,7 +51,7 @@ class Step
|
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
def self.job_files_for_archive(files, recursive = false)
|
|
54
|
+
def self.job_files_for_archive(files, recursive = false, skip_overriden = false)
|
|
55
55
|
job_files = Set.new
|
|
56
56
|
|
|
57
57
|
jobs = files.collect do |file|
|
|
@@ -65,6 +65,8 @@ class Step
|
|
|
65
65
|
|
|
66
66
|
jobs.each do |step|
|
|
67
67
|
next unless File.exists?(step.path)
|
|
68
|
+
next if skip_overriden && step.overriden
|
|
69
|
+
|
|
68
70
|
job_files << step.path
|
|
69
71
|
job_files << step.info_file if File.exists?(step.info_file)
|
|
70
72
|
job_files << Step.md5_file(step.path) if File.exists?(Step.md5_file step.path)
|
|
@@ -258,9 +260,9 @@ puts resource[path].find(search_path)
|
|
|
258
260
|
end
|
|
259
261
|
end
|
|
260
262
|
|
|
261
|
-
def self.purge(path, recursive = false)
|
|
263
|
+
def self.purge(path, recursive = false, skip_overriden = true)
|
|
262
264
|
path = [path] if String === path
|
|
263
|
-
job_files = job_files_for_archive path, recursive
|
|
265
|
+
job_files = job_files_for_archive path, recursive, skip_overriden
|
|
264
266
|
|
|
265
267
|
job_files.each do |file|
|
|
266
268
|
begin
|
|
@@ -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
|
|
@@ -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
|
|
|
@@ -5,8 +5,9 @@ class TestConfig < Test::Unit::TestCase
|
|
|
5
5
|
def setup
|
|
6
6
|
Rbbt::Config.set({:cpus => 30}, :test_config, :test)
|
|
7
7
|
Rbbt::Config.set(:cpus, 5, "slow::2", :test)
|
|
8
|
-
Rbbt::Config.set({:token => "token"}, "token"
|
|
8
|
+
Rbbt::Config.set({:token => "token"}, "token")
|
|
9
9
|
Rbbt::Config.set(:notoken, "no_token")
|
|
10
|
+
Rbbt::Config.set({:emptytoken => "empty"})
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
def test_simple
|
|
@@ -19,8 +20,12 @@ class TestConfig < Test::Unit::TestCase
|
|
|
19
20
|
|
|
20
21
|
def test_simple_no_token
|
|
21
22
|
assert_equal "token", Rbbt::Config.get("token", "token")
|
|
22
|
-
assert_equal "
|
|
23
|
-
assert_equal
|
|
23
|
+
assert_equal "no_token", Rbbt::Config.get("notoken", "key:notoken")
|
|
24
|
+
assert_equal 'token', Rbbt::Config.get("token", "key:token")
|
|
25
|
+
assert_equal 'token', Rbbt::Config.get("token")
|
|
26
|
+
assert_equal nil, Rbbt::Config.get("token", "someotherthing")
|
|
27
|
+
assert_equal "default_token", Rbbt::Config.get("token", 'unknown', :default => 'default_token')
|
|
28
|
+
assert_equal 'empty', Rbbt::Config.get("emptytoken", 'key:emptytoken')
|
|
24
29
|
end
|
|
25
30
|
|
|
26
31
|
def test_prio
|
|
@@ -54,6 +59,11 @@ class TestConfig < Test::Unit::TestCase
|
|
|
54
59
|
assert_equal "V1", Rbbt::Config.get('key', 'token1', 'token2')
|
|
55
60
|
end
|
|
56
61
|
|
|
62
|
+
def test_default
|
|
63
|
+
Rbbt::Config.add_entry 'key', 'V1', 'token1'
|
|
64
|
+
assert_equal "V3", Rbbt::Config.get('key', 'token2', :default => 'V3')
|
|
65
|
+
end
|
|
66
|
+
|
|
57
67
|
|
|
58
68
|
end
|
|
59
69
|
|
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.10
|
|
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-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|