rbbt-util 5.28.9 → 5.29.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rbbt/entity.rb +1 -1
  3. data/lib/rbbt/fix_width_table.rb +5 -4
  4. data/lib/rbbt/hpc.rb +1 -549
  5. data/lib/rbbt/hpc/orchestrate.rb +23 -0
  6. data/lib/rbbt/hpc/slurm.rb +570 -0
  7. data/lib/rbbt/persist.rb +9 -4
  8. data/lib/rbbt/persist/tsv/adapter.rb +0 -1
  9. data/lib/rbbt/persist/tsv/fix_width_table.rb +5 -3
  10. data/lib/rbbt/resource.rb +12 -6
  11. data/lib/rbbt/resource/path.rb +1 -1
  12. data/lib/rbbt/tsv/attach.rb +7 -4
  13. data/lib/rbbt/tsv/dumper.rb +6 -2
  14. data/lib/rbbt/tsv/parallel.rb +0 -3
  15. data/lib/rbbt/util/R.rb +2 -2
  16. data/lib/rbbt/util/cmd.rb +10 -0
  17. data/lib/rbbt/util/misc/bgzf.rb +1 -1
  18. data/lib/rbbt/util/misc/indiferent_hash.rb +8 -0
  19. data/lib/rbbt/util/misc/inspect.rb +11 -7
  20. data/lib/rbbt/util/named_array.rb +1 -1
  21. data/lib/rbbt/util/open.rb +17 -16
  22. data/lib/rbbt/workflow.rb +2 -1
  23. data/lib/rbbt/workflow/accessor.rb +3 -2
  24. data/lib/rbbt/workflow/definition.rb +3 -1
  25. data/lib/rbbt/workflow/examples.rb +2 -2
  26. data/lib/rbbt/workflow/integration/ansible.rb +53 -0
  27. data/lib/rbbt/workflow/integration/ansible/workflow.rb +60 -0
  28. data/lib/rbbt/workflow/step.rb +16 -5
  29. data/lib/rbbt/workflow/step/accessor.rb +36 -24
  30. data/lib/rbbt/workflow/step/dependencies.rb +8 -2
  31. data/lib/rbbt/workflow/step/run.rb +22 -19
  32. data/lib/rbbt/workflow/util/archive.rb +2 -0
  33. data/lib/rbbt/workflow/util/orchestrator.rb +30 -12
  34. data/lib/rbbt/workflow/util/provenance.rb +7 -3
  35. data/share/rbbt_commands/ansible +55 -0
  36. data/share/rbbt_commands/purge_job +0 -1
  37. data/share/rbbt_commands/slurm/list +141 -0
  38. data/share/rbbt_commands/slurm/orchestrate +47 -0
  39. data/share/rbbt_commands/{workflow/slurm → slurm/task} +10 -3
  40. data/share/rbbt_commands/system/status +22 -22
  41. data/share/rbbt_commands/workflow/forget_deps +9 -0
  42. data/share/rbbt_commands/workflow/info +12 -9
  43. data/share/rbbt_commands/workflow/prov +2 -1
  44. data/test/rbbt/association/test_index.rb +6 -6
  45. data/test/rbbt/knowledge_base/test_query.rb +3 -3
  46. data/test/rbbt/knowledge_base/test_registry.rb +1 -1
  47. data/test/rbbt/persist/tsv/test_cdb.rb +0 -7
  48. data/test/rbbt/persist/tsv/test_kyotocabinet.rb +2 -8
  49. data/test/rbbt/persist/tsv/test_leveldb.rb +0 -6
  50. data/test/rbbt/persist/tsv/test_lmdb.rb +0 -6
  51. data/test/rbbt/persist/tsv/test_tokyocabinet.rb +15 -14
  52. data/test/rbbt/test_entity.rb +0 -1
  53. data/test/rbbt/test_knowledge_base.rb +3 -4
  54. data/test/rbbt/test_persist.rb +10 -6
  55. data/test/rbbt/test_workflow.rb +49 -16
  56. data/test/rbbt/tsv/test_accessor.rb +11 -0
  57. data/test/rbbt/tsv/test_attach.rb +86 -8
  58. data/test/rbbt/tsv/test_index.rb +6 -7
  59. data/test/rbbt/tsv/test_manipulate.rb +2 -3
  60. data/test/rbbt/util/R/test_model.rb +2 -1
  61. data/test/rbbt/util/R/test_plot.rb +0 -2
  62. data/test/rbbt/util/concurrency/test_processes.rb +1 -1
  63. data/test/rbbt/util/misc/test_bgzf.rb +11 -7
  64. data/test/rbbt/util/misc/test_lock.rb +0 -1
  65. data/test/rbbt/util/misc/test_multipart_payload.rb +1 -1
  66. data/test/rbbt/util/misc/test_pipes.rb +0 -5
  67. data/test/rbbt/util/test_R.rb +1 -0
  68. data/test/rbbt/util/test_log.rb +4 -6
  69. data/test/rbbt/util/test_misc.rb +0 -2
  70. data/test/rbbt/util/test_open.rb +0 -1
  71. data/test/rbbt/util/test_python.rb +17 -1
  72. data/test/rbbt/workflow/test_remote_workflow.rb +1 -1
  73. data/test/rbbt/workflow/test_step.rb +8 -3
  74. data/test/rbbt/workflow/util/test_orchestrator.rb +50 -0
  75. metadata +10 -5
  76. data/test/rbbt/workflow/remote/test_client.rb +0 -56
