scout-gear 8.0.0 → 8.1.0

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 (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