scout-gear 10.11.4 → 10.11.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +17 -2
  3. data/VERSION +1 -1
  4. data/bin/scout +10 -10
  5. data/lib/scout/association/fields.rb +15 -15
  6. data/lib/scout/association/index.rb +6 -6
  7. data/lib/scout/association/item.rb +18 -8
  8. data/lib/scout/association.rb +4 -4
  9. data/lib/scout/entity/identifiers.rb +5 -5
  10. data/lib/scout/entity/property.rb +2 -2
  11. data/lib/scout/entity.rb +1 -1
  12. data/lib/scout/knowledge_base/description.rb +10 -10
  13. data/lib/scout/knowledge_base/entity.rb +6 -6
  14. data/lib/scout/knowledge_base/list.rb +1 -1
  15. data/lib/scout/knowledge_base/query.rb +4 -4
  16. data/lib/scout/knowledge_base/registry.rb +6 -6
  17. data/lib/scout/knowledge_base/traverse.rb +7 -40
  18. data/lib/scout/persist/engine/fix_width_table.rb +6 -6
  19. data/lib/scout/persist/engine/packed_index.rb +2 -2
  20. data/lib/scout/persist/engine/sharder.rb +4 -4
  21. data/lib/scout/persist/engine/tkrzw.rb +1 -1
  22. data/lib/scout/persist/engine/tokyocabinet.rb +2 -2
  23. data/lib/scout/persist/tsv/adapter/fix_width_table.rb +1 -1
  24. data/lib/scout/persist/tsv/adapter/packed_index.rb +1 -1
  25. data/lib/scout/persist/tsv/adapter/tkrzw.rb +1 -1
  26. data/lib/scout/persist/tsv/adapter/tokyocabinet.rb +3 -3
  27. data/lib/scout/persist/tsv/serialize.rb +3 -3
  28. data/lib/scout/persist/tsv.rb +1 -1
  29. data/lib/scout/semaphore.rb +100 -17
  30. data/lib/scout/tsv/annotation/repo.rb +4 -4
  31. data/lib/scout/tsv/annotation.rb +2 -2
  32. data/lib/scout/tsv/attach.rb +7 -7
  33. data/lib/scout/tsv/change_id/translate.rb +1 -1
  34. data/lib/scout/tsv/csv.rb +3 -3
  35. data/lib/scout/tsv/dumper.rb +8 -8
  36. data/lib/scout/tsv/index.rb +1 -1
  37. data/lib/scout/tsv/open.rb +3 -3
  38. data/lib/scout/tsv/stream.rb +2 -2
  39. data/lib/scout/tsv/traverse.rb +4 -4
  40. data/lib/scout/tsv/util/filter.rb +9 -9
  41. data/lib/scout/tsv/util/process.rb +2 -2
  42. data/lib/scout/tsv/util/reorder.rb +2 -2
  43. data/lib/scout/tsv/util/select.rb +3 -3
  44. data/lib/scout/tsv/util/unzip.rb +2 -2
  45. data/lib/scout/tsv/util.rb +1 -1
  46. data/lib/scout/tsv.rb +2 -2
  47. data/lib/scout/work_queue/socket.rb +3 -2
  48. data/lib/scout/work_queue/worker.rb +4 -4
  49. data/lib/scout/work_queue.rb +7 -7
  50. data/lib/scout/workflow/definition.rb +18 -16
  51. data/lib/scout/workflow/deployment/local.rb +81 -62
  52. data/lib/scout/workflow/deployment/orchestrator/batches.rb +66 -5
  53. data/lib/scout/workflow/deployment/orchestrator/chains.rb +47 -30
  54. data/lib/scout/workflow/deployment/orchestrator/rules.rb +3 -3
  55. data/lib/scout/workflow/deployment/orchestrator/workload.rb +11 -22
  56. data/lib/scout/workflow/deployment/scheduler/job.rb +34 -36
  57. data/lib/scout/workflow/deployment/scheduler/lfs.rb +1 -1
  58. data/lib/scout/workflow/deployment/scheduler/pbs.rb +4 -4
  59. data/lib/scout/workflow/deployment/scheduler/slurm.rb +2 -2
  60. data/lib/scout/workflow/deployment/scheduler.rb +23 -12
  61. data/lib/scout/workflow/deployment/trace.rb +2 -2
  62. data/lib/scout/workflow/documentation.rb +4 -4
  63. data/lib/scout/workflow/export.rb +1 -1
  64. data/lib/scout/workflow/path.rb +2 -2
  65. data/lib/scout/workflow/step/children.rb +1 -1
  66. data/lib/scout/workflow/step/dependencies.rb +36 -3
  67. data/lib/scout/workflow/step/info.rb +5 -19
  68. data/lib/scout/workflow/step/inputs.rb +1 -1
  69. data/lib/scout/workflow/step/progress.rb +2 -2
  70. data/lib/scout/workflow/step/provenance.rb +4 -4
  71. data/lib/scout/workflow/step/status.rb +23 -9
  72. data/lib/scout/workflow/step.rb +21 -19
  73. data/lib/scout/workflow/task/dependencies.rb +10 -3
  74. data/lib/scout/workflow/task/info.rb +3 -3
  75. data/lib/scout/workflow/task/inputs.rb +8 -8
  76. data/lib/scout/workflow/task.rb +37 -22
  77. data/lib/scout/workflow/usage.rb +13 -13
  78. data/lib/scout/workflow/util.rb +1 -1
  79. data/lib/scout/workflow.rb +6 -6
  80. data/scout-gear.gemspec +4 -3
  81. data/scout_commands/alias +1 -1
  82. data/scout_commands/batch/clean +12 -12
  83. data/scout_commands/batch/list +26 -25
  84. data/scout_commands/batch/tail +9 -5
  85. data/scout_commands/cat +1 -1
  86. data/scout_commands/doc +2 -2
  87. data/scout_commands/entity +4 -4
  88. data/scout_commands/find +1 -1
  89. data/scout_commands/kb/config +1 -1
  90. data/scout_commands/kb/entities +1 -1
  91. data/scout_commands/kb/list +1 -1
  92. data/scout_commands/kb/query +2 -2
  93. data/scout_commands/kb/register +1 -1
  94. data/scout_commands/kb/show +1 -1
  95. data/scout_commands/kb/traverse +1 -1
  96. data/scout_commands/log +6 -6
  97. data/scout_commands/resource/produce +2 -2
  98. data/scout_commands/resource/sync +1 -1
  99. data/scout_commands/system/clean +7 -7
  100. data/scout_commands/system/status +4 -4
  101. data/scout_commands/template +1 -1
  102. data/scout_commands/update +1 -1
  103. data/scout_commands/workflow/cmd +2 -1
  104. data/scout_commands/workflow/example +123 -0
  105. data/scout_commands/workflow/info +10 -1
  106. data/scout_commands/workflow/install +1 -1
  107. data/scout_commands/workflow/list +2 -2
  108. data/scout_commands/workflow/process +2 -2
  109. data/scout_commands/workflow/prov +3 -3
  110. data/scout_commands/workflow/task +36 -11
  111. data/scout_commands/workflow/trace +1 -1
  112. data/scout_commands/workflow/write_info +2 -2
  113. data/share/templates/command +1 -1
  114. data/test/scout/association/test_item.rb +5 -0
  115. data/test/scout/entity/test_property.rb +3 -3
  116. data/test/scout/knowledge_base/test_description.rb +1 -1
  117. data/test/scout/knowledge_base/test_traverse.rb +2 -2
  118. data/test/scout/persist/engine/test_packed_index.rb +6 -6
  119. data/test/scout/persist/test_tsv.rb +4 -4
  120. data/test/scout/persist/tsv/adapter/test_packed_index.rb +4 -4
  121. data/test/scout/persist/tsv/adapter/test_sharder.rb +23 -23
  122. data/test/scout/persist/tsv/adapter/test_tokyocabinet.rb +1 -1
  123. data/test/scout/persist/tsv/test_serialize.rb +1 -1
  124. data/test/scout/test_association.rb +1 -1
  125. data/test/scout/test_tsv.rb +2 -2
  126. data/test/scout/test_workflow.rb +2 -2
  127. data/test/scout/tsv/test_annotation.rb +4 -4
  128. data/test/scout/tsv/test_index.rb +1 -1
  129. data/test/scout/tsv/test_open.rb +2 -2
  130. data/test/scout/tsv/test_parser.rb +2 -2
  131. data/test/scout/tsv/test_stream.rb +1 -1
  132. data/test/scout/tsv/test_transformer.rb +1 -1
  133. data/test/scout/tsv/util/test_filter.rb +1 -1
  134. data/test/scout/tsv/util/test_melt.rb +1 -1
  135. data/test/scout/tsv/util/test_reorder.rb +1 -1
  136. data/test/scout/work_queue/test_socket.rb +3 -3
  137. data/test/scout/work_queue/test_worker.rb +2 -2
  138. data/test/scout/workflow/deployment/orchestrator/test_batches.rb +13 -3
  139. data/test/scout/workflow/deployment/orchestrator/test_chains.rb +15 -13
  140. data/test/scout/workflow/deployment/orchestrator/test_workload.rb +1 -1
  141. data/test/scout/workflow/deployment/test_local.rb +2 -2
  142. data/test/scout/workflow/deployment/test_scheduler.rb +1 -2
  143. data/test/scout/workflow/step/test_children.rb +1 -1
  144. data/test/scout/workflow/step/test_dependencies.rb +36 -1
  145. data/test/scout/workflow/step/test_info.rb +3 -35
  146. data/test/scout/workflow/step/test_load.rb +1 -1
  147. data/test/scout/workflow/step/test_provenance.rb +1 -1
  148. data/test/scout/workflow/step/test_status.rb +33 -1
  149. data/test/scout/workflow/task/test_dependencies.rb +9 -7
  150. data/test/scout/workflow/task/test_inputs.rb +1 -1
  151. data/test/scout/workflow/test_definition.rb +1 -1
  152. data/test/scout/workflow/test_documentation.rb +1 -1
  153. data/test/scout/workflow/test_entity.rb +2 -2
  154. data/test/scout/workflow/test_step.rb +13 -13
  155. data/test/scout/workflow/test_usage.rb +1 -1
  156. data/test/test_helper.rb +1 -1
  157. metadata +3 -2