@@ -50,8 +50,8 @@ module Workflow
50
50
  case input_types[input]
51
51
  when :file
52
52
  Log.debug "Pointing #{ input } to #{file}"
53
- if file =~ /\.read$/
54
- inputs[input.to_sym] = Open.read(file)
53
+ if file =~ /\.yaml/
54
+ inputs[input.to_sym] = YAML.load(Open.read(file))
55
55
  else
56
56
  inputs[input.to_sym] = Open.realpath(file)
57
57
  end
@@ -0,0 +1,53 @@
1
+ require_relative 'ansible/workflow'
2
+ require 'rbbt/workflow/usage'
3
+
4
+ module Ansible
5
+ def self.play(playbook, inventory = nil)
6
+ inventory = Rbbt.etc.ansible_inventory.find
7
+ Log.with_severity 0 do
8
+ TmpFile.with_file do |tmp|
9
+ if Hash === playbook
10
+ Open.write(tmp, [playbook].to_yaml)
11
+ playbook = tmp
12
+ end
13
+ CMD.cmd_log("ansible-playbook -i #{inventory} #{playbook}")
14
+ end
15
+ end
16
+ end
17
+
18
+ def self.clean_symbols(hash)
19
+ new = {}
20
+ hash.each do |key,value|
21
+ key = key.to_s
22
+ value = case value
23
+ when Symbol
24
+ value.to_s
25
+ when Hash
26
+ self.clean_symbols(value)
27
+ else
28
+ value
29
+ end
30
+ new[key] = value
31
+ end
32
+ new
33
+ end
34
+
35
+ def self.workflow2playbook(workflow, task, options = {})
36
+ job_options = workflow.get_SOPT(workflow.tasks[task])
37
+
38
+ tasks = workflow.job(task, nil, job_options).exec
39
+
40
+ hosts = options[:hosts] || 'localhost'
41
+
42
+ clean_tasks = tasks.collect{|task| self.clean_symbols task }
43
+ {"hosts" => hosts, "tasks" => clean_tasks}
44
+ end
45
+
46
+ def self.playbook(file, task = nil, options = {})
47
+ task = 'default' if task.nil?
48
+
49
+ workflow = Workflow.require_workflow file
50
+ task = workflow.tasks.keys.last if workflow.tasks[task].nil?
51
+ workflow2playbook workflow, task, options
52
+ end
53
+ end
@@ -0,0 +1,60 @@
1
+ require 'rbbt/workflow'
2
+
3
+ module Ansible
4
+ module AnsibleWorkflow
5
+ def self.extended(object)
6
+ class << object
7
+ attr_accessor :ans_tasks
8
+ end
9
+
10
+ object.helper :register do |task_info|
11
+ desc = task.description if task
12
+ name ||= desc || short_path
13
+ task_info = {"name" => name}.merge(task_info)
14
+ @ans_tasks ||= []
15
+ @ans_tasks << task_info
16
+ task
17
+ end
18
+
19
+ object.helper :ans do |name, info|
20
+ register({ name => info})
21
+ end
22
+
23
+ object.helper :add do |name, info|
24
+ @ans_tasks.last[name.to_s] = info
25
+ end
26
+
27
+ object.helper :shell do |cmd|
28
+ register({"shell" => cmd.strip})
29
+ end
30
+
31
+ object.helper :sudo do |cmd|
32
+ register({"shell" => cmd.strip, "become" => 'yes'})
33
+ end
34
+
35
+ object.helper :singularity do |scmd|
36
+ img = config :singularity_img, :build, :test, :small, :default => '/data/img/singularity/rbbt/rbbt.simg'
37
+ container = config :singularity_container, :build, :test, :small, :default => '/data/img/sandbox/mvazque2/'
38
+ cmd = <<-EOF
39
+ singularity exec -C -H '#{container}' '#{img}' #{scmd}
40
+ EOF
41
+ register({"shell" => cmd.strip, "name" => short_path})
42
+ end
43
+
44
+
45
+ object.helper :produce_task do
46
+ @ans_tasks
47
+ end
48
+ end
49
+
50
+ def play(name = nil, &block)
51
+ name = Misc.snake_case(@description) if name.nil?
52
+ task name => :yaml do |*args|
53
+ self.instance_exec *args, &block
54
+ dependencies.inject([]){|acc,dep| acc += dep.load } + produce_task
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+
@@ -12,6 +12,9 @@ class Step
12
12
  attr_accessor :exec
