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.
- checksums.yaml +4 -4
- data/.vimproject +26 -9
- data/Rakefile +6 -1
- data/VERSION +1 -1
- data/bin/scout +15 -4
- data/doc/lib/scout/path.md +35 -0
- data/doc/lib/scout/workflow/task.md +13 -0
- data/lib/scout/cmd.rb +23 -24
- data/lib/scout/concurrent_stream.rb +36 -19
- data/lib/scout/exceptions.rb +10 -0
- data/lib/scout/log/color.rb +11 -11
- data/lib/scout/log/progress/report.rb +7 -5
- data/lib/scout/log/progress/util.rb +3 -0
- data/lib/scout/log/trap.rb +3 -3
- data/lib/scout/log.rb +64 -36
- data/lib/scout/meta_extension.rb +34 -0
- data/lib/scout/misc/digest.rb +11 -2
- data/lib/scout/misc/format.rb +12 -7
- data/lib/scout/misc/monitor.rb +11 -0
- data/lib/scout/misc/system.rb +48 -0
- data/lib/scout/named_array.rb +8 -0
- data/lib/scout/offsite/ssh.rb +171 -0
- data/lib/scout/offsite/step.rb +83 -0
- data/lib/scout/offsite/sync.rb +55 -0
- data/lib/scout/offsite.rb +3 -0
- data/lib/scout/open/lock.rb +5 -24
- data/lib/scout/open/remote.rb +12 -1
- data/lib/scout/open/stream.rb +110 -122
- data/lib/scout/open/util.rb +9 -0
- data/lib/scout/open.rb +5 -4
- data/lib/scout/path/find.rb +15 -10
- data/lib/scout/path/util.rb +5 -0
- data/lib/scout/persist/serialize.rb +3 -3
- data/lib/scout/persist.rb +1 -1
- data/lib/scout/resource/path.rb +4 -0
- data/lib/scout/resource/util.rb +10 -4
- data/lib/scout/tsv/dumper.rb +2 -0
- data/lib/scout/tsv/index.rb +28 -86
- data/lib/scout/tsv/open.rb +35 -14
- data/lib/scout/tsv/parser.rb +9 -2
- data/lib/scout/tsv/persist/tokyocabinet.rb +2 -0
- data/lib/scout/tsv/stream.rb +204 -0
- data/lib/scout/tsv/transformer.rb +11 -0
- data/lib/scout/tsv.rb +9 -2
- data/lib/scout/work_queue/worker.rb +2 -2
- data/lib/scout/work_queue.rb +36 -12
- data/lib/scout/workflow/definition.rb +2 -1
- data/lib/scout/workflow/deployment/orchestrator.rb +245 -0
- data/lib/scout/workflow/deployment.rb +1 -0
- data/lib/scout/workflow/step/dependencies.rb +37 -11
- data/lib/scout/workflow/step/file.rb +5 -0
- data/lib/scout/workflow/step/info.rb +5 -3
- data/lib/scout/workflow/step/load.rb +1 -1
- data/lib/scout/workflow/step/provenance.rb +1 -0
- data/lib/scout/workflow/step/status.rb +6 -8
- data/lib/scout/workflow/step.rb +75 -30
- data/lib/scout/workflow/task/dependencies.rb +114 -0
- data/lib/scout/workflow/task/inputs.rb +27 -13
- data/lib/scout/workflow/task.rb +9 -108
- data/lib/scout/workflow/usage.rb +40 -12
- data/lib/scout/workflow.rb +4 -2
- data/lib/scout-gear.rb +2 -0
- data/lib/scout.rb +6 -0
- data/scout-gear.gemspec +32 -7
- data/scout_commands/doc +37 -0
- data/scout_commands/find +1 -0
- data/scout_commands/offsite +30 -0
- data/scout_commands/update +29 -0
- data/scout_commands/workflow/info +15 -3
- data/scout_commands/workflow/install +102 -0
- data/scout_commands/workflow/task +26 -5
- data/test/scout/offsite/test_ssh.rb +15 -0
- data/test/scout/offsite/test_step.rb +33 -0
- data/test/scout/offsite/test_sync.rb +36 -0
- data/test/scout/offsite/test_task.rb +0 -0
- data/test/scout/resource/test_path.rb +6 -0
- data/test/scout/test_named_array.rb +6 -0
- data/test/scout/test_persist.rb +3 -2
- data/test/scout/test_tsv.rb +17 -0
- data/test/scout/test_work_queue.rb +63 -41
- data/test/scout/tsv/persist/test_adapter.rb +1 -1
- data/test/scout/tsv/test_index.rb +14 -0
- data/test/scout/tsv/test_parser.rb +14 -0
- data/test/scout/tsv/test_stream.rb +200 -0
- data/test/scout/tsv/test_transformer.rb +12 -0
- data/test/scout/workflow/deployment/test_orchestrator.rb +272 -0
- data/test/scout/workflow/step/test_dependencies.rb +68 -0
- data/test/scout/workflow/step/test_info.rb +18 -0
- data/test/scout/workflow/step/test_status.rb +0 -1
- data/test/scout/workflow/task/test_dependencies.rb +355 -0
- data/test/scout/workflow/task/test_inputs.rb +53 -0
- data/test/scout/workflow/test_definition.rb +18 -0
- data/test/scout/workflow/test_documentation.rb +24 -0
- data/test/scout/workflow/test_step.rb +109 -0
- data/test/scout/workflow/test_task.rb +0 -287
- data/test/test_scout.rb +9 -0
- metadata +83 -5
- data/scout_commands/workflow/task_old +0 -706
data/lib/scout/workflow/step.rb
CHANGED
@@ -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 =
|
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 =>
|
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
|
-
|
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
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
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
|
-
|
190
|
-
|
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
|
-
|
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
|
-
|
224
|
-
|
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
|
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!(/(.*)\.(.*)/,
|
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.
|
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
|
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(
|
85
|
-
Persist.save(relative_file, input_file,
|
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 =
|
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(
|
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
|
-
|
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
|
-
|
103
|
-
|
104
|
-
|
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
|
data/lib/scout/workflow/task.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/scout/workflow/usage.rb
CHANGED
@@ -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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
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
|
-
|
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
|
data/lib/scout/workflow.rb
CHANGED
@@ -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