scout-gear 10.7.0 → 10.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +8 -1
  3. data/VERSION +1 -1
  4. data/lib/scout/association/index.rb +1 -1
  5. data/lib/scout/association.rb +21 -5
  6. data/lib/scout/entity/format.rb +9 -4
  7. data/lib/scout/entity/identifiers.rb +2 -2
  8. data/lib/scout/entity/named_array.rb +13 -0
  9. data/lib/scout/entity/property.rb +2 -1
  10. data/lib/scout/entity.rb +9 -4
  11. data/lib/scout/persist/tsv/adapter/base.rb +13 -1
  12. data/lib/scout/persist/tsv.rb +2 -1
  13. data/lib/scout/tsv/attach.rb +10 -2
  14. data/lib/scout/tsv/change_id.rb +3 -0
  15. data/lib/scout/tsv/dumper.rb +34 -30
  16. data/lib/scout/tsv/open.rb +1 -0
  17. data/lib/scout/tsv/parser.rb +22 -10
  18. data/lib/scout/tsv/path.rb +8 -0
  19. data/lib/scout/tsv/stream.rb +15 -8
  20. data/lib/scout/tsv/traverse.rb +12 -2
  21. data/lib/scout/tsv/util/process.rb +4 -1
  22. data/lib/scout/tsv/util/select.rb +8 -2
  23. data/lib/scout/tsv/util/sort.rb +23 -15
  24. data/lib/scout/tsv/util.rb +11 -2
  25. data/lib/scout/tsv.rb +23 -11
  26. data/lib/scout/workflow/definition.rb +24 -9
  27. data/lib/scout/workflow/deployment/orchestrator.rb +10 -7
  28. data/lib/scout/workflow/exceptions.rb +1 -0
  29. data/lib/scout/workflow/path.rb +40 -0
  30. data/lib/scout/workflow/step/dependencies.rb +36 -12
  31. data/lib/scout/workflow/step/file.rb +2 -1
  32. data/lib/scout/workflow/step/info.rb +20 -4
  33. data/lib/scout/workflow/step/load.rb +5 -3
  34. data/lib/scout/workflow/step/progress.rb +6 -0
  35. data/lib/scout/workflow/step/provenance.rb +1 -1
  36. data/lib/scout/workflow/step/status.rb +11 -4
  37. data/lib/scout/workflow/step.rb +33 -12
  38. data/lib/scout/workflow/task/dependencies.rb +33 -24
  39. data/lib/scout/workflow/task/inputs.rb +42 -12
  40. data/lib/scout/workflow/task.rb +22 -11
  41. data/lib/scout/workflow/usage.rb +3 -3
  42. data/lib/scout/workflow.rb +3 -0
  43. data/scout-gear.gemspec +13 -4
  44. data/scout_commands/db/query +83 -0
  45. data/scout_commands/db/register +43 -0
  46. data/scout_commands/db/show +47 -0
  47. data/test/scout/entity/test_named_array.rb +21 -0
  48. data/test/scout/persist/test_tsv.rb +20 -0
  49. data/test/scout/persist/tsv/adapter/test_base.rb +20 -0
  50. data/test/scout/test_tsv.rb +40 -0
  51. data/test/scout/tsv/test_dumper.rb +24 -0
  52. data/test/scout/tsv/test_path.rb +24 -0
  53. data/test/scout/tsv/test_stream.rb +93 -0
  54. data/test/scout/tsv/test_traverse.rb +99 -0
  55. data/test/scout/tsv/test_util.rb +2 -0
  56. data/test/scout/tsv/util/test_select.rb +22 -0
  57. data/test/scout/tsv/util/test_sort.rb +24 -0
  58. data/test/scout/workflow/step/test_dependencies.rb +26 -0
  59. data/test/scout/workflow/step/test_info.rb +35 -0
  60. data/test/scout/workflow/task/test_dependencies.rb +67 -1
  61. data/test/scout/workflow/task/test_inputs.rb +24 -7
  62. data/test/scout/workflow/test_definition.rb +31 -0
  63. data/test/scout/workflow/test_path.rb +9 -0
  64. data/test/scout/workflow/test_task.rb +36 -0
  65. data/test/scout/workflow/test_usage.rb +0 -1
  66. metadata +12 -3