@@ -1,7 +1,7 @@
1
1
  require_relative 'job'
2
2
  require 'scout'
3
3
 
4
- module LSF
4
+ module LSF
5
5
  extend SchedulerJob
6
6
 
7
7
  def self.system
@@ -1,7 +1,7 @@
1
1
  require_relative 'job'
2
2
  require 'scout'
3
3
 
4
- module PBS
4
+ module PBS
5
5
  extend SchedulerJob
6
6
 
7
7
  def self.system
@@ -13,7 +13,7 @@ module PBS
13
13
  let TOTAL_PROCESORS="$(cat /proc/cpuinfo|grep ^processor |wc -l)"
14
14
  let MAX_MEMORY_DEFAULT="$(grep MemTotal /proc/meminfo|grep -o "[[:digit:]]*") / ( (1024 * $TOTAL_PROCESORS) / $PBS_CPUS_PER_TASK )"
15
15
  MAX_MEMORY="$MAX_MEMORY_DEFAULT"
16
- [ ! -z $PBS_MEM_PER_CPU ] && let MAX_MEMORY="$PBS_MEM_PER_CPU * $PBS_CPUS_PER_TASK"
16
+ [ ! -z $PBS_MEM_PER_CPU ] && let MAX_MEMORY="$PBS_MEM_PER_CPU * $PBS_CPUS_PER_TASK"
17
17
  [ ! -z $PBS_MEM_PER_NODE ] && MAX_MEMORY="$PBS_MEM_PER_NODE"