13
13
  attr_accessor :relocated
14
14
  attr_accessor :result, :mutex, :seen
15
+ attr_accessor :real_inputs, :original_task_name
16
+
17
+ RBBT_DEBUG_CLEAN = ENV["RBBT_DEBUG_CLEAN"] == 'true'
15
18
 
16
19
  class << self
17
20
  attr_accessor :lock_dir
@@ -143,17 +146,24 @@ class Step
143
146
  seen = []
144
147
  while path = deps.pop
145
148
  dep_info = archived_info[path]
146
- dep_info[:inputs].each do |k,v|
147
- all_inputs[k] = v unless all_inputs.include?(k)
148
- end if dep_info[:inputs]
149
- deps.concat(dep_info[:dependencies].collect{|p| p.last } - seen) if dep_info[:dependencies]
150
- deps.concat(dep_info[:archived_dependencies].collect{|p| p.last } - seen) if dep_info[:archived_dependencies]
149
+ if dep_info
150
+ dep_info[:inputs].each do |k,v|
151
+ all_inputs[k] = v unless all_inputs.include?(k)
152
+ end if dep_info[:inputs]
153
+ deps.concat(dep_info[:dependencies].collect{|p| p.last } - seen) if dep_info[:dependencies]
154
+ deps.concat(dep_info[:archived_dependencies].collect{|p| p.last } - seen) if dep_info[:archived_dependencies]
155
+ end
151
156
  seen << path
152
157
  end
153
158
 
154
159
  all_inputs
155
160
  end
156
161
 
162
+ def dependencies=(dependencies)
163
+ @dependencies = dependencies
164
+ set_info :dependencies, dependencies.collect{|dep| [dep.task_name, dep.name, dep.path]} if dependencies
165
+ end
166
+
157
167
  def recursive_inputs
158
168
  if NamedArray === inputs
159
169
  i = {}
@@ -449,6 +459,7 @@ class Step
449
459
  status << "not running" if ! done? && ! running?
450
460
  status.unshift " " if status.any?