@@ -44,11 +44,14 @@ module TSV
44
44
  end
45
45
 
46
46
  def add_field(name = nil)
47
- through do |key, values|
47
+ keys.each do |key|
48
+ values = self[key]
48
49
  new_values = yield(key, values)
49
50
  new_values = [new_values].compact if type == :double and not Array === new_values
50
51
 
51
52
  case
53
+ when type == :single
54
+ values = new_values
52
55
  when (values.nil? and (fields.nil? or fields.empty?))
53
56
  values = [new_values]
54
57
  when values.nil?
@@ -156,8 +156,14 @@ module TSV
156
156
  case
157
157
  when ((Array === method) and (key == :key or key_field == key))
158
158
  with_unnamed do
159
- keys.each do |key|
160
- new[key] = self[key] if invert ^ (method.include? key)
159
+ if invert
160
+ keys.each do |key|
161
+ new[key] = self[key] unless method.include?(key)
162
+ end
163
+ else
164
+ method.each do |key|
165
+ new[key] = self[key] if self.include?(key)
166
+ end
161
167
  end
162
168
  end
163
169
  when Array === method
@@ -1,4 +1,10 @@
1
+ require 'scout/entity'
2
+
1
3
  module TSV
4
+ def prepare_entity(...)
5
+ Entity.prepare_entity(...)
6
+ end
7
+
2
8
  def sort_by(field = nil, just_keys = false, &block)
3
9
  field = :all if field.nil?
4
10
 
@@ -8,16 +14,18 @@ module TSV
8
14
  elems = []
9
15
  case type
10
16
  when :single
11
- through :key, field do |key, field|
12
- elems << [key, field]
17
+ through :key, field do |key, value|
18
+ elems << [key, value]
13
19
  end
14
20
  when :list, :flat
15
- through :key, field do |key, fields|
16
- elems << [key, fields.first]
21
+ through :key, field do |key, value|
22
+ v = field == :key ? key : value[0]
23
+ elems << [key, v]
17
24
  end
18
25
  when :double
19
- through :key, field do |key, fields|
20
- elems << [key, fields.first]
26
+ through :key, field do |key, value|
27
+ v = field == :key ? key : value[0]
28
+ elems << [key, v]
21
29
  end
22
30
  end
23
31
  end
@@ -81,16 +89,16 @@ module TSV
81
89
  elems = []
82
90
  case type
83
91
  when :single
84
- through :key, field do |key, field|
85
- elems << [key, field]
92
+ through :key, field do |key, value|
93
+ elems << [key, value]
86
94
  end
87
95
  when :list, :flat
88
- through :key, field do |key, fields|
89
- elems << [key, fields.first]
96
+ through :key, field do |key, values|
97
+ elems << [key, values[0]]
90
98
  end
91
99
  when :double
92
- through :key, field do |key, fields|
93
- elems << [key, fields.first]
100
+ through :key, field do |key, values|
101
+ elems << [key, values[0]]
94
102
  end
95
103
  end
96
104
  end
@@ -99,7 +107,7 @@ module TSV
99
107
  if fields == :all
100
108
  if just_keys
101
109
  keys = elems.sort_by{|key, value| key }.collect{|key, values| key}
102
- keys = prepare_entity(keys, key_field, entity_options.merge(:dup_array => true))
110
+ keys = prepare_entity(keys, key_field, (entity_options || {}).merge(:dup_array => true))
103
111
  else
104
112
  elems.sort_by{|key, value| key }
105
113
  end
@@ -128,7 +136,7 @@ module TSV
128
136
  end
129
137
  if just_keys
130
138
  keys = sorted.collect{|key, value| key}
131
- keys = prepare_entity(keys, key_field, entity_options.merge(:dup_array => true)) unless @unnamed
139
+ keys = prepare_entity(keys, key_field, (entity_options || {}).merge(:dup_array => true)) unless @unnamed
132
140
  keys
133
141
  else
