scout-gear 8.1.0 → 9.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +22 -0
  3. data/VERSION +1 -1
  4. data/bin/scout +1 -0
  5. data/lib/rbbt-scout.rb +2 -1
  6. data/lib/scout/cmd.rb +9 -5
  7. data/lib/scout/indiferent_hash.rb +17 -0
  8. data/lib/scout/log/progress/report.rb +1 -0
  9. data/lib/scout/log.rb +14 -11
  10. data/lib/scout/misc/filesystem.rb +2 -3
  11. data/lib/scout/offsite/ssh.rb +3 -0
  12. data/lib/scout/offsite/step.rb +20 -3
  13. data/lib/scout/open/stream.rb +0 -1
  14. data/lib/scout/open.rb +8 -8
  15. data/lib/scout/path.rb +1 -1
  16. data/lib/scout/persist/serialize.rb +1 -1
  17. data/lib/scout/resource/open.rb +8 -0
  18. data/lib/scout/resource/path.rb +12 -9
  19. data/lib/scout/resource/software.rb +4 -2
  20. data/lib/scout/resource.rb +2 -0
  21. data/lib/scout/tsv/dumper.rb +3 -1
  22. data/lib/scout/tsv/parser.rb +13 -3
  23. data/lib/scout/work_queue.rb +1 -0
  24. data/lib/scout/workflow/deployment/orchestrator.rb +17 -8
  25. data/lib/scout/workflow/step/dependencies.rb +9 -3
  26. data/lib/scout/workflow/step/info.rb +8 -0
  27. data/lib/scout/workflow/step/inputs.rb +5 -0
  28. data/lib/scout/workflow/step/status.rb +22 -2
  29. data/lib/scout/workflow/step.rb +11 -4
  30. data/lib/scout/workflow/task/dependencies.rb +2 -0
  31. data/lib/scout/workflow/task/inputs.rb +14 -9
  32. data/lib/scout/workflow/task.rb +4 -2
  33. data/lib/scout/workflow/usage.rb +21 -33
  34. data/lib/scout/workflow.rb +17 -13
  35. data/scout-gear.gemspec +9 -3
  36. data/scout_commands/resource/produce +66 -0
  37. data/scout_commands/template +52 -0
  38. data/scout_commands/workflow/install +3 -0
  39. data/scout_commands/workflow/task +24 -5
  40. data/share/software/install_helpers +2 -2
  41. data/share/templates/command +25 -0
  42. data/share/templates/workflow.rb +14 -0
  43. data/test/scout/offsite/test_step.rb +0 -1
  44. data/test/scout/test_persist.rb +2 -2
  45. data/test/scout/test_work_queue.rb +1 -1
  46. data/test/scout/tsv/test_parser.rb +21 -0
  47. data/test/scout/workflow/step/test_info.rb +0 -1
  48. data/test/scout/workflow/task/test_dependencies.rb +2 -0
  49. data/test/scout/workflow/task/test_inputs.rb +0 -1
  50. data/test/scout/workflow/test_definition.rb +1 -1
  51. metadata +8 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ca509bfb5065aabcdae73545139db0f8b04748084821e002c0475a55be5cb70
4
- data.tar.gz: 6f0333ca6dd0ceee0ea9290cf3c30f7164c2f0732b76ce739e29da19a0687242
3
+ metadata.gz: 98b3f84350f2f451b717f004bfc97cd7767f7e0fed58e1a2d0cd023bc700185f
4
+ data.tar.gz: '00847ad4d92b1cab22305ea867dc12c870b22e192e79536917f82aa90cc82989'
5
5
  SHA512:
6
- metadata.gz: 2cbd82d97ec0dad50e624cda26ae6a05aeba8b9e5ff07a5b4746c677b8e2ab1996378237095ba09a70f8ed8cc926d782c1677aa24d6f94784f560090d6845a2c
7
- data.tar.gz: aa9529b3393016c846b578b736428b964519d2fb5c1507a6335eff651d0588a5d9191cc61cff52279c18902f2efce386415099bcd92f8736f6d67cef1d33b561
6
+ metadata.gz: 4af5e13873fa13dea33161e9200aa725bb4329899e9242ae6504ffae2ab82e7eb01b82a53edc2a4331ede06d0f12bb07f86f579cb29ecbf0d36e791bf6d53f3e
7
+ data.tar.gz: fc773eb933e5c851aa1d642e872df02d282fbcb29ee1b8e1bf150ffebf9bd4ce8c3670d43a284ff2c8197477a8cf6f71dfcd49b265ad938c723292ec57579998
data/.vimproject CHANGED
@@ -10,6 +10,7 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
10
10
  glob
11
11
  doc
12
12
  update
13
+ template
13
14
  offsite
14
15
  workflow=workflow{
15
16
  task
@@ -17,6 +18,9 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
17
18
  info
18
19
  install
19
20
  }
21
+ resource=resource{
22
+ produce
23
+ }
20
24
  }
21
25
  lib=lib {
22
26
  scout-gear.rb
@@ -115,6 +119,7 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
115
119
  progress.rb
116
120
  provenance.rb
117
121
  status.rb
122
+ inputs.rb
118
123
  }
119
124
  task.rb
120
125
  task=task{
@@ -168,6 +173,9 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
168
173
  sync.rb
169
174
  step.rb
170
175
  }
176
+ hpc=hpc{
177
+ slurm.rb
178
+ }
171
179
  }
172
180
  }
