scout-gear 8.0.0 → 9.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +48 -9
  3. data/Rakefile +6 -1
  4. data/VERSION +1 -1
  5. data/bin/scout +16 -4
  6. data/doc/lib/scout/path.md +35 -0
  7. data/doc/lib/scout/workflow/task.md +13 -0
  8. data/lib/rbbt-scout.rb +2 -1
  9. data/lib/scout/cmd.rb +32 -29
  10. data/lib/scout/concurrent_stream.rb +36 -19
  11. data/lib/scout/exceptions.rb +10 -0
  12. data/lib/scout/indiferent_hash.rb +17 -0
  13. data/lib/scout/log/color.rb +11 -11
  14. data/lib/scout/log/progress/report.rb +8 -5
  15. data/lib/scout/log/progress/util.rb +3 -0
  16. data/lib/scout/log/trap.rb +3 -3
  17. data/lib/scout/log.rb +67 -36
  18. data/lib/scout/meta_extension.rb +34 -0
  19. data/lib/scout/misc/digest.rb +11 -2
  20. data/lib/scout/misc/filesystem.rb +2 -3
  21. data/lib/scout/misc/format.rb +12 -7
  22. data/lib/scout/misc/monitor.rb +11 -0
  23. data/lib/scout/misc/system.rb +48 -0
  24. data/lib/scout/named_array.rb +8 -0
  25. data/lib/scout/offsite/ssh.rb +174 -0
  26. data/lib/scout/offsite/step.rb +100 -0
  27. data/lib/scout/offsite/sync.rb +55 -0
  28. data/lib/scout/offsite.rb +3 -0
  29. data/lib/scout/open/lock.rb +5 -24
  30. data/lib/scout/open/remote.rb +12 -1
  31. data/lib/scout/open/stream.rb +109 -122
  32. data/lib/scout/open/util.rb +9 -0
  33. data/lib/scout/open.rb +12 -11
  34. data/lib/scout/path/find.rb +15 -10
  35. data/lib/scout/path/util.rb +5 -0
  36. data/lib/scout/path.rb +1 -1
  37. data/lib/scout/persist/serialize.rb +4 -4
  38. data/lib/scout/persist.rb +1 -1
  39. data/lib/scout/resource/open.rb +8 -0
  40. data/lib/scout/resource/path.rb +16 -9
  41. data/lib/scout/resource/software.rb +4 -2
  42. data/lib/scout/resource/util.rb +10 -4
  43. data/lib/scout/resource.rb +2 -0
  44. data/lib/scout/tsv/dumper.rb +5 -1
  45. data/lib/scout/tsv/index.rb +28 -86
  46. data/lib/scout/tsv/open.rb +35 -14
  47. data/lib/scout/tsv/parser.rb +22 -5
  48. data/lib/scout/tsv/persist/tokyocabinet.rb +2 -0
  49. data/lib/scout/tsv/stream.rb +204 -0
  50. data/lib/scout/tsv/transformer.rb +11 -0
  51. data/lib/scout/tsv.rb +9 -2
  52. data/lib/scout/work_queue/worker.rb +2 -2
  53. data/lib/scout/work_queue.rb +37 -12
  54. data/lib/scout/workflow/definition.rb +2 -1
  55. data/lib/scout/workflow/deployment/orchestrator.rb +254 -0
  56. data/lib/scout/workflow/deployment.rb +1 -0
  57. data/lib/scout/workflow/step/dependencies.rb +46 -14
  58. data/lib/scout/workflow/step/file.rb +5 -0
  59. data/lib/scout/workflow/step/info.rb +13 -3
  60. data/lib/scout/workflow/step/inputs.rb +5 -0
  61. data/lib/scout/workflow/step/load.rb +1 -1
  62. data/lib/scout/workflow/step/provenance.rb +1 -0
  63. data/lib/scout/workflow/step/status.rb +27 -9
  64. data/lib/scout/workflow/step.rb +82 -30
  65. data/lib/scout/workflow/task/dependencies.rb +116 -0
  66. data/lib/scout/workflow/task/inputs.rb +36 -17
  67. data/lib/scout/workflow/task.rb +12 -109
  68. data/lib/scout/workflow/usage.rb +57 -41
  69. data/lib/scout/workflow.rb +19 -13
  70. data/lib/scout-gear.rb +2 -0
  71. data/lib/scout.rb +6 -0
  72. data/scout-gear.gemspec +38 -7
  73. data/scout_commands/doc +37 -0
  74. data/scout_commands/find +1 -0
  75. data/scout_commands/offsite +30 -0
  76. data/scout_commands/resource/produce +66 -0
  77. data/scout_commands/template +52 -0
  78. data/scout_commands/update +29 -0
  79. data/scout_commands/workflow/info +15 -3
  80. data/scout_commands/workflow/install +105 -0
  81. data/scout_commands/workflow/task +46 -6
  82. data/share/software/install_helpers +2 -2
  83. data/share/templates/command +25 -0
  84. data/share/templates/workflow.rb +14 -0
  85. data/test/scout/offsite/test_ssh.rb +15 -0
  86. data/test/scout/offsite/test_step.rb +32 -0
  87. data/test/scout/offsite/test_sync.rb +36 -0
  88. data/test/scout/offsite/test_task.rb +0 -0
  89. data/test/scout/resource/test_path.rb +6 -0
  90. data/test/scout/test_named_array.rb +6 -0
  91. data/test/scout/test_persist.rb +3 -2
  92. data/test/scout/test_tsv.rb +17 -0
  93. data/test/scout/test_work_queue.rb +64 -42
  94. data/test/scout/tsv/persist/test_adapter.rb +1 -1
  95. data/test/scout/tsv/test_index.rb +14 -0
  96. data/test/scout/tsv/test_parser.rb +35 -0
  97. data/test/scout/tsv/test_stream.rb +200 -0
  98. data/test/scout/tsv/test_transformer.rb +12 -0
  99. data/test/scout/workflow/deployment/test_orchestrator.rb +272 -0
  100. data/test/scout/workflow/step/test_dependencies.rb +68 -0
  101. data/test/scout/workflow/step/test_info.rb +17 -0
  102. data/test/scout/workflow/step/test_status.rb +0 -1
  103. data/test/scout/workflow/task/test_dependencies.rb +357 -0
  104. data/test/scout/workflow/task/test_inputs.rb +52 -0
  105. data/test/scout/workflow/test_definition.rb +18 -0
  106. data/test/scout/workflow/test_documentation.rb +24 -0
  107. data/test/scout/workflow/test_step.rb +109 -0
  108. data/test/scout/workflow/test_task.rb +0 -287
  109. data/test/test_scout.rb +9 -0
  110. metadata +89 -5
  111. data/scout_commands/workflow/task_old +0 -706
@@ -8,16 +8,19 @@ require_relative 'step/dependencies'
8
8
  require_relative 'step/provenance'
9
9
  require_relative 'step/config'
10
10
  require_relative 'step/progress'
11
+ require_relative 'step/inputs'
11
12
 
12
13
  class Step
13
14
 
14
- attr_accessor :path, :inputs, :dependencies, :id, :task, :tee_copies, :non_default_inputs
15
- def initialize(path = nil, inputs = nil, dependencies = nil, id = nil, non_default_inputs = nil, &task)
15
+ attr_accessor :path, :inputs, :dependencies, :id, :task, :tee_copies, :non_default_inputs, :provided_inputs, :compute, :overriden_task, :overriden_workflow
16
+ def initialize(path = nil, inputs = nil, dependencies = nil, id = nil, non_default_inputs = nil, provided_inputs = nil, compute = nil, &task)
16
17
  @path = path
17
18
  @inputs = inputs
18
19
  @dependencies = dependencies
19
20
  @id = id
20
21
  @non_default_inputs = non_default_inputs
22
+ @provided_inputs = provided_inputs
23
+ @compute = compute
21
24
  @task = task
22
25
  @mutex = Mutex.new
23
26
  @tee_copies = 1
@@ -42,7 +45,7 @@ class Step
42
45
  if Open.exists?(info_file)
43
46
  info[:dependencies].collect do |path|
44
47
  Step.load(path)
45
- end
48
+ end if info[:dependencies]
46
49
  else
47
50
  []
48
51
  end
@@ -92,7 +95,12 @@ class Step
92
95
  inputs = new_inputs
93
96
  end
94
97
 
95
- @result = self.instance_exec(*inputs, &task)
98
+ @result = begin
99
+ @in_exec = true
100
+ self.instance_exec(*inputs, &task)
101
+ ensure
102
+ @in_exec = false
103
+ end
96
104
  end
97
105
 
98
106
  def tmp_path
@@ -115,11 +123,10 @@ class Step
115
123
  Persist.persist(name, type, :path => path, :tee_copies => tee_copies) do
116
124
  clear_info
117
125
  merge_info :status => :start, :start => Time.now,
118
- :pid => Process.pid, :pid_hostname => ENV["HOSTNAME"],
119
- :inputs => inputs, :type => type,
126
+ :pid => Process.pid, :pid_hostname => Misc.hostname,
127
+ :inputs => MetaExtension.purge(inputs), :type => type,
120
128
  :dependencies => dependencies.collect{|d| d.path }
121
129
 
122
-
123
130
  @result = exec
124
131
 
125
132
  if @result.nil? && File.exist?(self.tmp_path) && ! File.exist?(self.path)
@@ -129,6 +136,13 @@ class Step
129
136
  end
130
137
 
131
138
  @result
139
+
140
+ if (IO === @result || StringIO === @result) && (ENV["SCOUT_NO_STREAM"] == "true" || ! stream)
141
+ Open.sensible_write(self.path, @result)
142
+ @result = nil
143
+ else
144
+ @result
145
+ end
132
146
  end
133
147
  rescue Exception => e
134
148
  merge_info :status => :error, :exception => e, :end => Time.now
@@ -142,10 +156,14 @@ class Step
142
156
  end
143
157
 
144
158
  @result.abort_callback = proc do |exception|
145
- if Aborted === exception || Interrupt === exception
159
+ if exception.nil? || Aborted === exception || Interrupt === exception
146
160
  merge_info :status => :aborted, :end => Time.now
147
161
  else
148
- merge_info :status => :error, :exception => exception, :end => Time.now
162
+ begin
163
+ merge_info :status => :error, :exception => exception, :end => Time.now
164
+ rescue Exception
165
+ Log.exception $!
166
+ end
149
167
  end
150
168
  end
151
169
 
@@ -155,18 +173,16 @@ class Step
155
173
  end
156
174
  end
157
175
  end
176
+ end
158
177
 
159
- if stream && ENV["SCOUT_NO_STREAM"].nil?
160
- @result
161
- else
162
- if IO === @result || @result.respond_to?(:stream)
163
- join
164
- @result = nil
165
- self.load
166
- else
167
- @result
168
- end
178
+ def fork
179
+ Process.fork do
180
+ clear_info unless present?
181
+ run(false)
182
+ join
169
183
  end
184
+ grace
185
+ self
170
186
  end
171
187
 
172
188
  def done?
@@ -185,16 +201,21 @@ class Step
185
201
  else
186
202
  Log.debug "Taking result #{Log.fingerprint @result}"
187
203
  end
204
+
188
205
  @take_stream, @result = @result, @result.next
189
- @take_stream
190
- elsif done?
206
+
207
+ return @take_stream
208
+ end
209
+ end
210
+
211
+ if done?
212
+ Open.open(self.path)
213
+ else
214
+ if running? || waiting?
215
+ join
191
216
  Open.open(self.path)
192
217
  else
193
- if running?
194
- nil
195
- else
196
- exec
197
- end
218
+ exec
198
219
  end
199
220
  end
200
221
  end
@@ -207,21 +228,47 @@ class Step
207
228
  threads.each do |t|
208
229
  begin
209
230
  t.join
210
- rescue
231
+ rescue Exception
211
232
  threads.each{|t| t.raise(Aborted); t.join }
212
233
  raise $!
213
234
  end
214
235
  end
215
236
  end
216
237
 
238
+ def present?
239
+ Open.exist?(path) ||
240
+ Open.exist?(info_file) ||
241
+ Open.exist?(files_dir)
242
+ end
243
+
244
+ def grace
245
+ while ! present?
246
+ sleep 0.1
247
+ end
248
+ end
249
+
250
+ def terminated?
251
+ ! @in_exec && (done? || error? || aborted?)
252
+ end
253
+
217
254
  def join
218
255
  consume_all_streams
256
+ while @result.nil? && (present? && ! (terminated? || done?))
257
+ sleep 0.1
258
+ end
259
+ raise self.exception if self.exception
260
+ raise "Error in job #{self.path}" if self.error? or self.aborted?
219
261
  self
220
262
  end
221
263
 
222
- def produce
223
- run
224
- join
264
+ def produce(with_fork: false)
265
+ if with_fork
266
+ self.fork
267
+ self.join
268
+ else
269
+ run
270
+ end
271
+ self
225
272
  end
226
273
 
227
274
  def load
@@ -233,6 +280,7 @@ class Step
233
280
  def step(task_name)
234
281
  dependencies.each do |dep|
235
282
  return dep if dep.task_name == task_name
283
+ return dep if dep.overriden_task == task_name
236
284
  rec_dep = dep.step(task_name)
237
285
  return rec_dep if rec_dep
238
286
  end
@@ -250,4 +298,8 @@ class Step
250
298
  def fingerprint
251
299
  digest_str
252
300
  end
301
+
302
+ def task_signature
303
+ [workflow.to_s, task_name] * "#"
304
+ end
253
305
  end
@@ -0,0 +1,116 @@
1
+ module Task
2
+ def dependencies(id, provided_inputs, non_default_inputs = [], compute = {})
3
+ return [] if deps.nil?
4
+ dependencies = []
5
+
6
+ provided_inputs ||= {}
7
+
8
+ # Helper function
9
+ load_dep = proc do |id, workflow, task, step_options, definition_options, dependencies|
10
+ task = step_options.delete(:task) if step_options.include?(:task)
11
+ workflow = step_options.delete(:workflow) if step_options.include?(:workflow)
12
+ id = step_options.delete(:id) if step_options.include?(:id)
13
+ id = step_options.delete(:jobname) if step_options.include?(:jobname)
14
+
15
+ step_inputs = step_options.include?(:inputs)? step_options.delete(:inputs) : step_options
16
+ step_inputs = IndiferentHash.add_defaults step_inputs, definition_options
17
+
18
+ resolved_inputs = {}
19
+ step_inputs.each do |k,v|
20
+ if Symbol === v
21
+ input_dep = dependencies.select{|d| d.task_name == v }.first
22
+ resolved_inputs[k] = input_dep || step_inputs[v] || k
23
+ else
24
+ resolved_inputs[k] = v
25
+ end
26
+ end
27
+ job = workflow.job(task, id, resolved_inputs)
28
+ compute_options = definition_options[:compute] || []
29
+ compute_options = [compute_options] unless Array === compute_options
30
+ compute_options << :canfail if definition_options[:canfail]
31
+ compute_options << :produce if definition_options[:produce]
32
+ compute_options << :stream if definition_options[:stream]
33
+ compute[job.path] = compute_options if compute_options.any?
34
+ [job, step_inputs]
35
+ end
36
+
37
+ # Helper function
38
+ find_dep_non_default_inputs = proc do |dep,definition_options,step_inputs={}|
39
+ dep_non_default_inputs = dep.non_default_inputs
40
+ dep_non_default_inputs.select do |name|
41
+ step_inputs.include?(name)
42
+ end
43
+ dep_non_default_inputs.reject! do |name|
44
+ definition_options.include?(name) &&
45
+ (definition_options[name] != :placeholder || definition_options[name] != dep.inputs[name])
46
+ end
47
+
48
+ dep_non_default_inputs
49
+ end
50
+
51
+ deps.each do |workflow,task,definition_options,block=nil|
52
+ definition_options[:id] = definition_options.delete(:jobname) if definition_options.include?(:jobname)
53
+
54
+ if provided_inputs.include?(overriden = [workflow.name, task] * "#")
55
+ dep = provided_inputs[overriden]
56
+ dep = Step.new dep unless Step === dep
57
+ dep.type = workflow.tasks[task].type
58
+ dep.overriden_task = task
59
+ dep.overriden_workflow = workflow
60
+ dependencies << dep
61
+ non_default_inputs << overriden
62
+ next
63
+ end
64
+
65
+ definition_options ||= {}
66
+
67
+ if block
68
+ fixed_provided_inputs = self.assign_inputs(provided_inputs).first.to_hash
69
+ self.inputs.each do |name,type,desc,value|
70
+ fixed_provided_inputs[name] = value unless fixed_provided_inputs.include?(name)
71
+ end
72
+ fixed_provided_inputs = IndiferentHash.add_defaults fixed_provided_inputs, provided_inputs
73
+ block_options = IndiferentHash.add_defaults definition_options.dup, fixed_provided_inputs
74
+
75
+ res = block.call id, block_options, dependencies
76
+
77
+ case res
78
+ when Step
79
+ dep = res
80
+ dependencies << dep
81
+ dep_non_default_inputs = find_dep_non_default_inputs.call(dep, block_options)
82
+ non_default_inputs.concat(dep_non_default_inputs)
83
+ when Hash
84
+ step_options = block_options.merge(res)
85
+ dep, step_inputs = load_dep.call(id, workflow, task, step_options, block_options, dependencies)
86
+ dependencies << dep
87
+ dep_non_default_inputs = find_dep_non_default_inputs.call(dep, definition_options, step_inputs)
88
+ non_default_inputs.concat(dep_non_default_inputs)
89
+ when Array
90
+ res.each do |_res|
91
+ if Hash === _res
92
+ step_options = block_options.merge(_res)
93
+ dep, step_inputs = load_dep.call(id, workflow, task, step_options, block_options, dependencies)
94
+ dependencies << dep
95
+ dep_non_default_inputs = find_dep_non_default_inputs.call(dep, definition_options, step_inputs)
96
+ non_default_inputs.concat(dep_non_default_inputs)
97
+ else
98
+ dep = _res
99
+ dependencies << dep
100
+ dep_non_default_inputs = find_dep_non_default_inputs.call(dep, block_options)
101
+ non_default_inputs.concat(dep_non_default_inputs)
102
+ end
103
+ end
104
+ end
105
+ else
106
+ step_options = IndiferentHash.add_defaults definition_options.dup, provided_inputs
107
+ dep, step_inputs = load_dep.call(id, workflow, task, step_options, definition_options, dependencies)
108
+ dependencies << dep
109
+ dep_non_default_inputs = find_dep_non_default_inputs.call(dep, definition_options, step_inputs)
110
+ non_default_inputs.concat(dep_non_default_inputs)
111
+ end
112
+ end
113
+
114
+ dependencies
115
+ end
116
+ end
@@ -3,7 +3,7 @@ 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].include?(type) && (options.nil? || (! options[:noload] || options[:stream]))
6
+ if String === value && ! [:path, :file, :folder, :binary].include?(type) && ! (options && (options[:noload] || options[:stream] || options[:nofile]))
7
7
  if Open.exists?(value) && ! Open.directory?(value)
8
8
  Persist.load(value, type)
9
9
  else
@@ -20,7 +20,7 @@ module Task
20
20
  end
21
21
  end
22
22
 
23
- def assign_inputs(provided_inputs = {})
23
+ def assign_inputs(provided_inputs = {}, id = nil)
24
24
  if self.inputs.nil? || (self.inputs.empty? && Array === provided_inputs)
25
25
  case provided_inputs
26
26
  when Array
@@ -43,6 +43,8 @@ module Task
43
43
  if ! provided.nil? && provided != value
44
44
  non_default_inputs << name.to_sym
45
45
  input_array << provided
46
+ elsif options && options[:jobname]
47
+ input_array << id
46
48
  else
47
49
  input_array << value
48
50
  end
@@ -53,17 +55,18 @@ module Task
53
55
  [input_array, non_default_inputs]
54
56
  end
55
57
 
56
- def process_inputs(provided_inputs = {})
57
- input_array, non_default_inputs = assign_inputs provided_inputs
58
+ def process_inputs(provided_inputs = {}, id = nil)
59
+ input_array, non_default_inputs = assign_inputs provided_inputs, id
58
60
  digest_str = Misc.digest_str(input_array)
59
61
  [input_array, non_default_inputs, digest_str]
60
62
  end
61
63
 
62
64
  def save_file_input(orig_file, directory)
65
+ orig_file = orig_file.path if Step === orig_file
63
66
  basename = File.basename(orig_file)
64
67
  digest = Misc.digest(orig_file)
65
68
  if basename.include? '.'
66
- basename.sub!(/(.*)\.(.*)/, "\1-#{digest}.\2")
69
+ basename.sub!(/(.*)\.(.*)/, '\1-' + digest + '.\2')
67
70
  else
68
71
  basename += "-#{digest}"
69
72
  end
@@ -74,35 +77,51 @@ module Task
74
77
  end
75
78
 
76
79
  def save_inputs(directory, provided_inputs = {})
77
- input_array, non_default_inputs = assign_inputs(provided_inputs)
78
- self.inputs.each_with_index do |p,i|
80
+ #input_array, non_default_inputs = assign_inputs(provided_inputs)
81
+ self.recursive_inputs.each_with_index do |p,i|
79
82
  name, type, desc, value, options = p
80
- next unless non_default_inputs.include?(name)
83
+ next unless provided_inputs.include?(name)
84
+ value = provided_inputs[name]
81
85
  input_file = File.join(directory, name.to_s)
82
86
 
83
- if type == :file
84
- relative_file = save_file_input(input_array[i], directory)
85
- Persist.save(relative_file, input_file, type)
87
+ if Path.is_filename?(value)
88
+ relative_file = save_file_input(value, directory)
89
+ Open.write(input_file + ".as_file", relative_file)
90
+ elsif type == :file
91
+ relative_file = save_file_input(value, directory)
92
+ Persist.save(relative_file, input_file, :file)
86
93
  elsif type == :file_array
87
- new_files = input_array[i].collect do |orig_file|
94
+ new_files = value.collect do |orig_file|
88
95
  save_file_input(orig_file, directory)
89
96
  end
90
97
  Persist.save(new_files, input_file, type)
98
+ elsif Open.is_stream?(value)
99
+ Persist.save(value, input_file, type)
100
+ elsif Open.has_stream?(value)
101
+ Persist.save(value.stream, input_file, type)
91
102
  else
92
- Persist.save(input_array[i], input_file, type)
103
+ Persist.save(value, input_file, type)
93
104
  end
94
105
  end
95
106
  end
96
107
 
97
108
  def load_inputs(directory)
98
- self.inputs.collect do |p|
109
+ inputs = IndiferentHash.setup({})
110
+ self.recursive_inputs.each do |p|
99
111
  name, type, desc, value, options = p
100
112
  filename = File.join(directory, name.to_s)
101
113
  if Open.exists?(filename) || filename = Dir.glob(File.join(filename + ".*")).first
102
- Persist.load(filename, type)
103
- else
104
- value
114
+ if filename.end_with?('.as_file')
115
+ value = Open.read(filename).strip
116
+ value.sub!(/^\./, File.dirname(filename)) if value.start_with?("./")
117
+ inputs[name] = value
118
+ elsif (options && (options[:noload] || options[:stream] || options[:nofile]))
119
+ inputs[name] = filename
120
+ else
121
+ inputs[name] = Persist.load(filename, type)
122
+ end
105
123
  end
106
124
  end
125
+ inputs
107
126
  end
108
127
  end
@@ -2,6 +2,7 @@ require_relative '../meta_extension'
2
2
  require_relative '../named_array'
3
3
  require_relative 'step'
4
4
  require_relative 'task/inputs'
5
+ require_relative 'task/dependencies'
5
6
 
6
7
  module Task
7
8
  extend MetaExtension
@@ -38,123 +39,23 @@ module Task
38
39
  binding.instance_exec(*inputs, &self)
39
40
  end
40
41
 
41
- def dependencies(id, provided_inputs, non_default_inputs = [])
42
- return [] if deps.nil?
43
- dependencies = []
44
-
45
- provided_inputs ||= {}
46
-
47
- # Helper function
48
- load_dep = proc do |id, workflow, task, step_options, definition_options, dependencies|
49
- task = step_options.delete(:task) if step_options.include?(:task)
50
- workflow = step_options.delete(:workflow) if step_options.include?(:workflow)
51
- id = step_options.delete(:id) if step_options.include?(:id)
52
- id = step_options.delete(:jobname) if step_options.include?(:jobname)
53
-
54
- step_inputs = step_options.include?(:inputs)? step_options.delete(:inputs) : step_options
55
- step_inputs = IndiferentHash.add_defaults step_inputs, definition_options
56
-
57
- resolved_inputs = {}
58
- step_inputs.each do |k,v|
59
- if Symbol === v
60
- input_dep = dependencies.select{|d| d.task_name == v }.first
61
- resolved_inputs[k] = input_dep || step_inputs[v] || k
62
- else
63
- resolved_inputs[k] = v
64
- end
65
- end
66
- [workflow.job(task, id, resolved_inputs), step_inputs]
67
- end
68
-
69
- # Helper function
70
- find_dep_non_default_inputs = proc do |dep,definition_options,step_inputs={}|
71
- dep_non_default_inputs = dep.non_default_inputs
72
- dep_non_default_inputs.select do |name|
73
- step_inputs.include?(name)
74
- end
75
- dep_non_default_inputs.reject! do |name|
76
- definition_options.include?(name) &&
77
- (definition_options[name] != :placeholder || definition_options[name] != dep.inputs[name])
78
- end
79
-
80
- dep_non_default_inputs
81
- end
82
-
83
- deps.each do |workflow,task,definition_options,block=nil|
84
- definition_options[:id] = definition_options.delete(:jobname) if definition_options.include?(:jobname)
85
-
86
- if provided_inputs.include?(overriden = [workflow.name, task] * "#")
87
- dep = provided_inputs[overriden]
88
- dep = Step.new dep unless Step === dep
89
- dep.type = workflow.tasks[task].type
90
- dependencies << dep
91
- non_default_inputs << overriden
92
- next
93
- end
94
-
95
- definition_options ||= {}
96
-
97
- if block
98
- fixed_provided_inputs = self.assign_inputs(provided_inputs).first.to_hash
99
- self.inputs.each do |name,type,desc,value|
100
- fixed_provided_inputs[name] = value unless fixed_provided_inputs.include?(name)
101
- end
102
- fixed_provided_inputs = IndiferentHash.add_defaults fixed_provided_inputs, provided_inputs
103
- block_options = IndiferentHash.add_defaults definition_options.dup, fixed_provided_inputs
104
-
105
- res = block.call id, block_options, dependencies
106
-
107
- case res
108
- when Step
109
- dep = res
110
- dependencies << dep
111
- dep_non_default_inputs = find_dep_non_default_inputs.call(dep, block_options)
112
- non_default_inputs.concat(dep_non_default_inputs)
113
- when Hash
114
- step_options = block_options.merge(res)
115
- dep, step_inputs = load_dep.call(id, workflow, task, step_options, block_options, dependencies)
116
- dependencies << dep
117
- dep_non_default_inputs = find_dep_non_default_inputs.call(dep, definition_options, step_inputs)
118
- non_default_inputs.concat(dep_non_default_inputs)
119
- when Array
120
- res.each do |_res|
121
- if Hash === _res
122
- step_options = block_options.merge(_res)
123
- dep, step_inputs = load_dep.call(id, workflow, task, step_options, block_options, dependencies)
124
- dependencies << dep
125
- dep_non_default_inputs = find_dep_non_default_inputs.call(dep, definition_options, step_inputs)
126
- non_default_inputs.concat(dep_non_default_inputs)
127
- else
128
- dep = _res
129
- dependencies << dep
130
- dep_non_default_inputs = find_dep_non_default_inputs.call(dep, block_options)
131
- non_default_inputs.concat(dep_non_default_inputs)
132
- end
133
- end
134
- end
135
- else
136
- step_options = IndiferentHash.add_defaults definition_options.dup, provided_inputs
137
- dep, step_inputs = load_dep.call(id, workflow, task, step_options, definition_options, dependencies)
138
- dependencies << dep
139
- dep_non_default_inputs = find_dep_non_default_inputs.call(dep, definition_options, step_inputs)
140
- non_default_inputs.concat(dep_non_default_inputs)
141
- end
142
- end
143
-
144
- dependencies
145
- end
146
-
147
42
  def job(id = DEFAULT_NAME, provided_inputs = nil )
148
43
  provided_inputs, id = id, DEFAULT_NAME if (provided_inputs.nil? || provided_inputs.empty?) && (Hash === id || Array === id)
149
44
  provided_inputs = {} if provided_inputs.nil?
45
+ IndiferentHash.setup(provided_inputs)
150
46
  id = DEFAULT_NAME if id.nil?
151
47
 
152
- inputs, non_default_inputs, input_digest_str = process_inputs provided_inputs
48
+ provided_inputs = load_inputs(provided_inputs[:load_inputs]) if Hash === provided_inputs && provided_inputs[:load_inputs]
153
49
 
154
- dependencies = dependencies(id, provided_inputs, non_default_inputs)
50
+ inputs, non_default_inputs, input_digest_str = process_inputs provided_inputs, id
51
+
52
+ compute = {}
53
+ dependencies = dependencies(id, provided_inputs, non_default_inputs, compute)
155
54
 
156
55
  non_default_inputs.concat provided_inputs.keys.select{|k| String === k && k.include?("#") } if Hash === provided_inputs
157
56
 
57
+ non_default_inputs.uniq!
58
+
158
59
  if non_default_inputs.any?
159
60
  hash = Misc.digest(:inputs => input_digest_str, :dependencies => dependencies)
160
61
  name = [id, hash] * "_"
@@ -178,6 +79,7 @@ module Task
178
79
  end
179
80
  end
180
81
 
82
+
181
83
  path = directory[name]
182
84
 
183
85
  path = path.set_extension(extension) if extension
@@ -189,7 +91,8 @@ module Task
189
91
  Log.debug "ID #{self.name} #{id} - Clean"
190
92
  end
191
93
  NamedArray.setup(inputs, @inputs.collect{|i| i[0] }) if @inputs
192
- Step.new path.find, inputs, dependencies, id, non_default_inputs, &self
94
+ step_provided_inputs = Hash === provided_inputs ? provided_inputs.slice(*non_default_inputs) : provided_inputs
95
+ Step.new path.find, inputs, dependencies, id, non_default_inputs, step_provided_inputs, compute, &self
193
96
  end
194
97
  end
195
98
  end