451
461
  Log.high "Cleaning step: #{path}#{status * " "}"
462
+ Log.stack caller if RBBT_DEBUG_CLEAN
452
463
  abort if ! done? && running?
453
464
  Step.clean(path)
454
465
  self
@@ -8,6 +8,16 @@ class Step
8
8
  end
9
9
  end
10
10
 
11
+ def self.serialize_info(info)
12
+ info = info.clean_version if IndiferentHash === info
13
+ INFO_SERIALIZER.dump(info)
14
+ end
15
+
16
+ def self.load_serialized_info(io)
17
+ IndiferentHash.setup(INFO_SERIALIZER.load(io))
18
+ end
19
+
20
+
11
21
  def self.wait_for_jobs(jobs)
12
22
  jobs = [jobs] if Step === jobs
13
23
  begin
@@ -59,7 +69,7 @@ class Step
59
69
  def self.step_info(path)
60
70
  begin
61
71
  Open.open(info_file(path), :mode => 'rb') do |f|
62
- INFO_SERIALIZER.load(f)
72
+ self.load_serialized_info(f)
63
73
  end
64
74
  rescue Exception
65
75
  Log.exception $!
@@ -83,18 +93,18 @@ class Step
83
93
 
84
94
  Log.debug "Saving job input #{name} (#{type}) into #{path}"
85
95
  case
86
- when Array === value
87
- Open.write(path, value * "\n")
88
- when IO === value
89
- Open.write(path, value)
90
- when type == "file"
96
+ when Step === value
97
+ Open.link(value.path, path)
98
+ when type.to_s == "file"
91
99
  if String === value && File.exists?(value)
92
100
  Open.link(value, path)
93
101
  else
94
- Open.write(path + '.read', value.to_s)
102
+ Open.write(path + '.yaml', value.to_yaml)
95
103
  end
96
- when Step === value
97
- value = value.produce.load
104
+ when Array === value
105
+ Open.write(path, value * "\n")
106
+ when IO === value
107
+ Open.write(path, value)
98
108
  else
99
109
  Open.write(path, value.to_s)
100
110
  end
@@ -104,7 +114,7 @@ class Step
104
114
  def self.save_job_inputs(job, dir, options = nil)
105
115
  options = IndiferentHash.setup options.dup if options
106
116
 
107
- task_name = job.task_name
117
+ task_name = Symbol === job.overriden ? job.overriden : job.task_name
108
118
  workflow = job.workflow
109
119
  workflow = Kernel.const_get workflow if String === workflow
110
120
  task_info = workflow.task_info(task_name)
@@ -113,15 +123,17 @@ class Step
113
123
  input_defaults = task_info[:input_defaults]
114
124
 
115
125
  inputs = {}
126
+ real_inputs = job.real_inputs || job.info[:real_inputs]
116
127
  job.recursive_inputs.zip(job.recursive_inputs.fields).each do |value,name|
117
128
  next unless task_inputs.include? name.to_sym
118
- next if options and ! options.include?(name)
129
+ next unless real_inputs.include? name.to_sym
130
+ next if options && ! options.include?(name)
119
131
  next if value.nil?
120
132
  next if input_defaults[name] == value
121
133
  inputs[name] = value
122
134
  end
123
135
 
124
- if options.include? 'override_dependencies'
136
+ if options && options.include?('override_dependencies')
125
137
  inputs.merge!(:override_dependencies => open[:override_dependencies])
126
138
  input_types = IndiferentHash.setup(input_types.merge(:override_dependencies => :array))
127
139
  end
@@ -188,7 +200,7 @@ class Step
188
200
  info_lock.lock if check_lock and false
189
201
  begin
190
202
  Open.open(info_file, :mode => 'rb') do |file|
191
- INFO_SERIALIZER.load(file) #|| {}
203
+ Step.load_serialized_info(file)
192
204
  end
193
205
  ensure
194
206
  info_lock.unlock if check_lock and false
