scout-gear 8.0.0 → 8.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +26 -9
  3. data/Rakefile +6 -1
  4. data/VERSION +1 -1
  5. data/bin/scout +15 -4
  6. data/doc/lib/scout/path.md +35 -0
  7. data/doc/lib/scout/workflow/task.md +13 -0
  8. data/lib/scout/cmd.rb +23 -24
  9. data/lib/scout/concurrent_stream.rb +36 -19
  10. data/lib/scout/exceptions.rb +10 -0
  11. data/lib/scout/log/color.rb +11 -11
  12. data/lib/scout/log/progress/report.rb +7 -5
  13. data/lib/scout/log/progress/util.rb +3 -0
  14. data/lib/scout/log/trap.rb +3 -3
  15. data/lib/scout/log.rb +64 -36
  16. data/lib/scout/meta_extension.rb +34 -0
  17. data/lib/scout/misc/digest.rb +11 -2
  18. data/lib/scout/misc/format.rb +12 -7
  19. data/lib/scout/misc/monitor.rb +11 -0
  20. data/lib/scout/misc/system.rb +48 -0
  21. data/lib/scout/named_array.rb +8 -0
  22. data/lib/scout/offsite/ssh.rb +171 -0
  23. data/lib/scout/offsite/step.rb +83 -0
  24. data/lib/scout/offsite/sync.rb +55 -0
  25. data/lib/scout/offsite.rb +3 -0
  26. data/lib/scout/open/lock.rb +5 -24
  27. data/lib/scout/open/remote.rb +12 -1
  28. data/lib/scout/open/stream.rb +110 -122
  29. data/lib/scout/open/util.rb +9 -0
  30. data/lib/scout/open.rb +5 -4
  31. data/lib/scout/path/find.rb +15 -10
  32. data/lib/scout/path/util.rb +5 -0
  33. data/lib/scout/persist/serialize.rb +3 -3
  34. data/lib/scout/persist.rb +1 -1
  35. data/lib/scout/resource/path.rb +4 -0
  36. data/lib/scout/resource/util.rb +10 -4
  37. data/lib/scout/tsv/dumper.rb +2 -0
  38. data/lib/scout/tsv/index.rb +28 -86
  39. data/lib/scout/tsv/open.rb +35 -14
  40. data/lib/scout/tsv/parser.rb +9 -2
  41. data/lib/scout/tsv/persist/tokyocabinet.rb +2 -0
  42. data/lib/scout/tsv/stream.rb +204 -0
  43. data/lib/scout/tsv/transformer.rb +11 -0
  44. data/lib/scout/tsv.rb +9 -2
  45. data/lib/scout/work_queue/worker.rb +2 -2
  46. data/lib/scout/work_queue.rb +36 -12
  47. data/lib/scout/workflow/definition.rb +2 -1
  48. data/lib/scout/workflow/deployment/orchestrator.rb +245 -0
  49. data/lib/scout/workflow/deployment.rb +1 -0
  50. data/lib/scout/workflow/step/dependencies.rb +37 -11
  51. data/lib/scout/workflow/step/file.rb +5 -0
  52. data/lib/scout/workflow/step/info.rb +5 -3
  53. data/lib/scout/workflow/step/load.rb +1 -1
  54. data/lib/scout/workflow/step/provenance.rb +1 -0
  55. data/lib/scout/workflow/step/status.rb +6 -8
  56. data/lib/scout/workflow/step.rb +75 -30
  57. data/lib/scout/workflow/task/dependencies.rb +114 -0
  58. data/lib/scout/workflow/task/inputs.rb +27 -13
  59. data/lib/scout/workflow/task.rb +9 -108
  60. data/lib/scout/workflow/usage.rb +40 -12
  61. data/lib/scout/workflow.rb +4 -2
  62. data/lib/scout-gear.rb +2 -0
  63. data/lib/scout.rb +6 -0
  64. data/scout-gear.gemspec +32 -7
  65. data/scout_commands/doc +37 -0
  66. data/scout_commands/find +1 -0
  67. data/scout_commands/offsite +30 -0
  68. data/scout_commands/update +29 -0
  69. data/scout_commands/workflow/info +15 -3
  70. data/scout_commands/workflow/install +102 -0
  71. data/scout_commands/workflow/task +26 -5
  72. data/test/scout/offsite/test_ssh.rb +15 -0
  73. data/test/scout/offsite/test_step.rb +33 -0
  74. data/test/scout/offsite/test_sync.rb +36 -0
  75. data/test/scout/offsite/test_task.rb +0 -0
  76. data/test/scout/resource/test_path.rb +6 -0
  77. data/test/scout/test_named_array.rb +6 -0
  78. data/test/scout/test_persist.rb +3 -2
  79. data/test/scout/test_tsv.rb +17 -0
  80. data/test/scout/test_work_queue.rb +63 -41
  81. data/test/scout/tsv/persist/test_adapter.rb +1 -1
  82. data/test/scout/tsv/test_index.rb +14 -0
  83. data/test/scout/tsv/test_parser.rb +14 -0
  84. data/test/scout/tsv/test_stream.rb +200 -0
  85. data/test/scout/tsv/test_transformer.rb +12 -0
  86. data/test/scout/workflow/deployment/test_orchestrator.rb +272 -0
  87. data/test/scout/workflow/step/test_dependencies.rb +68 -0
  88. data/test/scout/workflow/step/test_info.rb +18 -0
  89. data/test/scout/workflow/step/test_status.rb +0 -1
  90. data/test/scout/workflow/task/test_dependencies.rb +355 -0
  91. data/test/scout/workflow/task/test_inputs.rb +53 -0
  92. data/test/scout/workflow/test_definition.rb +18 -0
  93. data/test/scout/workflow/test_documentation.rb +24 -0
  94. data/test/scout/workflow/test_step.rb +109 -0
  95. data/test/scout/workflow/test_task.rb +0 -287
  96. data/test/test_scout.rb +9 -0
  97. metadata +83 -5
  98. data/scout_commands/workflow/task_old +0 -706
@@ -11,13 +11,14 @@ require_relative 'step/progress'
11
11
 
12
12
  class Step
13
13
 
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)
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)
16
16
  @path = path
17
17
  @inputs = inputs
18
18
  @dependencies = dependencies
19
19
  @id = id
20
20
  @non_default_inputs = non_default_inputs
21
+ @compute = compute
21
22
  @task = task
22
23
  @mutex = Mutex.new
23
24
  @tee_copies = 1
@@ -42,7 +43,7 @@ class Step
42
43
  if Open.exists?(info_file)
43
44
  info[:dependencies].collect do |path|
44
45
  Step.load(path)
45
- end
46
+ end if info[:dependencies]
46
47
  else
47
48
  []
48
49
  end
@@ -92,7 +93,12 @@ class Step
92
93
  inputs = new_inputs
93
94
  end
94
95
 
95
- @result = self.instance_exec(*inputs, &task)
96
+ @result = begin
97
+ @in_exec = true
98
+ self.instance_exec(*inputs, &task)
99
+ ensure
100
+ @in_exec = false
101
+ end
96
102
  end
97
103
 
98
104
  def tmp_path
@@ -115,11 +121,10 @@ class Step
115
121
  Persist.persist(name, type, :path => path, :tee_copies => tee_copies) do
116
122
  clear_info
117
123
  merge_info :status => :start, :start => Time.now,
118
- :pid => Process.pid, :pid_hostname => ENV["HOSTNAME"],
119
- :inputs => inputs, :type => type,
124
+ :pid => Process.pid, :pid_hostname => Misc.hostname,
125
+ :inputs => MetaExtension.purge(inputs), :type => type,
120
126
  :dependencies => dependencies.collect{|d| d.path }
121
127
 
122
-
123
128
  @result = exec
124
129
 
125
130
  if @result.nil? && File.exist?(self.tmp_path) && ! File.exist?(self.path)
@@ -129,6 +134,13 @@ class Step
129
134
  end
130
135
 
131
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
132
144
  end
133
145
  rescue Exception => e
134
146
  merge_info :status => :error, :exception => e, :end => Time.now
@@ -142,10 +154,14 @@ class Step
142
154
  end
143
155
 
144
156
  @result.abort_callback = proc do |exception|
145
- if Aborted === exception || Interrupt === exception
157
+ if exception.nil? || Aborted === exception || Interrupt === exception
146
158
  merge_info :status => :aborted, :end => Time.now
147
159
  else
148
- 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
149
165
  end
150
166
  end
151
167
 
@@ -155,18 +171,16 @@ class Step
155
171
  end
156
172
  end
157
173
  end
174
+ end
158
175
 
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
176
+ def fork
177
+ Process.fork do
178
+ clear_info unless present?
179
+ run(false)
180
+ join
169
181
  end
182
+ grace
183
+ self
170
184
  end
171
185
 
172
186
  def done?
@@ -185,16 +199,21 @@ class Step
185
199
  else
186
200
  Log.debug "Taking result #{Log.fingerprint @result}"
187
201
  end
202
+
188
203
  @take_stream, @result = @result, @result.next
189
- @take_stream
190
- 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
191
214
  Open.open(self.path)
192
215
  else
193
- if running?
194
- nil
195
- else
196
- exec
197
- end
216
+ exec
198
217
  end
199
218
  end
200
219
  end
@@ -207,21 +226,47 @@ class Step
207
226
  threads.each do |t|
208
227
  begin
209
228
  t.join
210
- rescue
229
+ rescue Exception
211
230
  threads.each{|t| t.raise(Aborted); t.join }
212
231
  raise $!
213
232
  end
214
233
  end
215
234
  end
216
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
+
217
252
  def join
218
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?
219
259
  self
220
260
  end
221
261
 
222
- def produce
223
- run
224
- 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
225
270
  end
226
271
 
227
272
  def load
@@ -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
@@ -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
@@ -63,7 +63,7 @@ module Task
63
63
  basename = File.basename(orig_file)
64
64
  digest = Misc.digest(orig_file)
65
65
  if basename.include? '.'
66
- basename.sub!(/(.*)\.(.*)/, "\1-#{digest}.\2")
66
+ basename.sub!(/(.*)\.(.*)/, '\1-' + digest + '.\2')
67
67
  else
68
68
  basename += "-#{digest}"
69
69
  end
@@ -74,35 +74,49 @@ module Task
74
74
  end
75
75
 
76
76
  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|
77
+ #input_array, non_default_inputs = assign_inputs(provided_inputs)
78
+ self.recursive_inputs.each_with_index do |p,i|
79
79
  name, type, desc, value, options = p
80
- next unless non_default_inputs.include?(name)
80
+ next unless provided_inputs.include?(name)
81
+ value = provided_inputs[name]
81
82
  input_file = File.join(directory, name.to_s)
82
83
 
83
84
  if type == :file
84
- relative_file = save_file_input(input_array[i], directory)
85
- Persist.save(relative_file, input_file, type)
85
+ relative_file = save_file_input(value, directory)
86
+ Persist.save(relative_file, input_file, :file)
86
87
  elsif type == :file_array
87
- new_files = input_array[i].collect do |orig_file|
88
+ new_files = value.collect do |orig_file|
88
89
  save_file_input(orig_file, directory)
89
90
  end
90
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)
91
99
  else
92
- Persist.save(input_array[i], input_file, type)
100
+ Persist.save(value, input_file, type)
93
101
  end
94
102
  end
95
103
  end
96
104
 
97
105
  def load_inputs(directory)
98
- self.inputs.collect do |p|
106
+ inputs = IndiferentHash.setup({})
107
+ self.recursive_inputs.each do |p|
99
108
  name, type, desc, value, options = p
100
109
  filename = File.join(directory, name.to_s)
101
110
  if Open.exists?(filename) || filename = Dir.glob(File.join(filename + ".*")).first
102
- Persist.load(filename, type)
103
- else
104
- 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
105
118
  end
106
119
  end
120
+ inputs
107
121
  end
108
122
  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,22 @@ 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?
150
45
  id = DEFAULT_NAME if id.nil?
151
46
 
47
+ provided_inputs = load_inputs(provided_inputs[:load_inputs]) if Hash === provided_inputs && provided_inputs[:load_inputs]
48
+
152
49
  inputs, non_default_inputs, input_digest_str = process_inputs provided_inputs
153
50
 
154
- dependencies = dependencies(id, provided_inputs, non_default_inputs)
51
+ compute = {}
52
+ dependencies = dependencies(id, provided_inputs, non_default_inputs, compute)
155
53
 
156
54
  non_default_inputs.concat provided_inputs.keys.select{|k| String === k && k.include?("#") } if Hash === provided_inputs
157
55
 
56
+ non_default_inputs.uniq!
57
+
158
58
  if non_default_inputs.any?
159
59
  hash = Misc.digest(:inputs => input_digest_str, :dependencies => dependencies)
160
60
  name = [id, hash] * "_"
@@ -178,6 +78,7 @@ module Task
178
78
  end
179
79
  end
180
80
 
81
+
181
82
  path = directory[name]
182
83
 
183
84
  path = path.set_extension(extension) if extension
@@ -189,7 +90,7 @@ module Task
189
90
  Log.debug "ID #{self.name} #{id} - Clean"
190
91
  end
191
92
  NamedArray.setup(inputs, @inputs.collect{|i| i[0] }) if @inputs
192
- Step.new path.find, inputs, dependencies, id, non_default_inputs, &self
93
+ Step.new path.find, inputs, dependencies, id, non_default_inputs, compute, &self
193
94
  end
194
95
  end
195
96
  end
@@ -3,10 +3,31 @@ require 'scout/simple_opt'
3
3
  module Task
4
4
  def usage(workflow = nil, deps = nil)
5
5
  str = StringIO.new
6
- str.puts Log.color(:yellow, name)
7
- str.puts Log.color(:yellow, "-" * name.length)
8
- str.puts "\n" << Misc.format_paragraph(description.strip) << "\n" if description and not description.empty?
9
- str.puts
6
+
7
+ if description
8
+ title, paragraph = description.split("\n\n")
9
+ if title.length < Misc::MAX_TTY_LINE_WIDTH
10
+ title = self.name.to_s + " - " + title
11
+ str.puts Log.color :yellow, title
12
+ str.puts Log.color :yellow, "-" * title.length
13
+ if paragraph
14
+ str.puts "\n" << Misc.format_paragraph(paragraph)
15
+ end
16
+ str.puts
17
+ else
18
+ title = self.name.to_s
19
+ str.puts Log.color :yellow, title
20
+ str.puts Log.color :yellow, "-" * title.length
21
+ str.puts "\n" << Misc.format_paragraph(description)
22
+ str.puts
23
+ end
24
+ else
25
+ title = self.name.to_s
26
+ str.puts Log.color :yellow, title
27
+ str.puts Log.color :yellow, "-" * title.length
28
+ str.puts
29
+ end
30
+
10
31
 
11
32
  selects = []
12
33
  if inputs && inputs.any?
@@ -103,9 +124,16 @@ module Task
103
124
  sopt_options * ":"
104
125
  end
105
126
 
106
- def get_SOPT(task)
127
+ def get_SOPT
107
128
  sopt_option_string = self.SOPT_str
108
- SOPT.get sopt_option_string
129
+ job_options = SOPT.get sopt_option_string
130
+ recursive_inputs.uniq.each do |name,type|
131
+ next unless type.to_s.include?('array')
132
+ if job_options.include?(name) && (! Open.exist?(job_options[name]) || type.to_s.include?('file') || type.to_s.include?('path'))
133
+ job_options[name] = job_options[name].split(",")
134
+ end
135
+ end
136
+ job_options
109
137
  end
110
138
  end
111
139
 
@@ -219,15 +247,15 @@ module Workflow
219
247
  str.puts Log.color :magenta, "=" * self.name.length
220
248
  end
221
249
 
222
- if self.documentation[:description] and not self.documentation[:description].empty?
223
- str.puts
224
- str.puts Misc.format_paragraph self.documentation[:description]
225
- str.puts
226
- end
227
-
250
+ str.puts
228
251
 
229
252
  if task.nil?
230
253
 
254
+ if self.documentation[:description] and not self.documentation[:description].empty?
255
+ str.puts Misc.format_paragraph self.documentation[:description]
256
+ str.puts
257
+ end
258
+
231
259
  str.puts Log.color :magenta, "## TASKS"
232
260
  if self.documentation[:task_description] and not self.documentation[:task_description].empty?
233
261
  str.puts
@@ -4,13 +4,14 @@ require_relative 'workflow/task'
4
4
  require_relative 'workflow/step'
5
5
  require_relative 'workflow/documentation'
6
6
  require_relative 'workflow/usage'
7
+ require_relative 'workflow/deployment'
7
8
 
8
9
  require_relative 'resource'
9
10
  require_relative 'resource/scout'
10
11
 
11
12
  module Workflow
12
13
  class << self
13
- attr_accessor :workflows
14
+ attr_accessor :workflows, :main
14
15
  def workflows
15
16
  @workflows ||= []
16
17
  end
@@ -30,13 +31,14 @@ module Workflow
30
31
  workflow = Path.setup('workflows')[Misc.snake_case(workflow_name)]["workflow.rb"] unless Open.exists?(workflow)
31
32
  workflow = Path.setup('workflows')[Misc.camel_case(workflow_name)]["workflow.rb"] unless Open.exists?(workflow)
32
33
  if Open.exists?(workflow)
34
+ self.main = nil
33
35
  workflow = workflow.find if Path === workflow
34
36
  $LOAD_PATH.unshift(File.join(File.dirname(workflow), 'lib'))
35
37
  load workflow
36
38
  else
37
39
  raise "Workflow #{workflow_name} not found"
38
40
  end
39
- workflows.last
41
+ self.main || workflows.last
40
42
  end
41
43
 
42
44
  def job(name, *args)
data/lib/scout-gear.rb CHANGED
@@ -8,3 +8,5 @@ require_relative 'scout/resource'
8
8
  require_relative 'scout/resource/scout'
9
9
  require_relative 'scout/persist'
10
10
  require_relative 'scout/tsv'
11
+ require_relative 'scout/config'
12
+ require_relative 'scout/offsite'
data/lib/scout.rb CHANGED
@@ -1,2 +1,8 @@
1
1
  require 'workflow-scout'
2
2
  require 'rbbt-scout'
3
+
4
+ module Scout
5
+ def self.version
6
+ Open.read(File.join(__dir__, '../VERSION'))
7
+ end
8
+ end