173
181
  test=test {
@@ -198,7 +206,18 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
198
206
  test_task.rb
199
207
  test_usage.rb
200
208
  test_util.rb
209
+ step=step{
210
+ test_dependencies.rb
211
+ test_info.rb
212
+ test_load.rb
213
+ test_provenance.rb
214
+ test_status.rb
201
215
  }
216
+ task=task{
217
+ test_dependencies.rb
218
+ test_inputs.rb
219
+ }
220
+ }
202
221
  indiferent_hash=indiferent_hash{
203
222
  test_case_insensitive.rb
204
223
  test_options.rb
@@ -209,6 +228,9 @@ scout-gear=/$PWD filter="*.rb *.yaml" {
209
228
  software=software{
210
229
  install_helpers
211
230
  }
231
+ templates=templates{
232
+ workflow.rb
233
+ }
212
234
  }
213
235
 
214
236
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 8.1.0
1
+ 9.0.0
data/bin/scout CHANGED
@@ -54,6 +54,7 @@ if dev_dir
54
54
  end
55
55
  end
56
56
 
57
+ require 'scout'
57
58
 
58
59
  require 'scout/simple_opt'
59
60
 
data/lib/rbbt-scout.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  $LOAD_PATH.unshift File.join(__dir__, '../modules/rbbt-util/lib')
2
2
  module Rbbt
3
3
  extend Resource
4
- self.pkgdir = 'rbbt'
5
4
  self.path_maps = Path.path_maps.merge(:rbbt_lib => File.expand_path(File.join(__dir__, '../modules/rbbt-util/', '{TOPLEVEL}','{SUBPATH}')))
6
5
  end
6
+
7
+ Resource.set_software_env Rbbt.software
data/lib/scout/cmd.rb CHANGED
@@ -20,17 +20,22 @@ module CMD
20
20
  end
21
21
  end
22
22
 
23
+
23
24
  def self.get_tool(tool)
24
25
  return tool.to_s unless TOOLS[tool]
25
26
 
26
27
  @@init_cmd_tool ||= IndiferentHash.setup({})
28
+
29
+ claim, test, block, cmd = TOOLS[tool]
30
+ cmd = tool.to_s if cmd.nil?
31
+
27
32
  if !@@init_cmd_tool[tool]
28
- claim, test, block, cmd = TOOLS[tool]
33
+
29
34
  begin
30
35
  if test
31
36
  CMD.cmd(test + " ")
32
37
  else
33
- CMD.cmd("#{tool} --help")
38
+ CMD.cmd("#{cmd} --help")
34
39
  end
35
40
  rescue
36
41
  if claim
@@ -43,7 +48,7 @@ module CMD
43
48
  version = nil
44
49
  ["--version", "-version", "--help", ""].each do |f|
45
50
  begin
46
- version_txt += CMD.cmd("#{tool} #{f} 2>&1", :nofail => true).read
51
+ version_txt += CMD.cmd("#{cmd} #{f} 2>&1", :nofail => true).read
47
52
  version = CMD.scan_version_text(version_txt, tool)
48
53
  break if version
49
54
  rescue
@@ -56,9 +61,8 @@ module CMD
56
61
  return cmd if cmd
57
62
  end
58
63
 
59
- tool.to_s
64
+ cmd
60
65
  end
61
-
62
66
  def self.scan_version_text(text, cmd = nil)
63
67
  cmd = "NOCMDGIVE" if cmd.nil? || cmd.empty?
64
68
  text = Misc.fixutf8 text
@@ -75,5 +75,22 @@ module IndiferentHash
75
75
  end
76
76
  clean
77
77
  end
78
+
79
+ def slice(*list)
80
+ ext_list = []
81
+ list.each do |e|
82
+ case e
83
+ when Symbol
84
+ ext_list << e
85
+ ext_list << e.to_s
86
+ when String
87
+ ext_list << e
88
+ ext_list << e.to_sym
89
+ else
90
+ ext_list << e
91
+ end
92
+ end
93
+ IndiferentHash.setup(super(*ext_list))
94
+ end
78
95
  end
79
96
 
@@ -161,6 +161,7 @@ module Log
161
161
  def save
162
162
  info = {:start => @start, :last_time => @last_time, :last_count => @last_count, :last_percent => @last_percent, :desc => @desc, :ticks => @ticks, :max => @max, :mean => @mean}
163
163
  info.delete_if{|k,v| v.nil?}
164
+ FileUtils.mkdir_p File.dirname(file) unless File.exist?(File.dirname(file))
164
165
  File.write(file, info.to_yaml)
165
166
  end
166
167
 
data/lib/scout/log.rb CHANGED
@@ -51,17 +51,19 @@ module Log
51
51
 
52
52
  def self.tty_size
53
53
  @@tty_size ||= Log.ignore_stderr do
54
- begin
55
- IO.console.winsize.last
56
- rescue Exception
57
- begin
58
- res = `tput li`
59
- res = nil if res == ""
60
- res || ENV["TTY_SIZE"] || 80
61
- rescue Exception
62
- ENV["TTY_SIZE"] || 80
63
- end
64
- end
54
+ size = begin
55
+ IO.console.winsize.last
56
+ rescue Exception
57
+ begin
58
+ res = `tput li`
59
+ res = nil if res == ""
60
+ res || ENV["TTY_SIZE"] || 80
61
+ rescue Exception
62
+ ENV["TTY_SIZE"] || 80
63
+ end
64
+ end
65
+ size = size.to_i if String === size
66
+ size
65
67
  end
66
68
  end
67
69
 
@@ -269,6 +271,7 @@ module Log
269
271
  line = line.sub('`',"'")
270
272
  color = :green if line =~ /workflow/
271
273
  color = :blue if line =~ /scout-/
274
+ color = :cyan if line =~ /rbbt-/
272
275
  if color
273
276
  Log.color color, line
274
277
  else
@@ -16,11 +16,10 @@ module Misc
16
16
 
17
17
  basedir += "/" unless basedir.slice(-2,-1) == "/"
18
18
 
19
- if path.index(basedir) == 0
20
- return path[basedir.length..-1]
19
+ if path.start_with?(basedir)
20
+ return path.slice(basedir.length, basedir.length)
21
21
  else
22
22
  return nil
23
23
  end
24
24
  end
25
-
26
25
  end
@@ -21,6 +21,9 @@ class SSHLine
21
21
  ch.exec 'bash -l'
22
22
  end
23
23
 
24
+ @ch.send_data("[[ -f ~/.scout/environment ]] && source ~/.scout/environment\n")
25
+ @ch.send_data("[[ -f ~/.rbbt/environment ]] && source ~/.rbbt/environment\n")
26
+
24
27
  @ch.on_data do |_,data|
25
28
  if m = data.match(/DONECMD: (\d+)\n/)
26
29
  @exit_status = m[1].to_i
@@ -5,14 +5,14 @@ require_relative 'sync'
5
5
  module OffsiteStep
6
6
 
7
7
  extend MetaExtension
8
- extension_attr :server, :workflow_name, :clean_id, :provided_inputs
8
+ extension_attr :server, :workflow_name, :clean_id, :slurm
9
9
 
10
10
  def inputs_directory
11
11
  @inputs_directory ||= begin
12
12
  if provided_inputs && provided_inputs.any?
13
13
  file = ".scout/tmp/step_inputs/#{workflow}/#{task_name}/#{name}"
14
14
  TmpFile.with_path do |inputs_dir|
15
- task.save_inputs(inputs_dir, provided_inputs)
15
+ save_inputs(inputs_dir)
16
16
  SSHLine.rsync(inputs_dir, file, target: server, directory: true)
17
17
  end
18
18
  file
@@ -68,6 +68,19 @@ job = wf.job(:#{task_name}, "#{clean_name}");
68
68
  status == :done
69
69
  end
70
70
 
71
+ def orchestrate_slurm
72
+ bundle_files = offsite_job_ssh <<~EOF
73
+ require 'rbbt/hpc'
74
+ HPC::BATCH_MODULE = HPC.batch_system "SLURM"
75
+ HPC::BATCH_MODULE.orchestrate_job(job, {})
76
+ job.join
77
+ job.bundle_files
78
+ EOF
79
+ SSHLine.sync(bundle_files, source: server)
80
+ self.load
81
+ end
82
+
83
+
71
84
  def exec
72
85
  bundle_files = offsite_job_ssh <<~EOF
73
86
  job.run
@@ -78,6 +91,10 @@ job = wf.job(:#{task_name}, "#{clean_name}");
78
91
  end
79
92
 
80
93
  def run
81
- exec
94
+ if slurm
95
+ orchestrate_slurm
96
+ else
97
+ exec
98
+ end
82
99
  end
83
100
  end
@@ -66,7 +66,6 @@ module Open
66
66
  into.close if into and into_close and not into.closed?
67
67
  block.call if block_given?
68
68
 
69
- Log.debug "Consume stream done #{Log.fingerprint io} -> #{Log.fingerprint(into_path ||into)}"
70
69
  last_c
71
70
  rescue Aborted
72
71
  Thread.current["exception"] = true
data/lib/scout/open.rb CHANGED
@@ -20,21 +20,21 @@ module Open
20
20
  end
21
21
  end
22
22
 
23
- def self.get_stream(file, mode = 'r')
23
+ def self.get_stream(file, mode = 'r', options = {})
24
24
  return file if Open.is_stream?(file)
25
25
  return file.stream if Open.has_stream?(file)
26
26
  file = file.find if Path === file
27
27
 
28
- return Open.ssh(file) if Open.ssh?(file)
29
- return Open.wget(file) if Open.remote?(file)
28
+ return Open.ssh(file, options) if Open.ssh?(file)
29
+ return Open.wget(file, options) if Open.remote?(file)
30
30
 
31
31
  File.open(file, mode)
32
32
  end
33
33
 
34
- def self.file_open(file, grep = false, mode = 'r', invert_grep = false)
34
+ def self.file_open(file, grep = false, mode = 'r', invert_grep = false, options = {})
35
35
  Open.mkdir File.dirname(file) if mode.include? 'w'
36
36
 
37
- stream = get_stream(file, mode)
37
+ stream = get_stream(file, mode, options)
38
38
 
39
39
  if grep
40
40
  grep(stream, grep, invert_grep)
@@ -58,7 +58,7 @@ module Open
58
58
  def self.open(file, options = {})
59
59
  if IO === file || StringIO === file
60
60
  if block_given?
61
- res = yield file
61
+ res = yield file, options
62
62
  file.close
63
63
  return res
64
64
  else
@@ -72,7 +72,7 @@ module Open
72
72
 
73
73
  options[:noz] = true if mode.include? "w"
74
74
 
75
- io = file_open(file, options[:grep], mode, options[:invert_grep])
75
+ io = file_open(file, options[:grep], mode, options[:invert_grep], options)
76
76
 
77
77
  io = unzip(io) if ((String === file and zip?(file)) and not options[:noz]) or options[:zip]
78
78
  io = gunzip(io) if ((String === file and gzip?(file)) and not options[:noz]) or options[:gzip]
@@ -88,7 +88,7 @@ module Open
88
88
  rescue DontClose
89
89
  res = $!.payload
90
90
  rescue Exception
91
- io.abort if io.respond_to? :abort
91
+ io.abort $! if io.respond_to? :abort
92
92
  io.join if io.respond_to? :join
93
93
  raise $!
94
94
  ensure
data/lib/scout/path.rb CHANGED
@@ -32,7 +32,7 @@ module Path
32
32
  prevpath = prevpath.to_s if Symbol === prevpath
33
33
 
34
34
  subpath = File.join(prevpath.to_s, subpath) if prevpath
35
- new = self.empty? ? subpath : File.join(self, subpath)
35
+ new = self.empty? ? subpath.dup : File.join(self, subpath)
36
36
  self.annotate(new)
37
37
  new
38
38
  end
@@ -104,7 +104,7 @@ module Persist
104
104
 
105
105
  if type == :binary
106
106
  content.force_encoding("ASCII-8BIT") if content.respond_to? :force_encoding
107
- Open.open(path, :mode => 'wb') do |f|
107
+ Open.open(file, :mode => 'wb') do |f|
108
108
  f.puts content
109
109
  end
110
110
  content
@@ -0,0 +1,8 @@
1
+ class << Open
2
+ alias _just_open open
3
+
4
+ def open(file, *args, **kwargs, &block)
5
+ file.produce if Path === file
6
+ _just_open(file, *args, **kwargs, &block)
7
+ end
8
+ end
@@ -3,7 +3,7 @@ module Path
3
3
  return self if ! force && (Open.exist?(self) || @produced)
4
4
  begin
5
5
  if Resource === self.pkgdir
6
- self.pkgdir.produce self
6
+ self.pkgdir.produce self, force
7
7
  else
8
8
  false
9
9
  end
@@ -13,7 +13,7 @@ module Path
13
13
  message = $!.message
14
14
  message = "No exception message" if message.nil? || message.empty?
15
15
  Log.warn "Error producing #{self}: #{message}"
16
- false
16
+ raise $!
17
17
  ensure
18
18
  @produced = true
19
19
  end
@@ -33,13 +33,16 @@ module Path
33
33
  end
34
34
 
35
35
  def produce_and_find(extension = nil, *args)
36
- if extension
37
- found = find_with_extension(extension, *args)
38
- found.exists? ? found : produce_with_extension(extension, *args)
39
- else
40
- found = find
41
- found.exists? ? found : produce(*args)
42
- end
36
+ found = if extension
37
+ found = find_with_extension(extension, *args)
38
+ found.exists? ? found : produce_with_extension(extension, *args)
39
+ else
40
+ found = find
41
+ found.exists? ? found : produce(*args)
42
+ end
43
+ raise "Not found: #{self}" unless found
44
+
45
+ found
43
46
  end
44
47
 
45
48
  def relocate
@@ -6,7 +6,7 @@ module Resource
6
6
 
7
7
  def self.install(content, name, software_dir = Path.setup('software'), &block)
8
8
  software_dir ||= Path.setup('software')
9
- software_dir = software_dir.find if Path === software_dir
9
+ software_dir = software_dir.find(:user) if Path === software_dir
10
10
 
11
11
  content = block if block_given?
12
12
 
@@ -166,11 +166,13 @@ url='#{url}'
166
166
  value.sub!(/^['"]/,'')
167
167
  value.sub!(/['"]$/,'')
168
168
  value.gsub!(/\$[a-z_0-9]+/i){|var| ENV[var[1..-1]] }
169
- Log.debug "Set variable export from .post_install: #{Misc.fingerprint [var,value]*"="}"
169
+ Log.debug "Set variable export from .post_install: #{Log.fingerprint [var,value]*"="}"
170
170
  ENV[var] = value
171
171
  end
172
172
  end
173
173
  end
174
174
  end
175
175
  end
176
+
177
+ self.set_software_env
176
178
  end
@@ -2,7 +2,9 @@ require_relative 'log'
2
2
  require_relative 'path'
3
3
  require_relative 'resource/produce'
4
4
  require_relative 'resource/path'
5
+ require_relative 'resource/open'
5
6
  require_relative 'resource/util'
7
+ require_relative 'resource/software'
6
8
 
7
9
  module Resource
8
10
  extend MetaExtension
@@ -11,7 +11,9 @@ module TSV
11
11
  fields_str = "#{header_hash}#{key_field || "Id"}#{sep}#{fields*sep}"
12
12
  end
13
13
 
14
- if preamble && options.values.compact.any?
14
+ if String === preamble
15
+ preamble_str = preamble
16
+ elsif preamble && options.values.compact.any?
15
17
  preamble_str = "#: " << IndiferentHash.hash2string(options)
16
18
  else
17
19
  preamble_str = nil
@@ -51,7 +51,7 @@ module TSV
51
51
  [key, items]
52
52
  end
53
53
 
54
- def self.parse_stream(stream, data: nil, source_type: nil, type: :list, merge: true, one2one: false, fix: true, bar: false, first_line: nil, field_names: nil, **kargs, &block)
54
+ def self.parse_stream(stream, data: nil, source_type: nil, type: :list, merge: true, one2one: false, fix: true, bar: false, first_line: nil, field_names: nil, head: nil, **kargs, &block)
55
55
  begin
56
56
  bar = "Parsing #{Log.fingerprint stream}" if TrueClass === bar
57
57
  bar = Log::ProgressBar.get_obj_bar(stream, bar) if bar
@@ -62,7 +62,8 @@ module TSV
62
62
  data = {} if data.nil?
63
63
  merge = false if type != :double && type != :flat
64
64
  line = first_line || stream.gets
65
- while line
65
+ while line
66
+ break if head && head <= 0
66
67
  begin
67
68
  line.chomp!
68
69
  if Proc === fix
@@ -171,6 +172,7 @@ module TSV
171
172
  stream.abort($!) if stream.respond_to?(:abort)
172
173
  raise $!
173
174
  ensure
175
+ head = head - 1 if head
174
176
  if stream.closed?
175
177
  line = nil
176
178
  else
@@ -185,7 +187,15 @@ module TSV
185
187
  else
186
188
  bar.remove
187
189
  end if bar
188
- stream.join if stream.respond_to?(:join)
190
+
191
+ if stream.respond_to?(:join)
192
+ eof = begin
193
+ stream.eof?
194
+ rescue IOError
195
+ true
196
+ end
197
+ stream.join if eof
198
+ end
189
199
  end
190
200
  end
191
201
 
@@ -6,6 +6,7 @@ class WorkQueue
6
6
  attr_accessor :workers, :worker_proc, :callback
7
7
 
8
8
  def initialize(workers = 0, &block)
9
+ workers = workers.to_i if String === workers
9
10
  @input = WorkQueue::Socket.new
10
11
  @output = WorkQueue::Socket.new
11
12
  @workers = workers.times.collect{ Worker.new }
@@ -6,7 +6,7 @@ module Workflow
6
6
  return workload if job.done? && job.updated?
7
7
 
8
8
  job.dependencies.each do |dep|
9
- next if dep.done? && job.updated?
9
+ next if dep.done? && dep.updated?
10
10
  workload.merge!(job_workload(dep))
11
11
  workload[job] += workload[dep]
12
12
  workload[job] << dep
@@ -14,7 +14,7 @@ module Workflow
14
14
  end
15
15
 
16
16
  job.input_dependencies.each do |dep|
17
- next if dep.done? && job.updated?
17
+ next if dep.done? && dep.updated?
18
18
  workload.merge!(job_workload(dep))
19
19
  workload[job] += workload[dep]
20
20
  workload[job] << dep
@@ -85,15 +85,15 @@ module Workflow
85
85
  candidates = workload.
86
86
  select{|k,v| v.empty? }.
87
87
  collect{|k,v| k }.
88
- reject{|k| k.done? }
88
+ reject{|k| k.done? || k.running? }
89
89
  else
90
90
  candidates = workload. #select{|k,v| Orchestrator.job_rules(rules, k) }.
91
91
  select{|k,v| v.empty? }.
92
92
  collect{|k,v| k }.
93
- reject{|k| k.done? }
93
+ reject{|k| k.done? || k.running? }
94
94
  end
95
95
 
96
- top_level = workload.keys - workload.values.flatten
96
+ #top_level = workload.keys - workload.values.flatten
97
97
 
98
98
  candidates = purge_duplicates candidates
99
99
  candidates = sort_candidates candidates, rules
@@ -192,7 +192,10 @@ module Workflow
192
192
  workload = Orchestrator.workload(jobs)
193
193
  all_jobs = workload.keys
194
194
 
195
+ all_jobs.each{|job| job.clean unless job.done? && job.updated? }
196
+
195
197
  top_level_jobs = jobs.collect{|job| job.path }
198
+ failed_jobs = []
196
199
  while workload.any?
197
200
 
198
201
  candidates = resources_used.keys + Orchestrator.candidates(workload, rules)
@@ -203,9 +206,15 @@ module Workflow
203
206
  case
204
207
  when (job.error? || job.aborted?)
205
208
  begin
206
- if job.recoverable_error?
207
- job.clean
208
- raise TryAgain
209
+ if job.recoverable_error?
210
+ if failed_jobs.include?(job)
211
+ Log.warn "Failed twice #{job.path} with recoverable error"
212
+ next
213
+ else
214
+ failed_jobs << job
215
+ job.clean
216
+ raise TryAgain
217
+ end
209
218
  else
210
219
  next
211
220
  end
@@ -1,7 +1,13 @@
1
1
  class Step
2
- def rec_dependencies
3
- rec_dependencies = dependencies.dup
4
- dependencies.inject(rec_dependencies){|acc,d| acc.concat d.rec_dependencies }
2
+ def rec_dependencies(connected = false, seen = [])
3
+ direct_deps = []
4
+ dependencies.each do |dep|
5
+ next if seen.include? dep.path
6
+ next if connected && dep.done? && dep.updated?
7
+ direct_deps << dep
8
+ end
9
+ seen.concat direct_deps.collect{|d| d.path }
10
+ direct_deps.inject(direct_deps){|acc,d| acc.concat(d.rec_dependencies(connected, [])); acc }
5
11
  end
6
12
 
7
13
  def recursive_inputs
@@ -127,6 +127,14 @@ class Step
127
127
  ! done? && (info[:pid] && Misc.pid_alive?(info[:pid]))
128
128
  end
129
129
 
130
+ def overriden?
131
+ overriden_task || overriden_workflow || dependencies.select{|d| d.overriden? }.any?
132
+ end
133
+
134
+ def overriden_deps
135
+ rec_dependencies.select{|d| d.overriden? }
136
+ end
137
+
130
138
  def exception
131
139
  info[:exception]
132
140
  end
@@ -0,0 +1,5 @@
1
+ class Step
2
+ def save_inputs(inputs_dir)
3
+ self.task.save_inputs(inputs_dir, provided_inputs)
4
+ end
5
+ end