134
142
  sorted.collect{|key, value| [key, self[key]]}
@@ -137,7 +145,7 @@ module TSV
137
145
  else
138
146
  if just_keys
139
147
  keys = elems.sort(&block).collect{|key, value| key}
140
- keys = prepare_entity(keys, key_field, entity_options.merge(:dup_array => true)) unless @unnamed
148
+ keys = prepare_entity(keys, key_field, (entity_options || {}).merge(:dup_array => true)) unless @unnamed
141
149
  keys
142
150
  else
143
151
  elems.sort(&block).collect{|key, value| [key, self[key]]}
@@ -32,6 +32,7 @@ module TSV
32
32
  text
33
33
  end
34
34
 
35
+ path = path.find if Path === path
35
36
  TmpFile.with_file(values.uniq * "\n", false) do |value_file|
36
37
  cmd = "cat '#{ path }' | sed 's/\\t/\\tHEADERNOMATCH/' | grep -w -F -f '#{ value_file }' | sed 's/HEADERNOMATCH//' |sort -u|cut -f 2 |sort|uniq -c|sed 's/^ *//;s/ /\t/'"
37
38
  begin
@@ -84,8 +85,9 @@ module TSV
84
85
 
85
86
  def each(*args, &block)
86
87
  if block_given?
88
+ actual_unnamed = @unnamed.nil? ? true : @unnamed
87
89
  super(*args) do |k,v|
88
- NamedArray.setup(v, @fields) unless @unnamed || @type == :flat || ! (Array === v)
90
+ NamedArray.setup(v, @fields) unless actual_unnamed || @type == :flat || ! (Array === v)
89
91
  block.call(k, v)
90
92
  end
91
93
  else
@@ -105,7 +107,8 @@ module TSV
105
107
  end
106
108
  end
107
109
 
108
- def with_unnamed(unnamed = true)
110
+ def with_unnamed(unnamed = nil)
111
+ unnamed = true if unnamed.nil?
109
112
  begin
110
113
  old_unnamed = @unnamed
111
114
  @unnamed = unnamed
@@ -177,4 +180,10 @@ Example:
177
180
  self.annotate(super(other))
178
181
  end
179
182
 
183
+ def merge_zip(other)
184
+ other.each do |k,v|
185
+ self.zip_new k, v
186
+ end
187
+ end
188
+
180
189
  end
data/lib/scout/tsv.rb CHANGED
@@ -16,7 +16,8 @@ require_relative 'tsv/csv'
16
16
 
17
17
  module TSV
18
18
  extend Annotation
19
- annotation :key_field, :fields, :type, :cast, :filename, :namespace, :unnamed, :identifiers, :serializer
19
+ annotation :key_field, :fields, :type, :cast, :filename, :namespace, :unnamed, :identifiers, :serializer, :entity_options
20
+
20
21
 
21
22
  def self.str2options(str)
22
23
  field_options,_sep, rest = str.partition("#")
@@ -34,7 +35,6 @@ module TSV
34
35
  alias original_setup setup
35
36
 
36
37
  def setup(obj, *rest, &block)
37
-
38
38
  if rest.length == 1 && String === rest.first
39
39
  options = TSV.str2options(rest.first)
40
40
  if Array === obj
@@ -44,7 +44,7 @@ module TSV
44
44
  when :single
45
45
  nil
46
46
  end
47
- obj = Misc.array2hash(obj, default_value)
47
+ obj = IndiferentHash.array2hash(obj, default_value)
48
48
  end
49
49
  original_setup(obj, options, &block)
50
50
  else
@@ -57,7 +57,7 @@ module TSV
57
57
  when :single
58
58
  nil
59
59
  end
60
- obj = Misc.array2hash(obj, default_value)
60
+ obj = IndiferentHash.array2hash(obj, default_value)
61
61
  end
62
62
  original_setup(obj, *rest, &block)
63
63
  end
@@ -74,11 +74,17 @@ module TSV
74
74
  end
75
75
 
76
76
  def self.open(file, options = {})
77
- grep, invert_grep, nocache, monitor, entity_options = IndiferentHash.process_options options, :grep, :invert_grep, :nocache, :monitor, :entity_options
77
+ grep, invert_grep, fixed_grep, nocache, monitor, entity_options, unnamed, field = IndiferentHash.process_options options, :grep, :invert_grep, :fixed_grep, :nocache, :monitor, :entity_options, :unnamed, :field
78
+
79
+ if field and options[:field].nil?
80
+ options[:fields] = [field]
81
+ options[:type] ||= :single
82
+ end
78
83
 
79
84
  persist_options = IndiferentHash.pull_keys options, :persist
80
85
  persist_options = IndiferentHash.add_defaults persist_options, prefix: "TSV", type: :HDB, persist: false
81
86
  persist_options[:data] ||= options[:data]
87
+ persist_options[:update] = options.delete(:update) if options.include?(:update)
82
88
 
83
89
  file = StringIO.new file if String === file && ! (Path === file) && file.index("\n")
84
90
 
@@ -113,14 +119,20 @@ module TSV
113
119
  end
114
120
 
115
121
  tsv = if TSV::Parser === file
116
- TSV.parse(file, **options)
117
- else
118
- options[:tsv_invert_grep] ||= invert_grep if invert_grep
119
- Open.open(file, grep: grep, invert_grep: invert_grep, nocache: nocache) do |f|
120
- TSV.parse(f, **options)
121
- end
122
+ TSV.parse(file, **options)
123
+ else
124
+ options[:tsv_invert_grep] ||= invert_grep if invert_grep
125
+ Open.open(file, grep: grep, invert_grep: invert_grep, fixed_grep: fixed_grep, nocache: nocache) do |f|
126
+ TSV.parse(f, **options)
127
+ end
128
+ end
129
+
130
+ if tsv.identifiers.nil? and Path === tsv.filename and tsv.filename.identifier_file_path
131
+ tsv.identifiers = tsv.filename.identifier_file_path.find if tsv.filename.identifier_file_path.exists?
122
132
  end
123
133
 
134
+ tsv.unnamed = unnamed unless unnamed.nil?
135
+
124
136
  tsv
125
137
  end
126
138
  end
@@ -140,8 +140,17 @@ module Workflow
140
140
  end
141
141
  end
142
142
 
143
- FORGET_DEP_TASKS = ENV["SCOUT_FORGET_DEP_TASKS"] == "true"
144
- REMOVE_DEP_TASKS = ENV["SCOUT_REMOVE_DEP_TASKS"] == "true"
143
+ FORGET_TASK_ALIAS = begin
144
+ %w(SCOUT_FORGET_TASK_ALIAS SCOUT_FORGET_DEP_TASKS RBBT_FORGET_DEP_TASKS).select do |var|
145
+ ENV[var] == 'true'
146
+ end.any?
147
+ end
148
+ REMOVE_TASK_ALIAS = begin
149
+ remove = %w(SCOUT_REMOVE_TASK_ALIAS SCOUT_REMOVE_DEP_TASKS RBBT_REMOVE_DEP_TASKS).select do |var|
150
+ ENV.include?(var) && ENV[var] != 'false'
151
+ end.first
152
+ remove.nil? ? false : remove
153
+ end
145
154
  def task_alias(name, workflow, oname, *rest, &block)
146
155
  dep(workflow, oname, *rest, &block)
147
156
  extension :dep_task unless @extension
@@ -155,18 +164,24 @@ module Workflow
155
164
  Step.wait_for_jobs dependencies.select{|d| d.streaming? }
156
165
  dep = dependencies.last
157
166
  dep.join
158
- raise dep.get_exception if dep.error?
167
+ raise dep.exception if dep.error?
159
168
  raise Aborted, "Aborted dependency #{dep.path}" if dep.aborted?
160
- set_info :type, dep.info[:type]
161
- forget = config :forget_dep_tasks, "forget_dep_tasks", :default => FORGET_DEP_TASKS
169
+ merge_info type: dep.info[:type], task_alias: true
170
+
171
+ forget = config :forget_task_alias, "forget_task_alias"
172
+ forget = config :forget_dep_tasks, "forget_dep_tasks", :default => FORGET_TASK_ALIAS if forget.nil?
173
+
162
174
  if forget
