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.
- checksums.yaml +4 -4
- data/.vimproject +44 -16
- data/Rakefile +6 -1
- data/VERSION +1 -1
- data/bin/scout +21 -7
- data/doc/lib/scout/path.md +35 -0
- data/doc/lib/scout/workflow/task.md +13 -0
- data/lib/rbbt-scout.rb +1 -0
- data/lib/scout/cmd.rb +24 -25
- data/lib/scout/concurrent_stream.rb +59 -39
- data/lib/scout/config.rb +1 -1
- data/lib/scout/exceptions.rb +10 -0
- data/lib/scout/log/color.rb +15 -12
- data/lib/scout/log/progress/report.rb +8 -6
- data/lib/scout/log/progress/util.rb +61 -54
- data/lib/scout/log/progress.rb +1 -1
- data/lib/scout/log/trap.rb +107 -0
- data/lib/scout/log.rb +115 -52
- data/lib/scout/meta_extension.rb +47 -6
- data/lib/scout/misc/digest.rb +12 -3
- data/lib/scout/misc/format.rb +24 -7
- data/lib/scout/misc/insist.rb +1 -1
- data/lib/scout/misc/monitor.rb +22 -0
- data/lib/scout/misc/system.rb +58 -0
- data/lib/scout/named_array.rb +73 -3
- 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/lockfile.rb +587 -0
- data/lib/scout/open/lock.rb +9 -2
- data/lib/scout/open/remote.rb +16 -1
- data/lib/scout/open/stream.rb +146 -83
- data/lib/scout/open/util.rb +22 -3
- data/lib/scout/open.rb +5 -4
- data/lib/scout/path/find.rb +24 -11
- data/lib/scout/path/util.rb +40 -0
- data/lib/scout/persist/serialize.rb +19 -6
- data/lib/scout/persist.rb +29 -13
- data/lib/scout/resource/path.rb +57 -0
- data/lib/scout/resource/produce.rb +0 -8
- data/lib/scout/resource/util.rb +12 -5
- data/lib/scout/tmpfile.rb +7 -8
- data/lib/scout/tsv/attach.rb +177 -0
- data/lib/scout/tsv/change_id.rb +40 -0
- data/lib/scout/tsv/dumper.rb +74 -46
- data/lib/scout/tsv/index.rb +85 -87
- data/lib/scout/tsv/open.rb +160 -85
- data/lib/scout/tsv/parser.rb +142 -80
- data/lib/scout/tsv/path.rb +1 -2
- data/lib/scout/tsv/persist/adapter.rb +15 -45
- data/lib/scout/tsv/persist/fix_width_table.rb +3 -0
- data/lib/scout/tsv/persist/tokyocabinet.rb +6 -1
- data/lib/scout/tsv/persist.rb +4 -0
- data/lib/scout/tsv/stream.rb +204 -0
- data/lib/scout/tsv/transformer.rb +152 -0
- data/lib/scout/tsv/traverse.rb +96 -92
- data/lib/scout/tsv/util/filter.rb +9 -0
- data/lib/scout/tsv/util/reorder.rb +81 -0
- data/lib/scout/tsv/util/select.rb +78 -33
- data/lib/scout/tsv/util/unzip.rb +86 -0
- data/lib/scout/tsv/util.rb +60 -11
- data/lib/scout/tsv.rb +34 -4
- data/lib/scout/work_queue/socket.rb +6 -1
- data/lib/scout/work_queue/worker.rb +5 -2
- data/lib/scout/work_queue.rb +51 -20
- data/lib/scout/workflow/definition.rb +23 -3
- data/lib/scout/workflow/deployment/orchestrator.rb +245 -0
- data/lib/scout/workflow/deployment.rb +1 -0
- data/lib/scout/workflow/step/dependencies.rb +56 -10
- data/lib/scout/workflow/step/file.rb +5 -0
- data/lib/scout/workflow/step/info.rb +40 -7
- data/lib/scout/workflow/step/load.rb +1 -1
- data/lib/scout/workflow/step/provenance.rb +9 -7
- data/lib/scout/workflow/step/status.rb +43 -0
- data/lib/scout/workflow/step.rb +160 -49
- data/lib/scout/workflow/task/dependencies.rb +114 -0
- data/lib/scout/workflow/task/inputs.rb +40 -32
- data/lib/scout/workflow/task.rb +38 -102
- data/lib/scout/workflow/usage.rb +48 -18
- data/lib/scout/workflow.rb +4 -2
- data/lib/scout-gear.rb +2 -0
- data/lib/scout.rb +6 -0
- data/scout-gear.gemspec +52 -23
- 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 +57 -9
- 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/open/test_stream.rb +60 -58
- data/test/scout/path/test_find.rb +10 -1
- data/test/scout/resource/test_path.rb +6 -0
- data/test/scout/resource/test_produce.rb +15 -0
- data/test/scout/test_meta_extension.rb +25 -0
- data/test/scout/test_named_array.rb +24 -0
- data/test/scout/test_persist.rb +9 -2
- data/test/scout/test_tsv.rb +229 -2
- data/test/scout/test_work_queue.rb +65 -41
- data/test/scout/tsv/persist/test_tokyocabinet.rb +29 -1
- data/test/scout/tsv/test_attach.rb +227 -0
- data/test/scout/tsv/test_change_id.rb +98 -0
- data/test/scout/tsv/test_dumper.rb +1 -1
- data/test/scout/tsv/test_index.rb +49 -3
- data/test/scout/tsv/test_open.rb +160 -2
- data/test/scout/tsv/test_parser.rb +33 -2
- data/test/scout/tsv/test_persist.rb +2 -0
- data/test/scout/tsv/test_stream.rb +200 -0
- data/test/scout/tsv/test_transformer.rb +120 -0
- data/test/scout/tsv/test_traverse.rb +88 -3
- data/test/scout/tsv/test_util.rb +1 -0
- data/test/scout/tsv/util/test_reorder.rb +94 -0
- data/test/scout/tsv/util/test_select.rb +25 -11
- data/test/scout/tsv/util/test_unzip.rb +112 -0
- data/test/scout/work_queue/test_socket.rb +0 -1
- 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 +30 -0
- data/test/scout/workflow/task/test_dependencies.rb +355 -0
- data/test/scout/workflow/task/test_inputs.rb +67 -14
- 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 +112 -3
- data/test/scout/workflow/test_task.rb +0 -151
- data/test/scout/workflow/test_usage.rb +33 -6
- data/test/test_scout.rb +9 -0
- metadata +100 -8
- data/scout_commands/workflow/task_old +0 -706
@@ -1,4 +1,70 @@
|
|
1
1
|
module TSV
|
2
|
+
def self.select(key, values, method, fields: nil, field: nil, invert: false, type: nil, sep: nil, &block)
|
3
|
+
return ! select(key, values, method, field: field, invert: false, type: type, sep: sep, &block) if invert
|
4
|
+
|
5
|
+
return yield(key, values) if method.nil? && block_given
|
6
|
+
|
7
|
+
if Hash === method
|
8
|
+
if method.include?(:invert)
|
9
|
+
method = method.dup
|
10
|
+
invert = method.delete(:invert)
|
11
|
+
return select(key, values, method, fields: fields, field: field, invert: invert, type: type, sep: sep, &block)
|
12
|
+
end
|
13
|
+
field = method.keys.first
|
14
|
+
value = method[field]
|
15
|
+
return select(key, values, value, fields: fields, field: field, invert: invert, type: type, sep: sep, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
if field
|
19
|
+
field = fields.index(field) if fields && String === field
|
20
|
+
set = field == :key ? [key] : (type == :double ? values[field].split(sep) : values[field])
|
21
|
+
else
|
22
|
+
set = [key, (type == :double ? values.collect{|v| v.split(sep) } : values)]
|
23
|
+
end
|
24
|
+
|
25
|
+
if Array === set
|
26
|
+
set.flatten!
|
27
|
+
else
|
28
|
+
set = [set]
|
29
|
+
end
|
30
|
+
|
31
|
+
case method
|
32
|
+
when Array
|
33
|
+
(method & set).any?
|
34
|
+
when Regexp
|
35
|
+
set.select{|v| v =~ method }.any?
|
36
|
+
when Symbol
|
37
|
+
set.first.send(method)
|
38
|
+
when Numeric
|
39
|
+
set.size > method
|
40
|
+
when String
|
41
|
+
if block_given?
|
42
|
+
field = method
|
43
|
+
field = fields.index?(field) if fields && String === field
|
44
|
+
case
|
45
|
+
when block.arity == 1
|
46
|
+
if (method == key_field or method == :key)
|
47
|
+
yield(key)
|
48
|
+
else
|
49
|
+
yield(values[method])
|
50
|
+
end
|
51
|
+
when block.arity == 2
|
52
|
+
if (method == key_field or method == :key)
|
53
|
+
yield(key, key)
|
54
|
+
else
|
55
|
+
yield(key, values[method])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
elsif m = method.match(/^([<>]=?)(.*)/)
|
59
|
+
set.select{|v| v.to_f.send($1, $2.to_f) }.any?
|
60
|
+
else
|
61
|
+
set.select{|v| v == method }.any?
|
62
|
+
end
|
63
|
+
when Proc
|
64
|
+
set.select{|v| method.call(v) }.any?
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
2
68
|
def select(method = nil, invert = false, &block)
|
3
69
|
new = TSV.setup({}, :key_field => key_field, :fields => fields, :type => type, :filename => filename, :identifiers => identifiers)
|
4
70
|
|
@@ -33,7 +99,7 @@ module TSV
|
|
33
99
|
new[key] = values if invert ^ ([key,values].flatten.select{|v| v =~ method}.any?)
|
34
100
|
end
|
35
101
|
end
|
36
|
-
when (String === method || Symbol === method)
|
102
|
+
when ((String === method) || (Symbol === method))
|
37
103
|
if block_given?
|
38
104
|
case
|
39
105
|
when block.arity == 1
|
@@ -88,11 +154,11 @@ module TSV
|
|
88
154
|
key = method.keys.first
|
89
155
|
method = method.values.first
|
90
156
|
case
|
91
|
-
when (Array === method and (key == :key or key_field == key))
|
157
|
+
when ((Array === method) and (key == :key or key_field == key))
|
92
158
|
with_unnamed do
|
93
|
-
|
94
|
-
new[key] = self[key] if invert ^ (
|
95
|
-
|
159
|
+
keys.each do |key|
|
160
|
+
new[key] = self[key] if invert ^ (method.include? key)
|
161
|
+
end
|
96
162
|
end
|
97
163
|
when Array === method
|
98
164
|
with_unnamed do
|
@@ -125,7 +191,7 @@ module TSV
|
|
125
191
|
end
|
126
192
|
end
|
127
193
|
|
128
|
-
when (String === method and method =~ /name:(.*)/)
|
194
|
+
when ((String === method) and (method =~ /name:(.*)/))
|
129
195
|
name = $1
|
130
196
|
old_unnamed = self.unnamed
|
131
197
|
self.unnamed = false
|
@@ -187,34 +253,13 @@ module TSV
|
|
187
253
|
new
|
188
254
|
end
|
189
255
|
|
190
|
-
def
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
if merge == :concat
|
196
|
-
v.each_with_index do |new,i|
|
197
|
-
next if new.empty?
|
198
|
-
current[i].concat(new)
|
199
|
-
end
|
200
|
-
else
|
201
|
-
merged = []
|
202
|
-
v.each_with_index do |new,i|
|
203
|
-
next if new.empty?
|
204
|
-
merged[i] = current[i] + new
|
205
|
-
end
|
206
|
-
res[k] = merged
|
207
|
-
end
|
208
|
-
else
|
209
|
-
res[k] = v
|
256
|
+
def subset(keys)
|
257
|
+
new = self.annotate({})
|
258
|
+
self.with_unnamed do
|
259
|
+
keys.each do |k|
|
260
|
+
new[k] = self[k] if self.include?(k)
|
210
261
|
end
|
211
262
|
end
|
212
|
-
|
213
|
-
res.fields = field_names
|
214
|
-
res
|
215
|
-
end
|
216
|
-
|
217
|
-
def slice(fields)
|
218
|
-
reorder :key, fields
|
263
|
+
new
|
219
264
|
end
|
220
265
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module TSV
|
2
|
+
|
3
|
+
def self.unzip(source, field, target: nil, sep: ":", delete: true, type: :list, merge: false, one2one: true, bar: nil)
|
4
|
+
source = TSV::Parser.new source if String === source
|
5
|
+
|
6
|
+
field_pos = source.identify_field(field)
|
7
|
+
new_fields = source.fields.dup
|
8
|
+
field_name = new_fields[field_pos]
|
9
|
+
new_fields.delete_at(field_pos) if delete
|
10
|
+
new_key_field = [source.key_field, field_name] * sep
|
11
|
+
type = :double if merge
|
12
|
+
|
13
|
+
stream = target == :stream
|
14
|
+
|
15
|
+
target = case target
|
16
|
+
when :stream
|
17
|
+
TSV::Dumper.new(source.options.merge(sep: "\t"))
|
18
|
+
when nil
|
19
|
+
TSV.setup({})
|
20
|
+
else
|
21
|
+
target
|
22
|
+
end
|
23
|
+
|
24
|
+
target.fields = new_fields
|
25
|
+
target.key_field = new_key_field
|
26
|
+
target.type = type
|
27
|
+
|
28
|
+
transformer = TSV::Transformer.new source, target, unnamed: true
|
29
|
+
|
30
|
+
bar = "Unzip #{new_key_field}" if TrueClass === bar
|
31
|
+
|
32
|
+
transformer.traverse unnamed: true, one2one: one2one, bar: bar do |k,v|
|
33
|
+
if source.type == :double
|
34
|
+
if one2one
|
35
|
+
res = NamedArray.zip_fields(v).collect do |_v|
|
36
|
+
field_value = _v[field_pos]
|
37
|
+
|
38
|
+
if delete
|
39
|
+
new_values = _v.dup
|
40
|
+
new_values.delete_at field_pos
|
41
|
+
else
|
42
|
+
new_values = _v
|
43
|
+
end
|
44
|
+
|
45
|
+
new_key = [k,field_value] * sep
|
46
|
+
new_values = new_values.collect{|e| [e] } if transformer.type == :double
|
47
|
+
[new_key, new_values]
|
48
|
+
end
|
49
|
+
else
|
50
|
+
all_values = v.collect{|e| e.dup }
|
51
|
+
all_values.delete_at field_pos if delete
|
52
|
+
res = NamedArray.zip_fields(v).collect do |_v|
|
53
|
+
field_value = _v[field_pos]
|
54
|
+
|
55
|
+
new_key = [k,field_value] * sep
|
56
|
+
new_values = all_values if transformer.type == :double
|
57
|
+
[new_key, new_values]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
MultipleResult.setup(res)
|
62
|
+
else
|
63
|
+
field_value = v[field_pos]
|
64
|
+
|
65
|
+
if delete
|
66
|
+
new_values = v.dup
|
67
|
+
new_values.delete_at field_pos
|
68
|
+
else
|
69
|
+
new_values = v
|
70
|
+
end
|
71
|
+
|
72
|
+
new_key = [k,field_value] * sep
|
73
|
+
|
74
|
+
new_values = new_values.collect{|e| [e] } if transformer.type == :double
|
75
|
+
|
76
|
+
[new_key, new_values]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
stream ? transformer : transformer.tsv(merge: merge)
|
81
|
+
end
|
82
|
+
|
83
|
+
def unzip(*args, **kwargs)
|
84
|
+
TSV.unzip(self, *args, **kwargs)
|
85
|
+
end
|
86
|
+
end
|
data/lib/scout/tsv/util.rb
CHANGED
@@ -1,21 +1,57 @@
|
|
1
1
|
#require_relative '../../../modules/rbbt-util/lib/rbbt/tsv/manipulate'
|
2
2
|
#Log.warn "USING OLD RBBT CODE: #{__FILE__}"
|
3
3
|
require_relative 'traverse'
|
4
|
+
require_relative 'util/filter'
|
4
5
|
require_relative 'util/process'
|
5
6
|
require_relative 'util/select'
|
7
|
+
require_relative 'util/reorder'
|
8
|
+
require_relative 'util/unzip'
|
6
9
|
module TSV
|
7
|
-
def
|
8
|
-
|
9
|
-
|
10
|
+
def self.identify_field(key_field, fields, name, strict: nil)
|
11
|
+
return :key if name == :key || (! strict && NamedArray.field_match(key_field, name))
|
12
|
+
name.collect!{|n| key_field == n ? :key : n } if Array === name
|
13
|
+
NamedArray.identify_name(fields, name, strict: strict)
|
14
|
+
end
|
15
|
+
|
16
|
+
def identify_field(name, strict: nil)
|
17
|
+
TSV.identify_field(@key_field, @fields, name, strict: strict)
|
18
|
+
end
|
19
|
+
|
20
|
+
def [](key, *rest)
|
21
|
+
v = super(key, *rest)
|
22
|
+
NamedArray.setup(v, @fields, key) unless @unnamed || ! (Array === v)
|
10
23
|
v
|
11
24
|
end
|
12
25
|
|
26
|
+
def options
|
27
|
+
extension_attr_hash
|
28
|
+
end
|
29
|
+
|
30
|
+
def zip_new(key, values, insitu: :lax)
|
31
|
+
values = values.collect{|v| Array === v ? v : [v] } unless Array === values.first
|
32
|
+
if current_values = self[key]
|
33
|
+
if insitu == :lax
|
34
|
+
self[key] = NamedArray.add_zipped(current_values, values)
|
35
|
+
elsif insitu
|
36
|
+
NamedArray.add_zipped(current_values, values)
|
37
|
+
else
|
38
|
+
self[key] = NamedArray.add_zipped(current_values.dup, values)
|
39
|
+
end
|
40
|
+
else
|
41
|
+
if insitu && insitu != :lax
|
42
|
+
self[key] = values.dup
|
43
|
+
else
|
44
|
+
self[key] = values
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
13
49
|
def each(*args, &block)
|
14
50
|
if block_given?
|
15
51
|
super(*args) do |k,v|
|
16
|
-
|
17
|
-
|
18
|
-
|
52
|
+
NamedArray.setup(v, @fields) unless @unnamed || ! (Array === v)
|
53
|
+
block.call(k, v)
|
54
|
+
end
|
19
55
|
else
|
20
56
|
super(*args)
|
21
57
|
end
|
@@ -33,13 +69,13 @@ module TSV
|
|
33
69
|
end
|
34
70
|
end
|
35
71
|
|
36
|
-
def with_unnamed
|
72
|
+
def with_unnamed(unnamed = true)
|
37
73
|
begin
|
38
|
-
old_unnamed = unnamed
|
39
|
-
unnamed =
|
74
|
+
old_unnamed = @unnamed
|
75
|
+
@unnamed = unnamed
|
40
76
|
yield
|
41
77
|
ensure
|
42
|
-
unnamed = old_unnamed
|
78
|
+
@unnamed = old_unnamed
|
43
79
|
end
|
44
80
|
end
|
45
81
|
|
@@ -53,7 +89,7 @@ module TSV
|
|
53
89
|
end
|
54
90
|
|
55
91
|
filename = @filename
|
56
|
-
filename = "No filename" if filename.nil? || filename.empty?
|
92
|
+
filename = "No filename" if filename.nil? || String === filename && filename.empty?
|
57
93
|
filename.find if Path === filename
|
58
94
|
filename = File.basename(filename) + " [" + File.basename(persistence_path) + "]" if respond_to?(:persistence_path) and persistence_path
|
59
95
|
|
@@ -73,10 +109,23 @@ Example:
|
|
73
109
|
end
|
74
110
|
|
75
111
|
def all_fields
|
112
|
+
return [] if @fields.nil?
|
76
113
|
[@key_field] + @fields
|
77
114
|
end
|
78
115
|
|
116
|
+
def options
|
117
|
+
self.extension_attr_hash
|
118
|
+
end
|
119
|
+
|
79
120
|
def fingerprint
|
80
121
|
"TSV:{"<< Log.fingerprint(self.all_fields|| []) << ";" << Log.fingerprint(self.keys) << "}"
|
81
122
|
end
|
123
|
+
|
124
|
+
def digest_str
|
125
|
+
fingerprint
|
126
|
+
end
|
127
|
+
|
128
|
+
def inspect
|
129
|
+
fingerprint
|
130
|
+
end
|
82
131
|
end
|
data/lib/scout/tsv.rb
CHANGED
@@ -2,23 +2,53 @@ require_relative 'meta_extension'
|
|
2
2
|
require_relative 'tsv/util'
|
3
3
|
require_relative 'tsv/parser'
|
4
4
|
require_relative 'tsv/dumper'
|
5
|
+
require_relative 'tsv/transformer'
|
5
6
|
require_relative 'tsv/persist'
|
6
7
|
require_relative 'tsv/index'
|
7
8
|
require_relative 'tsv/path'
|
8
9
|
require_relative 'tsv/traverse'
|
9
10
|
require_relative 'tsv/open'
|
11
|
+
require_relative 'tsv/attach'
|
12
|
+
require_relative 'tsv/change_id'
|
13
|
+
require_relative 'tsv/stream'
|
10
14
|
|
11
15
|
module TSV
|
12
16
|
extend MetaExtension
|
13
|
-
extension_attr :key_field, :fields, :type, :filename, :namespace, :unnamed, :identifiers
|
17
|
+
extension_attr :key_field, :fields, :type, :cast, :filename, :namespace, :unnamed, :identifiers
|
18
|
+
|
19
|
+
def self.str2options(str)
|
20
|
+
field_options,_sep, rest = str.partition("#")
|
21
|
+
key, fields_str = field_options.split("~")
|
22
|
+
|
23
|
+
fields = fields_str.nil? ? [] : fields_str.split(/,\s*/)
|
24
|
+
|
25
|
+
rest = ":type=" << rest if rest =~ /^:?\w+$/
|
26
|
+
rest_options = rest.nil? ? {} : IndiferentHash.string2hash(rest)
|
27
|
+
|
28
|
+
{:key_field => key, :fields => fields}.merge(rest_options)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.str_setup(option_str, obj)
|
32
|
+
options = TSV.str2options(option_str)
|
33
|
+
setup(obj, options)
|
34
|
+
end
|
14
35
|
|
15
36
|
def self.open(file, options = {})
|
16
|
-
persist, type = IndiferentHash.process_options options, :persist, :persist_type, :persist => false, :persist_type => "HDB"
|
17
|
-
|
37
|
+
persist, type, grep, invert_grep = IndiferentHash.process_options options, :persist, :persist_type, :grep, :invert_grep, :persist => false, :persist_type => "HDB"
|
38
|
+
type = type.to_sym if type
|
39
|
+
file = StringIO.new file if String === file && ! (Path === file) && file.index("\n")
|
40
|
+
Persist.persist(file, type, options.merge(:persist => persist, :prefix => "Tsv", :other_options => options)) do |filename|
|
18
41
|
data = filename ? ScoutCabinet.open(filename, true, type) : nil
|
19
42
|
options[:data] = data if data
|
20
43
|
options[:filename] = file
|
21
|
-
|
44
|
+
|
45
|
+
if data
|
46
|
+
Log.debug "TSV open #{Log.fingerprint file} into #{Log.fingerprint data}"
|
47
|
+
else
|
48
|
+
Log.debug "TSV open #{Log.fingerprint file}"
|
49
|
+
end
|
50
|
+
|
51
|
+
Open.open(file, grep: grep, invert_grep: invert_grep) do |f|
|
22
52
|
TSV.parse(f, **options)
|
23
53
|
end
|
24
54
|
end
|
@@ -3,7 +3,7 @@ require 'scout/semaphore'
|
|
3
3
|
require 'scout/exceptions'
|
4
4
|
class WorkQueue
|
5
5
|
class Socket
|
6
|
-
attr_accessor :sread, :swrite, :write_sem, :read_sem, :cleaned
|
6
|
+
attr_accessor :sread, :swrite, :write_sem, :read_sem, :cleaned, :exception
|
7
7
|
def initialize(serializer = nil)
|
8
8
|
@sread, @swrite = Open.pipe
|
9
9
|
|
@@ -112,6 +112,11 @@ class WorkQueue
|
|
112
112
|
end
|
113
113
|
end
|
114
114
|
|
115
|
+
def abort(exception)
|
116
|
+
@exception = exception
|
117
|
+
@swrite.close unless closed_write?
|
118
|
+
end
|
119
|
+
|
115
120
|
alias write push
|
116
121
|
|
117
122
|
alias read pop
|
@@ -27,8 +27,10 @@ class WorkQueue
|
|
27
27
|
rescue Interrupt
|
28
28
|
rescue Exception
|
29
29
|
output.write WorkerException.new($!, Process.pid)
|
30
|
-
|
30
|
+
exit -1
|
31
|
+
ensure
|
31
32
|
end
|
33
|
+
exit 0
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
@@ -36,7 +38,8 @@ class WorkQueue
|
|
36
38
|
begin
|
37
39
|
Log.debug "Aborting worker #{@pid}"
|
38
40
|
Process.kill "INT", @pid
|
39
|
-
rescue Errno::ECHILD
|
41
|
+
rescue Errno::ECHILD
|
42
|
+
rescue Errno::ESRCH
|
40
43
|
end
|
41
44
|
end
|
42
45
|
|
data/lib/scout/work_queue.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative 'work_queue/socket'
|
2
2
|
require_relative 'work_queue/worker'
|
3
|
+
require 'timeout'
|
3
4
|
|
4
5
|
class WorkQueue
|
5
6
|
attr_accessor :workers, :worker_proc, :callback
|
@@ -38,7 +39,7 @@ class WorkQueue
|
|
38
39
|
@worker_mutex.synchronize do
|
39
40
|
worker = @workers.index{|w| w.pid == pid}
|
40
41
|
if worker
|
41
|
-
Log.
|
42
|
+
Log.low "Removed worker #{pid}"
|
42
43
|
@workers.delete_at(worker)
|
43
44
|
@removed_workers << pid
|
44
45
|
end
|
@@ -46,7 +47,11 @@ class WorkQueue
|
|
46
47
|
end
|
47
48
|
|
48
49
|
def process(&callback)
|
49
|
-
@
|
50
|
+
@workers.each do |w|
|
51
|
+
w.process @input, @output, &@worker_proc
|
52
|
+
end
|
53
|
+
|
54
|
+
@reader = Thread.new(Thread.current) do |parent|
|
50
55
|
begin
|
51
56
|
Thread.current.report_on_exception = false
|
52
57
|
Thread.current["name"] = "Output reader #{Process.pid}"
|
@@ -71,8 +76,9 @@ class WorkQueue
|
|
71
76
|
rescue DoneProcessing
|
72
77
|
rescue Aborted
|
73
78
|
rescue WorkerException
|
74
|
-
Log.error "Exception in worker #{obj.pid} in queue #{Process.pid}: #{obj.message}"
|
79
|
+
Log.error "Exception in worker #{obj.pid} in queue #{Process.pid}: #{obj.worker_exception.message}"
|
75
80
|
self.abort
|
81
|
+
@input.abort obj.worker_exception
|
76
82
|
raise obj.worker_exception
|
77
83
|
rescue
|
78
84
|
Log.error "Exception processing output in queue #{Process.pid}: #{$!.message}"
|
@@ -81,30 +87,45 @@ class WorkQueue
|
|
81
87
|
end
|
82
88
|
end
|
83
89
|
|
84
|
-
@workers.each do |w|
|
85
|
-
w.process @input, @output, &@worker_proc
|
86
|
-
end
|
87
|
-
|
88
90
|
Thread.pass until @reader["name"]
|
89
91
|
|
92
|
+
Thread.pass until @worker_mutex.synchronize{ @workers.select{|w| w.pid.nil? }.empty? }
|
93
|
+
|
90
94
|
@waiter = Thread.new do
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
95
|
+
Thread.current.report_on_exception = false
|
96
|
+
Thread.current["name"] = "Worker waiter #{Process.pid}"
|
97
|
+
while true
|
98
|
+
break if @worker_mutex.synchronize{ @workers.empty? }
|
99
|
+
begin
|
100
|
+
Timeout.timeout(1) do
|
101
|
+
begin
|
102
|
+
pid, status = Process.wait2
|
103
|
+
remove_worker(pid) if pid
|
104
|
+
rescue Exception
|
105
|
+
Log.exception $!
|
106
|
+
end
|
107
|
+
end
|
108
|
+
rescue Timeout::Error
|
109
|
+
pids = @worker_mutex.synchronize{ @workers.collect{|w| w.pid } }
|
110
|
+
pids.each do |p|
|
111
|
+
pid, status = Process.wait2 p, Process::WNOHANG
|
112
|
+
remove_worker(pid) if pid
|
113
|
+
end
|
98
114
|
end
|
99
115
|
end
|
100
116
|
end
|
101
117
|
|
102
|
-
Thread.pass until @worker_mutex.synchronize{ @workers.select{|w| w.pid.nil? }.empty? }
|
103
118
|
Thread.pass until @waiter["name"]
|
104
119
|
end
|
105
120
|
|
106
121
|
def write(obj)
|
107
|
-
|
122
|
+
begin
|
123
|
+
@input.write obj
|
124
|
+
rescue Exception
|
125
|
+
raise $! unless @input.exception
|
126
|
+
ensure
|
127
|
+
raise @input.exception if @input.exception
|
128
|
+
end
|
108
129
|
end
|
109
130
|
|
110
131
|
def abort
|
@@ -117,12 +138,22 @@ class WorkQueue
|
|
117
138
|
def close
|
118
139
|
@closed = true
|
119
140
|
@worker_mutex.synchronize{ @workers.length }.times do
|
120
|
-
@input.write DoneProcessing.new()
|
141
|
+
@input.write DoneProcessing.new() unless @input.closed_write?
|
121
142
|
end
|
122
143
|
end
|
123
144
|
|
124
|
-
def
|
125
|
-
@waiter.join if @waiter
|
126
|
-
@
|
145
|
+
def clean
|
146
|
+
@waiter.join if @waiter
|
147
|
+
@input.clean
|
148
|
+
@output.clean
|
149
|
+
end
|
150
|
+
|
151
|
+
def join(clean = true)
|
152
|
+
begin
|
153
|
+
@waiter.join if @waiter
|
154
|
+
@reader.join if @reader
|
155
|
+
ensure
|
156
|
+
self.clean if clean
|
157
|
+
end
|
127
158
|
end
|
128
159
|
end
|
@@ -50,7 +50,7 @@ module Workflow
|
|
50
50
|
|
51
51
|
def directory=(directory)
|
52
52
|
@directory = directory
|
53
|
-
@tasks.each{|name,d| d.directory = directory[name] } if @tasks
|
53
|
+
@tasks.each{|name,d| d.directory = Path === directory ? directory[name] : File.join(directory, name.to_s) } if @tasks
|
54
54
|
end
|
55
55
|
|
56
56
|
def annotate_next_task(type, obj)
|
@@ -76,9 +76,11 @@ module Workflow
|
|
76
76
|
end
|
77
77
|
when 1
|
78
78
|
task = args.first
|
79
|
+
options, task = task, nil if Hash === task
|
79
80
|
end
|
80
81
|
workflow = self if workflow.nil?
|
81
82
|
options = {} if options.nil?
|
83
|
+
task = task.to_sym if task
|
82
84
|
annotate_next_task :deps, [workflow, task, options, block, args]
|
83
85
|
end
|
84
86
|
|
@@ -101,8 +103,23 @@ module Workflow
|
|
101
103
|
def task(name_and_type, &block)
|
102
104
|
name, type = name_and_type.collect.first
|
103
105
|
@tasks ||= IndiferentHash.setup({})
|
106
|
+
block = self.method(name) if block.nil?
|
104
107
|
begin
|
105
108
|
@annotate_next_task ||= {}
|
109
|
+
@annotate_next_task[:extension] ||=
|
110
|
+
case type
|
111
|
+
when :tsv
|
112
|
+
"tsv"
|
113
|
+
when :yaml
|
114
|
+
"yaml"
|
115
|
+
when :marshal
|
116
|
+
"marshal"
|
117
|
+
when :json
|
118
|
+
"json"
|
119
|
+
else
|
120
|
+
nil
|
121
|
+
end
|
122
|
+
|
106
123
|
task = Task.setup(block, @annotate_next_task.merge(name: name, type: type, directory: directory[name], workflow: self))
|
107
124
|
@tasks[name] = task
|
108
125
|
ensure
|
@@ -110,11 +127,14 @@ module Workflow
|
|
110
127
|
end
|
111
128
|
end
|
112
129
|
|
130
|
+
FORGET_DEP_TASKS = ENV["SCOUT_FORGET_DEP_TASKS"] == "true"
|
131
|
+
REMOVE_DEP_TASKS = ENV["SCOUT_REMOVE_DEP_TASKS"] == "true"
|
113
132
|
def task_alias(name, workflow, oname, *rest, &block)
|
114
133
|
dep(workflow, oname, *rest, &block)
|
115
134
|
extension :dep_task unless @extension
|
116
|
-
returns workflow.tasks[oname].returns if
|
117
|
-
|
135
|
+
returns workflow.tasks[oname].returns if @returns.nil?
|
136
|
+
type = workflow.tasks[oname].type
|
137
|
+
task name => type do
|
118
138
|
raise RbbtException, "dep_task does not have any dependencies" if dependencies.empty?
|
119
139
|
Step.wait_for_jobs dependencies.select{|d| d.streaming? }
|
120
140
|
dep = dependencies.last
|