rbbt-util 5.30.2 → 5.30.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 649eff7bb5d00dd4bf47e39c8e7aba41279f0318d97289aae42e2f404eee7969
4
- data.tar.gz: cb215144a707557db37b8e160c860622676ef2f29aa395d15813d28b7c8ba233
3
+ metadata.gz: 3275cafa7bc74ca88f5d487287ff736113dad5ee6e607bb13f283bb4aa5e0562
4
+ data.tar.gz: 1a7642c60ce3f3828790599c2522ad1e083bd877c53de10401b93735e952934d
5
5
  SHA512:
6
- metadata.gz: 34b782a247f1816cd57b6acfef861a84f1d0003376e048b1c441c841cee7abe09b2a7d9d858eaa99bef8f2dfdbdb88352d0c8b6bef5cfec4a72a79e75f24db61
7
- data.tar.gz: 5a1bc971d33e35eb7e9b57e258d705393dfac17896ad68dabd58f0584ede460bcccbced20a68ac7a5250fc03932357ef185d1f9908b798691dde85d3cf173c35
6
+ metadata.gz: bc9717f6611646c099305587bdcf224243102a500ba68047e382df49e583a3c764489e09b7c9aa4993eab3953d72dc9ce206d5450213e1ae832b1622c96fd309
7
+ data.tar.gz: 791cdba47b74e1f1fd47c439bb3f2b025e540002ec2b1e18d846bab08c6fd858cc25a94f9c84056383c5125cca22c19f00d43ae0c53a8c77ef4de423c19f0d8c
@@ -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).
data/lib/rbbt/tsv.rb CHANGED
@@ -118,16 +118,13 @@ module TSV
118
118
  end
119
119
 
120
120
  if data.respond_to? :persistence_path
121
+ data.read
121
122
  data
122
123
  else
123
124
  h = data.dup
124
125
  data.clear
125
126
  data.annotate h
126
127
  end
127
-
128
- data.read if data.respond_to? :persistence_path
129
-
130
- data
131
128
  end
132
129
 
133
130
  def self.parse_header(stream, options = {})
@@ -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
 
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.2
4
+ version: 5.30.7
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-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake