scout-gear 7.3.0 → 8.1.0

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