18
18
  export MAX_MEMORY_DEFAULT
19
19
  export MAX_MEMORY
@@ -36,7 +36,7 @@ cd ${PBS_O_WORKDIR}
36
36
  time = IndiferentHash.process_options options, :time
37
37
  nodes = IndiferentHash.process_options options, :nodes
38
38
 
39
- # PBS
39
+ # PBS
40
40
  place = IndiferentHash.process_options options, :place, :place => 'scatter'
41
41
  system = IndiferentHash.process_options options, :partition
42
42
  filesystems = IndiferentHash.process_options options, :filesystems
@@ -45,7 +45,7 @@ cd ${PBS_O_WORKDIR}
45
45
 
46
46
  filesystems = filesystems * "," if Array === filesystems
47
47
 
48
- # NOT USED
48
+ # NOT USED
49
49
  partition = IndiferentHash.process_options options, :partition
50
50
  task_cpus = IndiferentHash.process_options options, :task_cpus
51
51
  exclusive = IndiferentHash.process_options options, :exclusive
@@ -1,7 +1,7 @@
1
1
  require_relative 'job'
2
2
  require 'scout'
3
3
 
4
- module SLURM
4
+ module SLURM
5
5
 
6
6
  extend SchedulerJob
7
7
 
@@ -15,7 +15,7 @@ module SLURM
15
15
  let TOTAL_PROCESORS="$(cat /proc/cpuinfo|grep ^processor |wc -l)"
16
16
  let MAX_MEMORY_DEFAULT="$(grep MemTotal /proc/meminfo|grep -o "[[:digit:]]*") / ( (1024 * $TOTAL_PROCESORS) / $SLURM_CPUS_PER_TASK )"
17
17
  MAX_MEMORY="$MAX_MEMORY_DEFAULT"
18
- [ ! -z $SLURM_MEM_PER_CPU ] && let MAX_MEMORY="$SLURM_MEM_PER_CPU * $SLURM_CPUS_PER_TASK"
18
+ [ ! -z $SLURM_MEM_PER_CPU ] && let MAX_MEMORY="$SLURM_MEM_PER_CPU * $SLURM_CPUS_PER_TASK"
19
19
  [ ! -z $SLURM_MEM_PER_NODE ] && MAX_MEMORY="$SLURM_MEM_PER_NODE"
20
20
  export MAX_MEMORY_DEFAULT
21
21
  export MAX_MEMORY
@@ -12,31 +12,42 @@ module Workflow::Scheduler
12
12
  Workflow::Scheduler.process_batches(batches, options)
13
13
  end
14
14
 
15
+ def self.produce_single_batch(job, rules = {}, options = {})
16
+ batches = Workflow::Orchestrator.job_batches(rules, job)
17
+ rules = batches.inject({}){|acc,b| acc = Workflow::Orchestrator.accumulate_rules acc, b[:rules] }
18
+
19
+ max_time = batches.collect{|b| b[:rules][:time] }.max
20
+ rules[:time] = options.include?(:time) ? options[:time] : max_time
21
+ rules[:deploy] = :local
22
+ if rules[:exclusive]
23
+ rules[:task_cpus] = nil
24
+ rules[:cpus] = nil
25
+ end
26
+
27
+ batch = {top_level: job, jobs: [job], rules: rules, deps: [] }
28
+ Workflow::Scheduler.process_batches([batch], options)
29
+ end
30
+
31
+
15
32
  def self.process_batches(batches, process_options = {})
