rbbt-util 5.30.3 → 5.30.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 86a6fb4f62fc52b64a090ff3068452055f79ec65f5d11a1a497d1433370b76e2
4
- data.tar.gz: 453409b866e291e8971d13ef737ac8b6666ba89251b22a756bebc37339fa4ea7
3
+ metadata.gz: be64e4af9e06d88f1188ab447f63ea37296d562663ed05945de890d4addd4ce1
4
+ data.tar.gz: c3c984994184f2b980dfb699b5809d88f41eda8f16201c5c403a20850fc4e9e9
5
5
  SHA512:
6
- metadata.gz: 8438fa94a7f460192656be9bd300b2b9991fd5b97d68cdfdf3d33baa76ed8f80c53caaa967e0ecd317cb6d99a32ca0e0fede252b58c96d913b5b44bbdcdfb8f0
7
- data.tar.gz: f6d50c0b5aba669526c0d044a15598a07ded038b3ae7964c84723de05c93e30b30763a5ceddbd300a9c5f79f1c84b9305ebaa786c67702de32c5a0b26ce56222
6
+ metadata.gz: bd1e8251c15b80c44c36e9b270db74aa1aadcc2d2c01ed1b613e715a0b1cc3ca23ecd4d936afd37697de1c1dbb476afd0efecf57a2ddefbbddec5eb81a902ff6
7
+ data.tar.gz: 33e7e4a1c9a22c9900da0dbb2e4530c4b360fc3ef2f3b3abb8fbc72fd657f4d10f63d1064e721c227b7900760b98e6d98acbc776e4cf476107635c96d64bd006
@@ -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.orchestrate_job(job, options, skip = false, seen = {})
60
- return if job.done?
61
- return unless job.path.split("/")[-4] == "jobs"
62
- seen[:orchestration_target_job] ||= job
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
- rules = YAML.load(Open.read(options[:orchestration_rules])) if options[:orchestration_rules]
72
- rules ||= {}
73
- IndiferentHash.setup(rules)
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
- deps = get_job_dependencies(job, job_rules)
83
+ job_deps.each do |dep|
84
+ input_deps.concat dep.input_dependencies
85
+ get_chains(dep, rules, chains)
86
+ end
78
87
 
79
- dep_ids = deps.collect do |dep|
80
- skip_dep = job_rules["chain_tasks"] &&
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
- deps = seen[dep.path] ||= self.orchestrate_job(dep, options, skip_dep, seen)
85
- if job.canfail_paths.include? dep.path
86
- [deps].flatten.compact.collect{|id| ['canfail', id] * ":"}
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
- deps
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
- skip = true if job_rules[:skip]
93
- return dep_ids if skip and seen[:orchestration_target_job] != job
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
- run_job(job, job_options)
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
@@ -21,10 +21,12 @@ module HPC
21
21
  exclusive = options.delete :exclusive
22
22
  highmem = options.delete :highmem
23
23
 
24
- queue = options.delete(:queue) || 'bsc_ls'
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:10"
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
- mkdir -p "$(dirname '#{target}')"
305
- rsync -avztAXHP --copy-unsafe-links "#{source}/" "#{target}/" &>> #{fsync}
306
- sync_es="$?"
307
- echo $sync_es > #{fsyncexit}
308
- 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
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
@@ -349,7 +349,7 @@ module Persist
349
349
 
350
350
  Open.notify_write(path)
351
351
 
352
- return path if persist_options[:no_load]
352
+ return path if persist_options[:no_load] || type == :path
353
353
 
354
354
  res
355
355
  end
@@ -218,7 +218,14 @@ module Path
218
218
 
219
219
  else
220
220
  where = where.to_sym
221
- raise "Did not recognize the 'where' tag: #{where}. Options: #{paths.keys}" unless paths.include? where
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).
@@ -717,7 +717,7 @@ module TSV
717
717
  def transpose(key_field = "Unkown ID")