@@ -204,7 +216,7 @@ class Step
204
216
  Log.debug{"Error loading info file: " + info_file}
205
217
  Log.exception $!
206
218
  Open.rm info_file
207
- Misc.sensiblewrite(info_file, INFO_SERIALIZER.dump({:status => :error, :messages => ["Info file lost"]}))
219
+ Misc.sensiblewrite(info_file, Step.serialize_info({:status => :error, :messages => ["Info file lost"]}))
208
220
  raise $!
209
221
  end
210
222
  end
@@ -212,10 +224,10 @@ class Step
212
224
  def init_info(force = false)
213
225
  return nil if @exec || info_file.nil? || (Open.exists?(info_file) && ! force)
214
226
  Open.lock(info_file, :lock => info_lock) do
215
- i = {:status => :waiting, :pid => Process.pid, :path => path}
227
+ i = {:status => :waiting, :pid => Process.pid, :path => path, :real_inputs => real_inputs}
216
228
  i[:dependencies] = dependencies.collect{|dep| [dep.task_name, dep.name, dep.path]} if dependencies
217
- @info_cache = i
218
- Misc.sensiblewrite(info_file, INFO_SERIALIZER.dump(i), :force => true, :lock => false)
229
+ Misc.sensiblewrite(info_file, Step.serialize_info(i), :force => true, :lock => false)
230
+ @info_cache = IndiferentHash.setup(i)
219
231
  @info_cache_time = Time.now
220
232
  end
221
233
  end
@@ -227,9 +239,9 @@ class Step
227
239
  Open.lock(info_file, :lock => info_lock) do
228
240
  i = info(false).dup
229
241
  i[key] = value
230
- @info_cache = i
231
- dump = INFO_SERIALIZER.dump(i)
232
- Misc.sensiblewrite(info_file, dump, :force => true, :lock => false)
242
+ dump = Step.serialize_info(i)
243
+ @info_cache = IndiferentHash.setup(i)
244
+ Misc.sensiblewrite(info_file, dump, :force => true, :lock => false) if Open.exists?(info_file)
233
245
  @info_cache_time = Time.now
234
246
  value
235
247
  end
@@ -242,9 +254,9 @@ class Step
242
254
  Open.lock(info_file, :lock => info_lock) do
243
255
  i = info(false)
244
256
  i.merge! hash
245
- @info_cache = i
246
- dump = INFO_SERIALIZER.dump(i)
247
- Misc.sensiblewrite(info_file, dump, :force => true, :lock => false)
257
+ dump = Step.serialize_info(i)
258
+ @info_cache = IndiferentHash.setup(i)
259
+ Misc.sensiblewrite(info_file, dump, :force => true, :lock => false) if Open.exists?(info_file)
248
260
  @info_cache_time = Time.now
249
261
  value
250
262
  end
@@ -537,7 +549,7 @@ class Step
537
549
  end
538
550
 
539
551
  def file(name)
540
- Path.setup(File.join(files_dir, name.to_s))
552
+ Path.setup(File.join(files_dir, name.to_s), workflow, self)
541
553
  end
542
554
 
543
555
  def save_file(name, content)
@@ -92,7 +92,13 @@ class Step
92
92
  (job.done? && job.dirty?) || (job.error? && job.dirty?) ||
93
93
  (!(job.noinfo? || job.done? || job.error? || job.aborted? || job.running?))
94
94
 
95
- job.clean unless job.resumable? && (job.updated? && ! job.dirty?)
95
+ if ! (job.resumable? && (job.updated? && ! job.dirty?))
96
+ Log.high "About to clean -- status: #{status}, present #{File.exists?(job.path)}, " +
97
+ %w(done? error? recoverable_error? noinfo? updated? dirty? aborted? running? resumable?).
98
+ collect{|v| [v, job.send(v)]*": "} * ", " if RBBT_DEBUG_CLEAN
99
+
100
+ job.clean
101
+ end
96
102
  job.set_info :status, :cleaned
97
103
  end
98
104
 
@@ -121,7 +127,7 @@ class Step
121
127
  end
122
128
 
123
129
  def input_dependencies
124
- inputs.flatten.select{|i| Step === i}
130
+ (inputs.flatten.select{|i| Step === i} + inputs.flatten.select{|dep| Path === dep && Step === dep.resource}.collect{|dep| dep.resource})
125
131
  end
126
132
 
127
133
 
@@ -112,7 +112,7 @@ 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?))
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)))
116
116
  end
117
117
 
118
118
  def dependency_checks
@@ -128,7 +128,7 @@ class Step
128
128
  end
129
129
 
130
130
  def input_checks
131
- inputs.select{|i| Step === i }.
131
+ (inputs.select{|i| Step === i } + inputs.select{|i| Path === i && Step === i.resource}.collect{|i| i.resource}).
132
132
  select{|dependency| dependency.updatable? }
133
133
  end
134
134
 
@@ -154,25 +154,28 @@ class Step
154
154
  canfail_paths = self.canfail_paths
155
155
  this_mtime = Open.mtime(self.path) if Open.exists?(self.path)
156
156
 
157
- checks.each do |dep|
158
- next unless dep.updatable?
159
- dep_done = dep.done?
157
+ outdated_time = checks.select{|dep| dep.updatable? && dep.done? && Persist.newer?(path, dep.path) }
158
+ outdated_dep = checks.reject{|dep| dep.done? || (dep.error? && ! dep.recoverable_error? && canfail_paths.include?(dep.path)) }
160
159
 
161
- begin
162
- if this_mtime && dep_done && Open.exists?(dep.path) && (Open.mtime(dep.path) > this_mtime + 1)
163
- outdated_time << dep
164
- end
165
- rescue
166
- end
160
+ #checks.each do |dep|
161
+ # next unless dep.updatable?
162
+ # dep_done = dep.done?
167
163
 
168
- # Is this pointless? this would mean some dep got updated after a later
169
- # dep but but before this one.
170
- #if (! dep.done? && ! canfail_paths.include?(dep.path)) || ! dep.updated?
164
+ # begin
165
+ # if this_mtime && dep_done && Open.exists?(dep.path) && (Open.mtime(dep.path) > this_mtime + 1)
166
+ # outdated_time << dep
167
+ # end
168
+ # rescue
169
+ # end
171
170
 
172
- if (! dep_done && ! canfail_paths.include?(dep.path))
173
- outdated_dep << dep
174
- end
175
- end
171
+ # # Is this pointless? this would mean some dep got updated after a later
172
+ # # dep but but before this one.
173
+ # #if (! dep.done? && ! canfail_paths.include?(dep.path)) || ! dep.updated?
174
+
175
+ # if (! dep_done && ! canfail_paths.include?(dep.path))
176
+ # outdated_dep << dep
177
+ # end
178
+ #end
176
179
 
177
180
  Log.high "Some newer files found: #{Misc.fingerprint outdated_time}" if outdated_time.any?
178
181
  Log.high "Some outdated files found: #{Misc.fingerprint outdated_dep}" if outdated_dep.any?
@@ -215,7 +218,7 @@ class Step
215
218
  no_load = :stream if no_load
216
219
 
217
220
  Open.write(pid_file, Process.pid.to_s) unless Open.exists?(path) or Open.exists?(pid_file)
218
- result_type = @task.result_type
221
+ result_type = @task.result_type if @task
219
222
  result_type = info[:result_type] if result_type.nil?
220
223
  result = Persist.persist "Job", result_type, :file => path, :check => persist_checks, :no_load => no_load do
221
224
  if Step === Step.log_relay_step and not self == Step.log_relay_step
@@ -67,8 +67,10 @@ class Step
67
67
  next unless File.exists?(step.path)
68
68
  job_files << step.path
69
69
  job_files << step.info_file if File.exists?(step.info_file)
70
+ job_files << Step.md5_file(step.path) if File.exists?(Step.md5_file step.path)
70
71
  job_file_dir_content = Dir.glob(step.files_dir + '/**/*')
71
72
  job_files += job_file_dir_content
73
+ job_files << step.files_dir if File.exists?(step.files_dir)
72
74
  rec_dependencies = Set.new
73
75
 
74
76
  next unless recursive
@@ -26,15 +26,25 @@ module Workflow
26
26
  workload
27
27
  end
28
28
 
29
+ def self.workload(jobs)
30
+ jobs.inject({}) do |acc,job|
31
+ Orchestrator.job_workload(job).each do |j,d|
32
+ acc[j] = d unless acc.keys.collect{|k| k.path }.include? j.path
33
+ end
34
+ acc
35
+ end
36
+ end
37
+
29
38
  def self.job_rules(rules, job)
30
39
  workflow = job.workflow.to_s
31
40
  task_name = job.task_name.to_s
41
+ defaults = rules["defaults"] || {}
32
42
 
33
- return IndiferentHash.setup(rules["defaults"]) unless rules[workflow]
34
- return IndiferentHash.setup(rules["defaults"]) unless rules[workflow][task_name]
43
+ return IndiferentHash.setup(defaults) unless rules[workflow]
44
+ return IndiferentHash.setup(defaults) unless rules[workflow][task_name]
35
45
 
36
46
  job_rules = IndiferentHash.setup(rules[workflow][task_name])
37
- rules["defaults"].each{|k,v| job_rules[k] = v if job_rules[k].nil? } if rules["defaults"]
47
+ defaults.each{|k,v| job_rules[k] = v if job_rules[k].nil? } if defaults
38
48
  job_rules
39
49
  end
40
50
 
@@ -143,18 +153,25 @@ module Workflow
143
153
  end
144
154
  end
145
155
 
146
- def erase_job_dependencies(job, rules, workload, top_level_jobs)
156
+ def erase_job_dependencies(job, rules, all_jobs, top_level_jobs)
147
157
  job.dependencies.each do |dep|
148
158
  next if top_level_jobs.include? dep.path
149
159
  next unless Orchestrator.job_rules(rules, dep)["erase"].to_s == 'true'
150
160
 
151
- list = (workload.keys - [job]).collect{|pending| pending.dependencies}.flatten
152
- next if list.include?(dep)
161
+ dep_path = dep.path
162
+ parents = all_jobs.select do |parent|
163
+ paths = parent.info[:dependencies].nil? ? parent.dependencies.collect{|d| d.path } : parent.info[:dependencies].collect{|d| d.last }
164
+ paths.include? dep_path
165
+ end
166
+
167
+ next unless parents.reject{|parent| parent.done? }.empty?
153
168
 
154
- Log.high "Erasing #{dep.path} from #{job.path}"
155
- job.archive_deps
156
- job.copy_files_dir
157
- job.dependencies = job.dependencies - [dep]
169
+ parents.each do |parent|
170
+ Log.high "Erasing #{dep.path} from #{parent.path}"
171
+ parent.archive_deps
172
+ parent.copy_files_dir
173
+ parent.dependencies = parent.dependencies - [dep]
174
+ end
158
175
  dep.clean
159
176
  end
160
177
  end
@@ -162,7 +179,8 @@ module Workflow
162
179
  def process(rules, jobs)
163
180
  begin
164
181
 
165
- workload = jobs.inject({}){|acc,job| acc.merge!(Orchestrator.job_workload(job)) }
182
+ workload = Orchestrator.workload(jobs)
183
+ all_jobs = workload.keys
166
184
 
167
185
  top_level_jobs = jobs.collect{|job| job.path }
168
186
  while workload.any?
@@ -187,7 +205,7 @@ module Workflow
187
205
  when job.done?
188
206
  Log.debug "Orchestrator done #{job.path}"
189
207
  release_resources(job)
190
- erase_job_dependencies(job, rules, workload, top_level_jobs)
208
+ erase_job_dependencies(job, rules, all_jobs, top_level_jobs)
191
209
 
192
210
  when job.running?
193
211
  next