16
33
  failed_jobs = []
17
34
 
18
- pending = batches.dup
19
-
20
- sorted = []
21
- while pending.any?
22
- leaf_nodes = batches.select{|batch| (batch[:deps] - sorted).empty? }
23
- sorted.concat(leaf_nodes - sorted)
24
- pending -= leaf_nodes
25
- end
35
+ sorted = Workflow::Orchestrator.sort_batches batches
36
+ cleaned = Workflow::Orchestrator.clean_batches sorted
26
37
 
27
38
  batch_system = Scout::Config.get :system, :batch, :scheduler, 'env:BATCH_SYSTEM', default: 'SLURM'
28
39
 
29
40
  batch_ids = {}
30
- sorted.collect do |batch|
41
+ cleaned.collect do |batch|
31
42
  job_options = batch[:rules]
32
43
  job_options = IndiferentHash.add_defaults job_options, process_options.dup
33
44
 
34
45
  if batch[:deps].nil?
35
- batch_dependencies = []
36
- else
46
+ batch_dependencies = []
47
+ else
37
48
  top_jobs = batch[:jobs]
38
49
 
39
- batch_dependencies = batch[:deps].collect{|dep|
50
+ batch_dependencies = batch[:deps].collect{|dep|
40
51
  dep_target = dep[:top_level]
41
52
  id = batch_ids[dep_target].to_s
42
53
 
@@ -132,10 +132,10 @@ module Workflow
132
132
  info[:time] << time
133
133
 
134
134
  report_keys.each do |key|
135
- info[key] = dep_info[key]
135
+ info[key] = dep_info[key]
136
136
  end
137
137
 
138
- dep.info[:config_keys].each do |kinfo|
138
+ dep.info[:config_keys].each do |kinfo|
139
139
  key, value, tokens = kinfo
140
140
 
141
141
  info[key.to_s] = value if report_keys.include? key.to_s
@@ -31,7 +31,7 @@ module Workflow
31
31
  title = doc_parse_first_line doc
32
32
  description, task_info = doc_parse_up_to doc, /^# Tasks/i
33
33
  task_description, tasks = doc_parse_up_to task_info, /^##/, true
34
- tasks = doc_parse_chunks tasks, /^## (.*)/
34
+ tasks = doc_parse_chunks tasks, /^## (.*)/
35
35
  {:title => title.strip, :description => description.strip, :task_description => task_description.strip, :tasks => tasks}
36
36
  end
37
37
 
@@ -52,11 +52,11 @@ module Workflow
52
52
  documentation = Workflow.parse_workflow_doc documentation_markdown
53
53
 
54
54
  if @description && (documentation[:description].nil? || documentation[:description].empty?)
55
- documentation[:description] = @description
55
+ documentation[:description] = @description
56
56
  end
57
57
 
58
58
  if @title && (documentation[:title].nil? || documentation[:title].empty?)
59
- documentation[:title] = @title
59
+ documentation[:title] = @title
60
60
  end
61
61
  documentation[:tasks].each do |task, description|
62
62
  if task.include? "#"
@@ -74,7 +74,7 @@ module Workflow
74
74
  if workflow.tasks.include? task
75
75
  workflow.tasks[task].description = description
76
76
  else
77
- Log.low "Documentation for #{ task }, but not a #{ workflow.to_s } task"
77
+ Log.low "Documentation for #{ task }, but not a #{ workflow.to_s } task"
78
78
  end
79
79
  end
80
80
  documentation
@@ -39,7 +39,7 @@ module Workflow
39
39
  asynchronous_exports.replace asynchronous_exports - names if asynchronous_exports
40
40
  stream_exports.replace stream_exports - names if stream_exports
41
41
  end
42
-
42
+
43
43
  def export_exec(*names)
44
44
  unexport *names
45
45
  exec_exports.concat names
@@ -11,9 +11,9 @@ module Path
11
11
  _loaded = false
12
12
  begin
13
13
  Kernel.const_get(workflow)
14
- rescue
14
+ rescue
15
15
  if ! _loaded
16
- Workflow.require_workflow workflow
16
+ Workflow.require_workflow workflow
17
17
  _loaded = true
18
18
  retry
19
19
  end
@@ -40,7 +40,7 @@ class Step
40
40
  if c == "\n"
41
41
  Log.logn "STDOUT [#{child_pid}]: ", level
42
42
  end
43
- end
43
+ end
44
44
 
45
45
  io.join
46
46
 
@@ -1,4 +1,5 @@
1
1
  class Step
2
+
2
3
  def rec_dependencies(connected = false, seen = Set.new)
3
4
  @rec_dependencies = {}
4
5
  @rec_dependencies[connected] ||= begin
@@ -34,6 +35,31 @@ class Step
34
35
  end.compact.uniq
35
36
  end
36
37
 
38
+ def overrider?
39
+ ! (overriden_task.nil? && overriden_workflow.nil?)
40
+ end
41
+
42
+ def overriden?
43
+ @overriden
44
+ end
45
+
46
+ def overriden_deps
47
+ dependencies.select{|d| d.overriden? }
48
+ end
49
+
50
+ def recursive_overriden_deps
51
+ overriden_deps = self.overriden_deps
52
+ overriden_deps + overriden_deps.collect{|dep| dep.recursive_overriden_deps }
53
+ end
54
+
55
+ def overrider_deps
56
+ dependencies.select{|d| d.overrider? }
57
+ end
58
+
59
+ def recursive_overrider_deps
60
+ self.rec_dependencies.select{|dep| dep.overrider? }
61
+ end
62
+
37
63
  def prepare_dependencies
38
64
  inverse_dep = {}
39
65
 
@@ -44,7 +70,14 @@ class Step
44
70
  end
45
71
 
46
72
  next if dep.done?
47
- next if dep.error? && ! dep.recoverable_error?
73
+
74
+ if dep.error? && ! dep.recoverable_error?
75
+ if dep.canfail?
76
+ next
77
+ else
78
+ raise dep.exception
79
+ end
80
+ end
48
81
 
49
82
  if dep.dependencies
50
83
  dep.dependencies.each do |d|
@@ -74,7 +107,7 @@ class Step
74
107
  end
75
108
 
76
109
  def run_dependencies
77
- all_dependencies.each do |dep|
110
+ all_dependencies.each do |dep|
78
111
  next if dep.running? || dep.done?
79
112
  next if dep.error? && ! dep.recoverable_error?
80
113
 
@@ -100,7 +133,7 @@ class Step
100
133
  end
101
134
 
102
135
  def abort_dependencies
103
- all_dependencies.each{|dep| dep.abort if dep.running? }
136
+ all_dependencies.each{|dep| dep.abort if dep.running? }
104
137
  end
105
138
 
106
139
  def self.wait_for_jobs(jobs, canfail=false)
@@ -30,7 +30,8 @@ class Step
30
30
  end
31
31
 
32
32
  def save_info(info = nil)
33
- Persist.save(@info = info, info_file, SERIALIZER)
33
+ purged = Annotation.purge(@info = info)
34
+ Persist.save(purged, info_file, SERIALIZER)
34
35
  @info_load_time = Time.now
35
36
  end
36
37
 
@@ -82,6 +83,7 @@ class Step
82
83
 
83
84
  if start && eend
84
85
  time = eend - start
86
+ Log.warn "No issue time #{self.path}" if issued.nil?
85
87
  total_time = eend - issued
86
88
  if total_time - time > 1
87
89
  time_str = "#{Misc.format_seconds_short(time)} (#{Misc.format_seconds_short(total_time)})"
@@ -93,7 +95,7 @@ class Step
93
95
  message = Log.color(:time, time_str)
94
96
  end
95
97
  end
96
- report_status value, message
98
+ report_status value, message
97
99
  end
98
100
 
99
101
  if key == :message
@@ -136,7 +138,7 @@ class Step
136
138
  def set_info(key, value)
137
139
  merge_info(key => value)
138
140
  end
139
-
141
+
140
142
  def report_status(status, message = nil)
141
143
  if message.nil?
142
144
  Log.info [Log.color(:status, status, true), Log.color(:task, task_name, true), Log.color(:path, path)] * " "
@@ -184,22 +186,6 @@ class Step
184
186
  ! (done? && status == :done) && (info[:pid] && Misc.pid_alive?(info[:pid]))
185
187
  end
186
188
 
187
- def overriden?
188
- @overriden = overriden_task || overriden_workflow || overriden_deps.any? if @overriden.nil?
189
- @overriden
190
- end
191
-
192
- def overriden_deps
193
- dependencies.select{|d| d.overriden? }
194
- end
195
-
196
- def recursive_overriden_deps
197
- overriden_deps = dependencies.select{|d|
198
- d.overriden?
199
- }
200
- (overriden_deps + overriden_deps.collect{|d| d.recursive_overriden_deps }).flatten.uniq
201
- end
202
-
203
189
  def exception
204
190
  return nil unless info[:exception]
205
191
  begin
@@ -3,7 +3,7 @@ class Step
3
3
  if clean_name != name
4
4
  #hash = name[clean_name.length..-1]
5
5
  #inputs_dir += hash
6
- Log.medium "Saving job inputs to: #{Log.fingerprint inputs_dir}"
6
+ Log.medium "Saving job inputs to: #{Log.fingerprint inputs_dir} #{Log.fingerprint provided_inputs}"
7
7
  self.task.save_inputs(inputs_dir, provided_inputs)
8
8
  else
9
9
  Log.medium "Saving no input job: #{Log.fingerprint inputs_dir}"
@@ -27,9 +27,9 @@ class Step
27
27
  end
28
28
 
29
29
  def monitor_stream(stream, options = {}, &block)
30
- case options[:bar]
30
+ case options[:bar]
31
31
  when TrueClass
32
- bar = progress_bar
32
+ bar = progress_bar
33
33
  when Hash
34
34
  bar = progress_bar options[:bar]
35
35
  when Numeric
@@ -58,10 +58,10 @@ class Step
58
58
  str = if ! (Open.remote?(path) || Open.ssh?(path)) && (Open.exists?(path) && $main_mtime && path_mtime && ($main_mtime - path_mtime) < -2)
59
59
  prov_status_msg(status.to_s) << " " << [workflow, task, path, input_str].compact * " " << " (#{Log.color(:red, "Mtime out of sync") })"
60
60
  else
61
- prov_status_msg(status.to_s) << " " << [workflow, task, path, input_str].compact * " "
61
+ prov_status_msg(status.to_s) << " " << [workflow, task, path, input_str].compact * " "
62
62
  end
63
63
 
64
- if $inputs and $inputs.any?
64
+ if $inputs and $inputs.any?
65
65
  job_inputs = Step.new(path).recursive_inputs.to_hash
66
66
  IndiferentHash.setup(job_inputs)
67
67
 
@@ -119,7 +119,7 @@ class Step
119
119
  step.dependencies.each do |dep|
120
120
  if dep.input_dependencies.any?
121
121
  dep.input_dependencies.each do |id|
122
- input_name, _dep = dep.recursive_inputs.select{|f,d|
122
+ input_name, _dep = dep.recursive_inputs.select{|f,d|
123
123
  d == id || (String === d && d.start_with?(id.files_dir)) || (Array === d && d.include?(id))
124
124
  }.keys.last
125
125
  if input_name
@@ -135,7 +135,7 @@ class Step
135
135
  indent = prov_indent(step, offset, input_dependencies)
136
136
  str << indent + this_step_msg if ENV["SCOUT_ORIGINAL_STACK"] == 'true'
137
137
 
138
- step.dependencies.dup.tap{|l|
138
+ step.dependencies.dup.tap{|l|
139
139
  l.reverse! if ENV["SCOUT_ORIGINAL_STACK"] == 'true'
140
140
  }.each do |dep|
141
141
  path = dep.path
@@ -5,7 +5,7 @@ class Step
5
5
  begin
6
6
  s = Misc.abort_child pid, true
7
7
  Log.medium "Aborted pid #{path} #{s}"
8
- rescue
8
+ rescue
9
9
  Log.debug("Aborted job #{pid} was not killed: #{$!.message}")
10
10
  end
11
11
  else
@@ -17,35 +17,49 @@ class Step
17
17
  end
18
18
 
19
19
  def recoverable_error?
20
- self.error? && ! (ScoutException === self.exception)
20
+ self.error? && ! (ENV['SCOUT_NO_RECOVERABLE_ERROR'].to_s.downcase == 'true') && ! (ScoutException === self.exception)
21
21
  end
22
22
 
23
23
  def newer_dependencies
24
+ rec_dependencies = self.rec_dependencies
25
+ rec_dependencies = rec_dependencies.select{|dep| Open.exists?(dep.info_file) }
26
+ rec_dependencies = rec_dependencies.reject{|dep| dep.error? && ! dep.recoverable_error? }
24
27
  newer = rec_dependencies.select{|dep| Path.newer?(self.path, dep.path) }
25
28
  newer += input_dependencies.select{|dep| Path.newer?(self.path, dep.path) }
26
29
  newer += rec_dependencies.collect{|dep| dep.input_dependencies }.flatten.select{|dep| Path.newer?(self.path, dep.path) }
27
30
  newer
28
31
  end
29
32
 
33
+ def cleaned_dependencies
34
+ return []
35
+ rec_dependencies = self.rec_dependencies
36
+ cleaned = rec_dependencies.select{|dep| dep.info[:status] == :cleaned }
37
+ cleaned += input_dependencies.select{|dep| dep.info[:status] == :cleaned }
38
+ cleaned += rec_dependencies.collect{|dep| dep.input_dependencies }.flatten.select{|dep| dep.info[:status] == :cleaned }
39
+ cleaned
40
+ end
41
+
30
42
  def updated?
31
43
  return false if self.error? && self.recoverable_error?
32
- return true if (self.done? || (self.error? && ! self.recoverable_error?)) && ! ENV["SCOUT_UPDATE"]
44
+ return true if (self.done? || (self.error? && ! self.recoverable_error?)) && ! ENV["SCOUT_UPDATE"].to_s.downcase == 'true'
33
45
  newer = newer_dependencies
46
+ cleaned = cleaned_dependencies
34
47
 
35
48
  Log.low "Newer deps found for #{Log.fingerprint self}: #{Log.fingerprint newer}" if newer.any?
36
- newer.empty?
49
+ Log.low "Cleaned deps found for #{Log.fingerprint self}: #{Log.fingerprint cleaned}" if cleaned.any?
50
+ newer.empty? && cleaned.empty?
37
51
  end
38
52
 
39
53
  def clean
40
54
  Log.debug "Cleaning job files: #{path}"
41
- @take_stream = nil
55
+ @take_stream = nil
42
56
  @result = nil
43
57
  @info = nil
44
58
  @info_load_time = nil
45
59
  @done = nil
46
- Open.rm path if Open.exist_or_link?(path)
47
- Open.rm tmp_path if Open.exist_or_link?(tmp_path)
48
- Open.rm info_file if Open.exist_or_link?(info_file)
60
+ Open.rm path if Open.exist_or_link?(path) && Path.can_write?(path)
61
+ Open.rm tmp_path if Open.exist_or_link?(tmp_path) && Path.can_write?(tmp_path)
62
+ Open.rm info_file if Open.exist_or_link?(info_file) && Path.can_write?(info_file)
49
63
  Open.rm_rf files_dir if Open.exist_or_link?(files_dir)
50
64
  self
51
65
  end
@@ -59,7 +73,7 @@ class Step
59
73
  dependencies.each do |dep|
60
74
  dep.recursive_clean
61
75
  end
62
- clean
76
+ clean if Open.exists?(self.info_file)
63
77
  end
64
78
 
65
79
  def canfail?
@@ -13,17 +13,18 @@ require_relative 'step/inputs'
13
13
  require_relative 'step/children'
14
14
  require_relative 'step/archive'
15
15
 
16
- class Step
16
+ class Step
17
17
 
18
18
  attr_accessor :path, :inputs, :dependencies, :id, :task, :tee_copies, :non_default_inputs, :provided_inputs, :compute, :overriden_task, :overriden_workflow, :workflow, :exec_context, :overriden
19
- def initialize(path = nil, inputs = nil, dependencies = nil, id = nil, non_default_inputs = nil, provided_inputs = nil, compute = nil, exec_context: nil, &task)
19
+ def initialize(path = nil, inputs = nil, dependencies = nil, id = nil, non_default_inputs = nil, provided_inputs = nil, compute = nil, overriden = nil, exec_context: nil, &task)
20
20
  @path = path
21
21
  @inputs = inputs
22
22
  @dependencies = dependencies
23
23
  @id = id
24
24
  @non_default_inputs = non_default_inputs
25
25
  @provided_inputs = provided_inputs
26
- @compute = compute
26
+ @compute = compute
27
+ @overriden = overriden unless overriden.nil?
27
28
  @task = task
28
29
  @mutex = Mutex.new
29
30
  @tee_copies = 1
@@ -36,12 +37,12 @@ class Step
36
37
 
37
38
  def provided_inputs
38
39
  @provided_inputs ||= begin
39
- if info_file && Open.exists?(info_file)
40
- info[:provided_inputs]
41
- else
42
- {}
43
- end
44
- end
40
+ if info_file && Open.exists?(info_file)
41
+ info[:provided_inputs]
42
+ else
43
+ {}
44
+ end
45
+ end
45
46
  end
46
47
 
47
48
  def non_default_inputs
@@ -97,7 +98,7 @@ class Step
97
98
  return @id if @id
98
99
  return info[:clean_name] if info.include? :clean_name
99
100
  if m = name.match(/(.+?)(?:_[a-z0-9]{32})?(?:\..*)?$/)
100
- return m[1]
101
+ return m[1]
101
102
  end
102
103
  return name.split(".").first
103
104
  end
@@ -189,9 +190,10 @@ class Step
189
190
  end
190
191
  end
191
192
 
192
-
193
193
  return @result || self.load if done?
194
+
194
195
  prepare_dependencies
196
+
195
197
  begin
196
198
 
197
199
 
@@ -200,11 +202,11 @@ class Step
200
202
 
201
203
 
202
204
  reset_info :status => :setup, :issued => Time.now,
203
- :pid => Process.pid, :pid_hostname => Misc.hostname,
205
+ :pid => Process.pid, :pid_hostname => Misc.hostname,
204
206
  :task_name => task_name, :workflow => workflow.to_s,
205
- :provided_inputs => Annotation.purge(provided_inputs),
207
+ :provided_inputs => IndiferentHash.serializable(provided_inputs),
206
208
  :non_default_inputs => non_default_inputs,
207
- :inputs => Annotation.purge(inputs), :input_names => input_names, :type => type,
209
+ :inputs => IndiferentHash.serializable(inputs), :input_names => input_names, :type => type,
208
210
  :dependencies => (dependencies || []) .collect{|d| d.path }
209
211
 
210
212
  run_dependencies
@@ -313,7 +315,7 @@ class Step
313
315
  end
314
316
 
315
317
  def streaming?
316
- @take_stream || IO === @result || StringIO === @result
318
+ @take_stream || IO === @result || StringIO === @result
317
319
  end
318
320
 
319
321
  def stream
@@ -344,16 +346,16 @@ class Step
344
346
  end
345
347
 
346
348
  def consume_all_streams
347
- threads = []
349
+ threads = []
348
350
  while @result && streaming? && stream = self.stream
349
351
  threads << Open.consume_stream(stream, true)
350
352
  end
351
353
 
352
354
  threads.compact!
353
355
 
354
- threads.each do |t|
356
+ threads.each do |t|
355
357
  begin
356
- t.join
358
+ t.join
357
359
  rescue Exception
358
360
  threads.compact.each{|t| t.raise(Aborted); t.join }
359
361
  raise $!
@@ -388,7 +390,7 @@ class Step
388
390
 
389
391
  raise self.exception if self.exception
390
392
 
391
- raise "Error in job #{self.path}" if self.error? or self.aborted?
393
+ raise "Error in job #{self.path}" if self.error? or self.aborted?
392
394
 
393
395
  self
394
396
  end
@@ -2,7 +2,7 @@ module Task
2
2
  def dependencies(id, provided_inputs, non_default_inputs = [], compute = {})
3
3
  return [] if deps.nil?
4
4
  dependencies = []
5
-
5
+
6
6
  provided_inputs ||= {}
7
7
 
8
8
  # Helper function
@@ -66,8 +66,15 @@ module Task
66
66
 
67
67
  if provided_inputs.include?(overriden = [workflow.name, task] * "#")
68
68
  dep = provided_inputs[overriden]
69
- dep = Step.new dep unless Step === dep
70
- dep = dep.dup
69
+ dep = case dep
70
+ when Step
71
+ dep
72
+ when String
73
+ Step.new dep
74
+ when Symbol
75
+ dependencies.select{|dep| dep.task_name == dep }.last
76
+ end
77
+
71
78
  dep.type = workflow.tasks[task].type
72
79
  dep.overriden_task = task
73
80
  dep.overriden_workflow = workflow
@@ -42,8 +42,8 @@ module Workflow
42
42
  def rec_input_use(task_name)
43
43
  input_use = {}
44
44
  task = self.tasks[task_name]
45
- task.inputs.each do |name,_|
46
- input_use[name] ||= {}
45
+ task.inputs.each do |name,_|
46
+ input_use[name] ||= {}
47
47
  input_use[name][self] ||= []
48
48
  input_use[name][self] << task_name
49
49
  end
@@ -69,7 +69,7 @@ module Workflow
69
69
  raise "No '#{name}' task in '#{self.name}' Workflow" if task.nil?
70
70
  id = File.join(self.name, name.to_s)
71
71
  @task_info ||= {}
72
- @task_info[id] ||= begin
72
+ @task_info[id] ||= begin
73
73
  description = task.description
74
74
  returns = task.returns
75
75
 
@@ -3,9 +3,9 @@ module Task
3
3
  def self.format_input(value, type, options = {})
4
4
  return value if IO === value || StringIO === value || Step === value
5
5
 
6
- if String === value && ! [:path, :file, :folder, :binary, :tsv].include?(type) && ! (options && (options[:noload] || options[:stream] || options[:nofile] || options[:asfile]))
6
+ if String === value && Path.is_filename?(value) && ! [:path, :file, :folder, :binary, :tsv].include?(type) && ! (options && (options[:noload] || options[:stream] || options[:nofile] || options[:asfile]))
7
7
  if Open.exists?(value) && ! Open.directory?(value)
8
- Persist.load(value, type)
8
+ Persist.load(value, type)
9
9
  else
10
10
  Persist.deserialize(value, type)
11
11
  end
@@ -96,7 +96,7 @@ module Task
96
96
  basename += "-#{digest}"
97
97
  end
98
98
  new_file = File.join(directory, 'saved_input_files', basename)
99
- relative_file = File.join('.', 'saved_input_files', basename)
99
+ relative_file = File.join('.', 'saved_input_files', basename)
100
100
  Open.link orig_file, new_file
101
101
  relative_file
102
102
  end
@@ -104,7 +104,7 @@ module Task
104
104
  def self.save_input(directory, name, type, value)
105
105
  input_file = File.join(directory, name.to_s)
106
106
 
107
- if Path.is_filename?(value)
107
+ if Path.is_filename?(value)
108
108
  if type == :path
109
109
  Open.write(input_file + ".as_path", value)
110
110
  elsif Path.step_file?(value)
@@ -114,7 +114,7 @@ module Task
114
114
  Open.write(input_file + ".as_file", relative_file)
115
115
  end
116
116
  elsif Step === value
117
- Open.write(input_file + ".as_step", value.short_path)
117
+ Open.write(input_file + ".as_step", value.identify_path)
118
118
  elsif type == :file
119
119
  relative_file = save_file_input(value, directory)
120
120
  Persist.save(relative_file, input_file, :file)
@@ -153,8 +153,8 @@ module Task
153
153
  value.sub!(/^\./, File.dirname(filename)) if value.start_with?("./")
154
154
  value
155
155
  elsif filename.end_with?('.as_step')
156
- value = Open.read(filename).strip
157
- Step.load value
156
+ value = Path.setup Open.read(filename).strip
157
+ Step.load value.find
158
158
  elsif filename.end_with?('.as_path')
159
159
  value = Open.read(filename).strip
160
160
  Path.setup value
@@ -183,7 +183,7 @@ module Task
183
183
  self.recursive_inputs.each do |p|
184
184
  name, type, desc, value, options = p
185
185
  next if seen.include?(name)
186
- filename = File.join(directory, name.to_s)
186
+ filename = File.join(directory, name.to_s)
187
187
  value = Task.load_input_from_file(filename, type, options)
188
188
  inputs[name] = value unless value.nil?
189
189
  seen << name