163
- remove = config :remove_dep_tasks, "remove_dep_tasks", :default => REMOVE_DEP_TASKS
175
+ remove = config :remove_task_alias, "remove_task_alias"
176
+ remove = config :remove_dep_tasks, "remove_dep_tasks", :default => REMOVE_TASK_ALIAS if remove.nil?
177
+
178
+ Log.medium "Forget task_alias (remove: #{remove}): #{short_path}"
164
179
 
165
180
  self.archive_deps
166
181
  self.copy_linked_files_dir
167
182
  self.dependencies = self.dependencies - [dep]
168
183
  Open.rm_rf self.files_dir if Open.exist? self.files_dir
169
- FileUtils.cp_r dep.files_dir, self.files_dir if Open.exist?(dep.files_dir)
184
+ Open.link_dir dep.files_dir, self.files_dir if Open.exist?(dep.files_dir)
170
185
 
171
186
  if dep.overriden?
172
187
  Open.link dep.path, self.tmp_path
@@ -179,9 +194,9 @@ module Workflow
179
194
  when 'recursive'
180
195
  (dep.dependencies + dep.rec_dependencies).uniq.each do |d|
181
196
  next if d.overriden
182
- d.clean unless config(:remove_dep, d.task_signature, d.task_name, d.workflow.to_s, :default => true).to_s == 'false'
197
+ d.clean unless Scout::Config.get(:remove_dep, "task:#{d.task_signature}", "task:#{d.task_name}", "workflow:#{d.workflow.name}", :default => true).to_s == 'false'
183
198
  end
184
- dep.clean unless config(:remove_dep, dep.task_signature, dep.task_name, dep.workflow.to_s, :default => true).to_s == 'false'
199
+ dep.clean unless Scout::Config.get(:remove_dep, "task:#{dep.task_signature}", "task:#{dep.task_name}", "workflow:#{dep.workflow.name}", :default => true).to_s == 'false'
185
200
  end
186
201
  end
187
202
  else
@@ -34,14 +34,16 @@ module Workflow
34
34
  end
35
35
 
36
36
  def self.job_rules(rules, job)
37
+ IndiferentHash.setup(rules)
37
38
  workflow = job.workflow.name
38
39
  task_name = job.task_name.to_s
39
40
  defaults = rules["defaults"] || {}
40
41
 
41
42
  return IndiferentHash.setup(defaults) unless rules[workflow]
42
- return IndiferentHash.setup(defaults) unless rules[workflow][task_name]
43
+ workflow_rules = IndiferentHash.setup(rules[workflow])
44
+ return IndiferentHash.setup(defaults) unless workflow_rules[task_name]
45
+ job_rules = IndiferentHash.setup(workflow_rules[task_name])
43
46
 
44
- job_rules = IndiferentHash.setup(rules[workflow][task_name])
45
47
  defaults.each{|k,v| job_rules[k] = v if job_rules[k].nil? } if defaults
46
48
  job_rules
47
49
  end
@@ -85,7 +87,7 @@ module Workflow
85
87
  candidates = workload.
86
88
  select{|k,v| v.empty? }.
87
89
  collect{|k,v| k }.
88
- reject{|k| k.done? || k.running? }
90
+ reject{|k| k.done? || k.running? || (k.error? && ! k.recoverable_error?) }
89
91
  else
90
92
  candidates = workload. #select{|k,v| Orchestrator.job_rules(rules, k) }.
91
93
  select{|k,v| v.empty? }.
@@ -107,7 +109,7 @@ module Workflow
107
109
 
108
110
  attr_accessor :available_resources, :resources_requested, :resources_used, :timer
109
111
 
110
- def initialize(timer = 5, available_resources = {})
112
+ def initialize(timer = 5, available_resources = nil)
111
113
  available_resources = {:cpus => Etc.nprocessors } if available_resources.nil?
112
114
  @timer = timer
113
115
  @available_resources = IndiferentHash.setup(available_resources)
@@ -192,7 +194,7 @@ module Workflow
192
194
  workload = Orchestrator.workload(jobs)
193
195
  all_jobs = workload.keys
194
196
 
195
- all_jobs.each{|job| job.clean unless job.done? && job.updated? }
197
+ all_jobs.each{|job| job.clean unless (job.done? && job.updated?) || (job.error? && ! job.recoverable_error?) }
196
198
 
197
199
  top_level_jobs = jobs.collect{|job| job.path }
198
200
  failed_jobs = []
@@ -216,6 +218,7 @@ module Workflow
216
218
  raise TryAgain
217
219
  end
218
220
  else
221
+ Log.warn "Non-recoverable error in #{job.path}"
219
222
  next
220
223
  end
221
224
  ensure
@@ -253,7 +256,7 @@ module Workflow
253
256
  end
254
257
  end
255
258
 
256
- def self.produce_dependencies(jobs, tasks, produce_cpus = Etc.nprocessors)
259
+ def self.produce_dependencies(jobs, tasks, produce_cpus = Etc.nprocessors, produce_timer = 5)
257
260
  jobs = [jobs] unless Array === jobs
258
261
  produce_list = []
259
262
  jobs.each do |job|
@@ -265,7 +268,7 @@ module Workflow
265
268
  end
266
269
  end
267
270
 
268
- orchestrator = Orchestrator.new 0.1, cpus: produce_cpus.to_i
271
+ orchestrator = Orchestrator.new produce_timer, cpus: produce_cpus.to_i
269
272
  orchestrator.process({}, produce_list)
270
273
  produce_list
271
274
  end
@@ -0,0 +1 @@
1
+ class TaskNotFound < StandardError; end
@@ -0,0 +1,40 @@
1
+ module Path
2
+ def self.step_file?(path)
3
+ return false unless path =~ /\.files(?:\/|$)/
4
+ parts = path.split("/")
5
+ job = parts.select{|p| p =~ /\.files$/}.first
6
+
7
+ if job
8
+ i = parts.index job
9
+ begin
10
+ workflow, task = parts.values_at i - 2, i - 1
11
+ _loaded = false
12
+ begin
13
+ Kernel.const_get(workflow)
14
+ rescue
15
+ if ! _loaded
16
+ Workflow.require_workflow workflow
17
+ _loaded = true
18
+ retry
19
+ end
20
+ raise $!
21
+ end
22
+ return parts[i-2..-1] * "/"
23
+ rescue
24
+ Log.exception $!
25
+ end
26
+ end
27
+
28
+ false
29
+ end
30
+
31
+ alias original_digest_str digest_str
32
+
33
+ def digest_str
34
+ if step_file = Path.step_file?(self)
35
+ "Step file: #{step_file}"
36
+ else
37
+ original_digest_str
38
+ end
39
+ end
40
+ end
@@ -1,20 +1,26 @@
1
1
  class Step
2
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 if dependencies
9
- seen.concat direct_deps.collect{|d| d.path }
10
- direct_deps.inject(direct_deps){|acc,d| acc.concat(d.rec_dependencies(connected, seen)); acc }
3
+ @rec_dependencies = {}
4
+ @rec_dependencies[connected] ||= begin
5
+ direct_deps = []
6
+ dependencies.each do |dep|
7
+ next if seen.include? dep.path
8
+ next if connected && dep.done? && dep.updated?
9
+ direct_deps << dep
10
+ end if dependencies
11
+ seen.concat direct_deps.collect{|d| d.path }
12
+ seen.uniq!
13
+ direct_deps.inject(direct_deps){|acc,d| acc.concat(d.rec_dependencies(connected, seen)); acc }
14
+ direct_deps.uniq!
15
+ direct_deps
16
+ end
11
17
  end
12
18
 
13
19
  def recursive_inputs
14
- recursive_inputs = NamedArray === @inputs ? @inputs.to_hash : {}
20
+ recursive_inputs = NamedArray === inputs ? inputs.to_hash : {}
15
21
  return recursive_inputs if dependencies.nil?
16
22
  dependencies.inject(recursive_inputs) do |acc,dep|
17
- acc.merge(dep.recursive_inputs)
23
+ acc = dep.recursive_inputs.merge(acc)
18
24
  end
19
25
  end
20
26
 
@@ -41,6 +47,7 @@ class Step
41
47
  end
42
48
 
43
49
  next if dep.done?
50
+ next if dep.error? && ! dep.recoverable_error?
44
51
 
45
52
  if dep.dependencies
46
53
  dep.dependencies.each do |d|
@@ -72,9 +79,13 @@ class Step
72
79
  def run_dependencies
73
80
  all_dependencies.each do |dep|
74
81
  next if dep.running? || dep.done?
82
+ next if dep.error? && ! dep.recoverable_error?
83
+
75
84
  compute_options = compute[dep.path] if compute
76
85
  compute_options = [] if compute_options.nil?
77
86
 
87
+ next if compute_options.include?(false)
88
+
78
89
  stream = compute_options.include?(:stream)
79
90
  stream = true unless ENV["SCOUT_EXPLICIT_STREAMING"] == 'true'
80
91
  stream = :no_load if compute_options.include?(:produce)
@@ -95,12 +106,25 @@ class Step
95
106
  all_dependencies.each{|dep| dep.abort if dep.running? }
96
107
  end
97
108
 
98
- def self.wait_for_jobs(jobs)
109
+ def self.wait_for_jobs(jobs, canfail=false)
99
110
  threads = []
100
111
  jobs.each do |job|
101
112
  threads << Thread.new do
102
113
  Thread.current.report_on_exception = false
103
- job.join
114
+ begin
115
+ job.join
116
+ rescue Exception
117
+ case canfail
118
+ when TrueClass
119
+ next
120
+ else
121
+ if canfail === $!
122
+ next
123
+ else
124
+ raise $!
125
+ end
126
+ end
127
+ end
104
128
  end
105
129
  end
106
130
  threads.each do |t|
@@ -7,6 +7,7 @@ class Step
7
7
  else
8
8
  Path.setup(dir)
9
9
  end
10
+ dir = dir.find
10
11
  dir.pkgdir = self
11
12
  dir
12
13
  end
@@ -34,7 +35,7 @@ class Step
34
35
  begin
35
36
  realpath = Open.realpath(self.files_dir)
36
37
  Open.rm self.files_dir
37
- Open.cp realpath, self.files_dir
38
+ Open.link_dir realpath, self.files_dir
38
39
  rescue
39
40
  Log.warn "Copy files_dir for #{self.workflow_short_path} failed: " + $!.message
40
41
  end
@@ -10,7 +10,11 @@ class Step
10
10
  end
11
11
 
12
12
  def self.load_info(info_file)
13
- info = Persist.load(info_file, SERIALIZER) || {}
13
+ info = begin
14
+ Persist.load(info_file, SERIALIZER) || {}
15
+ rescue
16
+ {status: :noinfo}
17
+ end
14
18
  IndiferentHash.setup(info)
15
19
  end
16
20
 
@@ -20,7 +24,7 @@ class Step
20
24
  end
21
25
 
22
26
  def save_info(info = nil)
23
- Persist.save(info, info_file, SERIALIZER)
27
+ Persist.save(@info = info, info_file, SERIALIZER)
24
28
  @info_load_time = Time.now
25
29
  end
26
30
 
@@ -117,6 +121,7 @@ class Step
117
121
  if message.nil?
118
122
  Log.info [Log.color(:status, status, true), Log.color(:task, task_name, true), Log.color(:path, path)] * " "
119
123
  else
124
+ message = Log.fingerprint(message).sub(/^'/,'').sub(/'$/,'')
120
125
  Log.info [Log.color(:status, status, true), Log.color(:task, task_name, true), message, Log.color(:path, path)] * " "
121
126
  end
122
127
  end
@@ -139,6 +144,10 @@ class Step
139
144
  info[:messages]
140
145
  end
141
146
 
147
+ def message(message)
148
+ merge_info :message => message
149
+ end
150
+
142
151
  def status
143
152
  info[:status].tap{|s| s.nil? ? s : s.to_sym }
144
153
  end
@@ -152,7 +161,7 @@ class Step
152
161
  end
153
162
 
154
163
  def running?
155
- ! done? && (info[:pid] && Misc.pid_alive?(info[:pid]))
164
+ ! (done? && status == :done) && (info[:pid] && Misc.pid_alive?(info[:pid]))
156
165
  end
157
166
 
158
167
  def overriden?
@@ -161,7 +170,14 @@ class Step
161
170
  end
162
171
 
163
172
  def overriden_deps
164
- rec_dependencies.select{|d| d.overriden? }
173
+ dependencies.select{|d| d.overriden? }
174
+ end
175
+
176
+ def recursive_overriden_deps
177
+ overriden_deps = dependencies.select{|d|
178
+ d.overriden?
179
+ }
180
+ (overriden_deps + overriden_deps.collect{|d| d.recursive_overriden_deps }).flatten.uniq
165
181
  end
166
182
 
167
183
  def exception
@@ -4,9 +4,11 @@ class Step
4
4
  Path.setup(path) unless Path === path
5
5
  relocated = path.relocate
6
6
  return relocated if Open.exists?(relocated)
7
- subpath = path.split("/")[-3..-1] * "/"
8
- relocated = Path.setup("var/jobs")[subpath]
9
- return relocated if Open.exists?(relocated)
7
+ if path.scan("/").length >= 2
8
+ subpath = path.split("/")[-3..-1] * "/"
9
+ relocated = Path.setup("var/jobs")[subpath]
10
+ return relocated if Open.exists?(relocated)
11
+ end
10
12
  path
11
13
  end
12
14
 
@@ -19,5 +19,11 @@ class Step
19
19
  bar
20
20
  end
21
21
  end
22
+
23
+ def traverse(obj, desc: nil , **kwargs, &block)
24
+ desc = "Processing #{self.short_path}" if desc.nil?
25
+ kwargs[:bar] = self.progress_bar(desc) unless kwargs.include?(:bar)
26
+ TSV.traverse obj, **kwargs, &block
27
+ end
22
28
  end
23
29
 
@@ -62,7 +62,7 @@ class Step
62
62
  end
63
63
 
64
64
  if $inputs and $inputs.any?
65
- job_inputs = Workflow.load_step(path).recursive_inputs.to_hash
65
+ job_inputs = Step.new(path).recursive_inputs.to_hash
66
66
  IndiferentHash.setup(job_inputs)
67
67
 
68
68
  $inputs.each do |input|
@@ -20,17 +20,24 @@ class Step
20
20
  self.error? && ! (ScoutException === self.exception)
21
21
  end
22
22
 
23
- def updated?
24
- return false if self.error? && self.recoverable_error?
25
- return true if self.done? && ! ENV["SCOUT_UPDATE"]
23
+ def newer_dependencies
26
24
  newer = rec_dependencies.select{|dep| Path.newer?(self.path, dep.path) }
27
25
  newer += input_dependencies.select{|dep| Path.newer?(self.path, dep.path) }
26
+ newer += rec_dependencies.collect{|dep| dep.input_dependencies }.flatten.select{|dep| Path.newer?(self.path, dep.path) }
27
+ newer
28
+ end
29
+
30
+ def updated?
31
+ return false if self.error? && self.recoverable_error?
32
+ return true if (self.done? || (self.error? && ! self.recoverable_error?)) && ! ENV["SCOUT_UPDATE"]
33
+ newer = newer_dependencies
28
34
 
29
35
  Log.low "Newer deps found for #{Log.fingerprint self}: #{Log.fingerprint newer}" if newer.any?
30
36
  newer.empty?
31
37
  end
32
38
 
33
39
  def clean
40
+ Log.debug "Cleaning job files: #{path}"
34
41
  @take_stream = nil
35
42
  @result = nil
36
43
  @info = nil
@@ -55,7 +62,7 @@ class Step
55
62
  end
56
63
 
57
64
  def canfail?
58
- @compute && @compute.include?(:canfail)
65
+ @compute && @compute[self.path] && @compute[self.path].include?(:canfail)
59
66
  end
60
67
 
61
68
  def started?