718
718
  case type
719
719
  when :single, :flat
720
- transpose_list self.to_list, key_field
720
+ self.to_list.transpose_list key_field
721
721
  when :list
722
722
  transpose_list key_field
723
723
  when :double
@@ -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.exist?(path)
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.info{"Loading workflow #{wf_name}"}
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
- inputs = assign_dep_inputs({}, options.merge(d[:inputs] || {}), real_dependencies, task_info)
386
- d[:workflow]._job(d[:task], d[:jobname], inputs)
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
- inputs = assign_dep_inputs({}, dep[:inputs], real_dependencies, task_info)
404
- dep = dep[:workflow]._job(dep[:task], dep[:jobname], inputs)
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
- inputs[input.to_sym] = Open.realpath(file)
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}"
@@ -315,6 +315,11 @@ class RemoteStep < Step
315
315
  end
316
316
  end
317
317
 
318
+ def workflow_short_path
319
+ init_job unless @url
320
+ [@base_url, @task, @name] * "/"
321
+ end
322
+
318
323
  def short_path
319
324
  init_job unless @url
320
325
  [@task, @name] * "/"
@@ -114,9 +114,13 @@ class Step
114
114
 
115
115
  def copy_files_dir
116
116
  if File.symlink?(self.files_dir)
117
- realpath = Open.realpath(self.files_dir)
118
- Open.rm self.files_dir
119
- Open.cp realpath, self.files_dir
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
- def rec_dependencies(need_run = false, seen = [])
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? && need_run && ! updatable?
490
+ next if self.done? && connected && ! updatable?
484
491
 
485
- r = step.rec_dependencies(need_run, new_dependencies.collect{|d| d.path})
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
- (ENV["RBBT_UPDATE_ALL_JOBS"] == 'true' || ( ENV["RBBT_UPDATE"] == "true" && Open.exists?(info_file)) && status != :noinfo && ! (relocated? && done?)) || (ENV["RBBT_UPDATE"] && ! (done? && ! Open.exists?(info_file)))
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|
@@ -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 and input_options[i][:select_options] }.each{|i,t| selects << [i, input_options[i][:select_options]] }
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
@@ -232,7 +232,7 @@ puts resource[path].find(search_path)
232
232
  ppp Open.read(tmp_include_file)
233
233
  puts cmd
234
234
  else
235
- CMD.cmd_log(cmd)
235
+ CMD.cmd_log(cmd, :log => Log::INFO)
236
236
  end
237
237
  end
238
238
  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
- str << Log.color(:green, " " * (offset + 1) + Log.uncolor(prov_report_msg(status, name, path, info)))
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)
@@ -107,6 +107,6 @@ real_paths.each do |source|
107
107
  puts cmd
108
108
  exit 0
109
109
  else
110
- CMD.cmd_log(cmd)
110
+ CMD.cmd_log(cmd, :log => Log::INFO)
111
111
  end
112
112
  end
@@ -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 = Time.now - [outt, errt].max
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 || search
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
- select = true if queued && deps && (running_jobs & deps).any?
124
- select = true if running && (exit_status.nil? && running_jobs.include?(id)) && (!deps || (running_jobs & deps).empty?)
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, "Output: ") << File.exists?(File.join(dir, 'std.out')).to_s << (id.nil? ? "" : " (last update " + Misc.format_seconds(time_diff) + " ago)")
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[:options]
112
- options[:options].split(";").each do |pair|
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 'puma_alt'
126
+ when 'puma_production'
123
127
  #`puma '#{config_ru_file}' -p #{options[:Port] || "2887"} -w 3 -t 8:32 --preload`
124
- `env RBBT_LOG=#{Log.severity.to_s} puma '#{config_ru_file}' -p #{options[:Port] || "2887"} -w 20 -t 10:160 --preload`
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.3
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-02 00:00:00.000000000 Z
11
+ date: 2021-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake