rbbt-util 5.11.1 → 5.11.2
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/lib/rbbt/persist.rb +97 -27
- data/lib/rbbt/tsv/parallel/traverse.rb +24 -16
- data/lib/rbbt/util/concurrency/processes.rb +3 -3
- data/lib/rbbt/util/concurrency/processes/socket.rb +1 -1
- data/lib/rbbt/util/log.rb +105 -47
- data/lib/rbbt/util/misc.rb +64 -21
- data/lib/rbbt/workflow.rb +30 -11
- data/lib/rbbt/workflow/accessor.rb +29 -12
- data/lib/rbbt/workflow/step.rb +113 -100
- data/share/rbbt_commands/workflow/task +2 -2
- data/test/rbbt/util/test_log.rb +8 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 06c3a98f22b69a5738d6c9b478a2cee9a4e52e66
|
4
|
+
data.tar.gz: d60e07e6371c2c6c88359d6b028e7c7fdcbd0c64
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dab5cbee06c6169ab384555b53e6ea3407cb2c3f18b0b8d99f9aac6d6209d4c8656a6baeba4d46ede3c87c8eb141a870723d7a8336f7f58c85535d6d2f3f54a6
|
7
|
+
data.tar.gz: e3268aebe76ca88cfbc948b34367992188e38289fe966fc90ffc07609e2f6b355d751327008b691fbe4e94a1d7b9085e32fd0f73734ee538b041b9bd982486b0
|
data/lib/rbbt/persist.rb
CHANGED
@@ -172,59 +172,118 @@ module Persist
|
|
172
172
|
end
|
173
173
|
end
|
174
174
|
|
175
|
-
def self.tee_stream_fork(stream, path, type, callback = nil)
|
175
|
+
#def self.tee_stream_fork(stream, path, type, callback = nil)
|
176
|
+
# file, out = Misc.tee_stream(stream)
|
177
|
+
|
178
|
+
# saver_pid = Process.fork do
|
179
|
+
# out.close
|
180
|
+
# stream.close
|
181
|
+
# Misc.purge_pipes
|
182
|
+
# begin
|
183
|
+
# Misc.lock(path) do
|
184
|
+
# save_file(path, type, file)
|
185
|
+
# end
|
186
|
+
# rescue Aborted
|
187
|
+
# stream.abort if stream.respond_to? :abort
|
188
|
+
# raise $!
|
189
|
+
# rescue Exception
|
190
|
+
# Log.exception $!
|
191
|
+
# Kernel.exit! -1
|
192
|
+
# end
|
193
|
+
# Kernel.exit! 0
|
194
|
+
# end
|
195
|
+
# file.close
|
196
|
+
# ConcurrentStream.setup(out, :pids => [saver_pid], :filename => path)
|
197
|
+
#end
|
198
|
+
|
199
|
+
def self.tee_stream_thread(stream, path, type, callback = nil)
|
176
200
|
file, out = Misc.tee_stream(stream)
|
177
201
|
|
178
|
-
|
179
|
-
out.close
|
180
|
-
stream.close
|
181
|
-
Misc.purge_pipes
|
202
|
+
saver_thread = Thread.new(Thread.current, path, file) do |parent,path,file|
|
182
203
|
begin
|
204
|
+
Thread.current["name"] = "file saver: " + path
|
183
205
|
Misc.lock(path) do
|
184
206
|
save_file(path, type, file)
|
185
207
|
end
|
186
208
|
rescue Aborted
|
209
|
+
Log.error "Persist stream thread aborted: #{ Log.color :blue, path }"
|
187
210
|
stream.abort if stream.respond_to? :abort
|
188
|
-
raise $!
|
189
211
|
rescue Exception
|
212
|
+
Log.error "Persist stream thread exception: #{ Log.color :blue, path }"
|
190
213
|
Log.exception $!
|
191
|
-
|
214
|
+
stream.abort if stream.respond_to? :abort
|
215
|
+
parent.raise $!
|
192
216
|
end
|
193
|
-
Kernel.exit! 0
|
194
217
|
end
|
195
|
-
|
196
|
-
ConcurrentStream.setup(out, :pids => [saver_pid], :filename => path)
|
218
|
+
ConcurrentStream.setup(out, :threads => saver_thread, :filename => path)
|
197
219
|
end
|
198
220
|
|
199
|
-
def self.
|
200
|
-
|
201
|
-
|
202
|
-
saver_thread = Thread.new(Thread.current, path, file) do |parent,path,file|
|
221
|
+
def self.tee_stream_pipe(stream, path, type, callback = nil)
|
222
|
+
parent_pid = Process.pid
|
223
|
+
out = Misc.open_pipe true, false do |sin|
|
203
224
|
begin
|
204
|
-
|
205
|
-
|
206
|
-
|
225
|
+
file, out = Misc.tee_stream(stream)
|
226
|
+
|
227
|
+
saver_th = Thread.new(Thread.current, path, file) do |parent,path,file|
|
228
|
+
begin
|
229
|
+
Misc.lock(path) do
|
230
|
+
save_file(path, type, file)
|
231
|
+
end
|
232
|
+
Log.high "Stream pipe saved: #{path}"
|
233
|
+
rescue Aborted
|
234
|
+
Log.error "Persist stream pipe exception: #{ Log.color :blue, path }"
|
235
|
+
stream.abort if stream.respond_to? :abort
|
236
|
+
rescue Exception
|
237
|
+
Log.error "Persist stream pipe exception: #{ Log.color :blue, path }"
|
238
|
+
Log.exception $!
|
239
|
+
stream.abort if stream.respond_to? :abort
|
240
|
+
parent.raise $!
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
tee_th = Thread.new(Thread.current) do |parent|
|
245
|
+
begin
|
246
|
+
while block = out.read(2028)
|
247
|
+
sin.write block
|
248
|
+
end
|
249
|
+
rescue Aborted
|
250
|
+
Log.error "Tee stream thread aborted"
|
251
|
+
stream.abort if stream.respond_to? :abort
|
252
|
+
rescue Exception
|
253
|
+
stream.abort if stream.respond_to? :abort
|
254
|
+
Log.exception $!
|
255
|
+
parent.raise $!
|
256
|
+
ensure
|
257
|
+
sin.close unless sin.closed?
|
258
|
+
end
|
207
259
|
end
|
260
|
+
saver_th.join
|
261
|
+
tee_th.join
|
208
262
|
rescue Aborted
|
209
|
-
|
210
|
-
|
263
|
+
tee_th.raise Aborted.new if tee_th and tee_th.alive?
|
264
|
+
saver_th.raise Aborted.new if saver_th and saver_th.alive?
|
265
|
+
Kernel.exit! -1
|
211
266
|
rescue Exception
|
212
|
-
|
267
|
+
tee_th.raise Aborted.new if tee_th and tee_th.alive?
|
268
|
+
saver_th.raise Aborted.new if saver_th and saver_th.alive?
|
213
269
|
Log.exception $!
|
214
|
-
|
270
|
+
Process.kill :INT, parent_pid
|
271
|
+
Kernel.exit! -1
|
215
272
|
end
|
216
273
|
end
|
217
|
-
|
274
|
+
stream.close
|
275
|
+
out
|
218
276
|
end
|
219
277
|
|
220
278
|
class << self
|
221
279
|
alias tee_stream tee_stream_thread
|
222
280
|
end
|
223
281
|
|
282
|
+
|
224
283
|
def self.persist(name, type = nil, persist_options = {})
|
225
284
|
type ||= :marshal
|
226
285
|
|
227
|
-
return (persist_options[:repo] || Persist::MEMORY)[persist_options[:file]] ||= yield if type ==:memory and persist_options[:file]
|
286
|
+
return (persist_options[:repo] || Persist::MEMORY)[persist_options[:file]] ||= yield if type ==:memory and persist_options[:file] and persist_options[:persist] and persist_options[:persist] != :update
|
228
287
|
|
229
288
|
if FalseClass != persist_options[:persist]
|
230
289
|
other_options = Misc.process_options persist_options, :other
|
@@ -327,6 +386,7 @@ module Persist
|
|
327
386
|
|
328
387
|
lock_filename = Persist.persistence_path(path + '.persist', {:dir => Persist.lock_dir})
|
329
388
|
Misc.lock lock_filename do |lockfile|
|
389
|
+
|
330
390
|
if is_persisted?(path, persist_options)
|
331
391
|
Log.low "Persist up-to-date (suddenly): #{ path } - #{Misc.fingerprint persist_options}"
|
332
392
|
return path if persist_options[:no_load]
|
@@ -342,13 +402,21 @@ module Persist
|
|
342
402
|
when IO
|
343
403
|
res = tee_stream(res, path, type, res.respond_to?(:callback)? res.callback : nil)
|
344
404
|
ConcurrentStream.setup res do
|
345
|
-
|
405
|
+
begin
|
406
|
+
lockfile.unlock
|
407
|
+
rescue
|
408
|
+
Log.warn "Lockfile exception: " << $!.message
|
409
|
+
end
|
346
410
|
end
|
347
411
|
raise KeepLocked.new res
|
348
412
|
when TSV::Dumper
|
349
413
|
res = tee_stream(res.stream, path, type, res.respond_to?(:callback)? res.callback : nil)
|
350
414
|
ConcurrentStream.setup res do
|
351
|
-
|
415
|
+
begin
|
416
|
+
lockfile.unlock
|
417
|
+
rescue
|
418
|
+
Log.warn "Lockfile exception: " << $!.message
|
419
|
+
end
|
352
420
|
end
|
353
421
|
raise KeepLocked.new res
|
354
422
|
end
|
@@ -367,6 +435,7 @@ module Persist
|
|
367
435
|
end
|
368
436
|
rescue
|
369
437
|
res.abort if res.respond_to? :abort
|
438
|
+
raise $!
|
370
439
|
ensure
|
371
440
|
res.join if res.respond_to? :join
|
372
441
|
end
|
@@ -376,6 +445,7 @@ module Persist
|
|
376
445
|
res = TSV.open(io)
|
377
446
|
rescue
|
378
447
|
io.abort if io.respond_to? :abort
|
448
|
+
raise $!
|
379
449
|
ensure
|
380
450
|
io.join if io.respond_to? :join
|
381
451
|
end
|
@@ -389,7 +459,7 @@ module Persist
|
|
389
459
|
end
|
390
460
|
|
391
461
|
rescue
|
392
|
-
Log.
|
462
|
+
Log.error "Error in persist: #{path}#{Open.exists?(path) ? Log.color(:red, " Erasing") : ""}"
|
393
463
|
FileUtils.rm path if Open.exists? path
|
394
464
|
raise $!
|
395
465
|
end
|
@@ -410,7 +480,7 @@ module Persist
|
|
410
480
|
file = name
|
411
481
|
repo = options.delete :repo if options and options.any?
|
412
482
|
file << "_" << (options[:key] ? options[:key] : Misc.hash2md5(options)) if options and options.any?
|
413
|
-
persist name, :memory,
|
483
|
+
persist name, :memory, {:repo => repo, :persist => true, :file => file}.merge(options), &block
|
414
484
|
end
|
415
485
|
end
|
416
486
|
end
|
@@ -115,7 +115,7 @@ module TSV
|
|
115
115
|
else
|
116
116
|
obj.traverse(options, &block)
|
117
117
|
end
|
118
|
-
when IO, File
|
118
|
+
when IO, File
|
119
119
|
begin
|
120
120
|
if options[:type] == :array
|
121
121
|
traverse_io_array(obj, options, &block)
|
@@ -123,7 +123,8 @@ module TSV
|
|
123
123
|
traverse_io(obj, options, &block)
|
124
124
|
end
|
125
125
|
rescue Exception
|
126
|
-
|
126
|
+
obj.abort if obj.respond_to? :abort
|
127
|
+
raise $!
|
127
128
|
ensure
|
128
129
|
begin
|
129
130
|
obj.close if obj.respond_to? :close and not obj.closed?
|
@@ -150,7 +151,7 @@ module TSV
|
|
150
151
|
when Array
|
151
152
|
traverse_array(obj, options, &block)
|
152
153
|
when nil
|
153
|
-
raise "Can not traverse nil object"
|
154
|
+
raise "Can not traverse nil object into #{stream_name(options)}"
|
154
155
|
else
|
155
156
|
raise "Unknown object for traversal: #{Misc.fingerprint obj }"
|
156
157
|
end
|
@@ -191,18 +192,24 @@ module TSV
|
|
191
192
|
q.callback &callback
|
192
193
|
q.init &block
|
193
194
|
|
194
|
-
|
195
|
-
q.
|
195
|
+
pid = Process.fork do
|
196
|
+
Misc.purge_pipes(q.queue.swrite)
|
197
|
+
traverse_obj(obj, options) do |*p|
|
198
|
+
q.process *p
|
199
|
+
end
|
196
200
|
end
|
197
201
|
|
198
|
-
|
202
|
+
#stream = obj_stream(obj)
|
203
|
+
#stream.close if stream
|
204
|
+
|
205
|
+
Process.waitpid pid
|
199
206
|
rescue Exception
|
207
|
+
Log.exception $!
|
200
208
|
q.abort
|
201
209
|
raise $!
|
202
210
|
ensure
|
203
211
|
q.join
|
204
212
|
end
|
205
|
-
|
206
213
|
end
|
207
214
|
|
208
215
|
def self.store_into(store, value)
|
@@ -243,11 +250,13 @@ module TSV
|
|
243
250
|
when TSV::Dumper
|
244
251
|
close_streams << obj.result.in_stream
|
245
252
|
when (defined? Step and Step)
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
253
|
+
obj.mutex.synchronize do
|
254
|
+
case obj.result
|
255
|
+
when IO
|
256
|
+
close_streams << obj.result
|
257
|
+
when TSV::Dumper
|
258
|
+
close_streams << obj.result.in_stream
|
259
|
+
end
|
251
260
|
end
|
252
261
|
obj.inputs.each do |input|
|
253
262
|
close_streams = get_streams_to_close(input) + close_streams
|
@@ -294,7 +303,6 @@ module TSV
|
|
294
303
|
parent.raise $!
|
295
304
|
end
|
296
305
|
end
|
297
|
-
thread.wakeup
|
298
306
|
ConcurrentStream.setup(obj_stream(into), :threads => thread)
|
299
307
|
end
|
300
308
|
|
@@ -311,7 +319,8 @@ module TSV
|
|
311
319
|
begin
|
312
320
|
traverse(obj, options.merge(:into => sin), &block)
|
313
321
|
rescue Exception
|
314
|
-
|
322
|
+
sout.abort if sout.respond_to? :abort
|
323
|
+
sout.join if sout.respond_to? :join
|
315
324
|
end
|
316
325
|
end
|
317
326
|
return sout
|
@@ -328,11 +337,10 @@ module TSV
|
|
328
337
|
end
|
329
338
|
|
330
339
|
case into
|
331
|
-
when TSV::Dumper, IO
|
340
|
+
when TSV::Dumper, IO
|
332
341
|
traverse_stream(obj, threads, cpus, options, &block)
|
333
342
|
else
|
334
343
|
traverse_run(obj, threads, cpus, options, &block)
|
335
|
-
into.join if into.respond_to? :join
|
336
344
|
into.close if into.respond_to? :close
|
337
345
|
end
|
338
346
|
|
@@ -31,7 +31,7 @@ class RbbtProcessQueue
|
|
31
31
|
Log.error "Callback thread aborted"
|
32
32
|
rescue ClosedStream
|
33
33
|
rescue Exception
|
34
|
-
Log.exception
|
34
|
+
Log.error "Callback thread exception"
|
35
35
|
parent.raise $!
|
36
36
|
ensure
|
37
37
|
@callback_queue.sread.close unless @callback_queue.sread.closed?
|
@@ -68,7 +68,6 @@ class RbbtProcessQueue
|
|
68
68
|
|
69
69
|
def close_callback
|
70
70
|
@callback_queue.push ClosedStream.new if @callback_thread.alive?
|
71
|
-
@callback_queue.swrite.close
|
72
71
|
@callback_thread.join
|
73
72
|
end
|
74
73
|
|
@@ -81,6 +80,7 @@ class RbbtProcessQueue
|
|
81
80
|
close_callback if @callback
|
82
81
|
rescue Exception
|
83
82
|
Log.exception $!
|
83
|
+
raise $!
|
84
84
|
ensure
|
85
85
|
@queue.swrite.close
|
86
86
|
end
|
@@ -100,7 +100,7 @@ class RbbtProcessQueue
|
|
100
100
|
end
|
101
101
|
|
102
102
|
def abort
|
103
|
-
@process_monitor.raise Aborted.new if @process_monitor.alive?
|
103
|
+
@process_monitor.raise Aborted.new if @process_monitor and @process_monitor.alive?
|
104
104
|
@callback_thread.raise Aborted.new if @callback_thread and @callback_thread.alive?
|
105
105
|
end
|
106
106
|
|
data/lib/rbbt/util/log.rb
CHANGED
@@ -4,13 +4,29 @@ require 'rbbt/util/color'
|
|
4
4
|
module Log
|
5
5
|
extend Term::ANSIColor
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
7
|
+
|
8
|
+
SEVERITY_NAMES ||= begin
|
9
|
+
names = %w(DEBUG LOW MEDIUM HIGH INFO WARN ERROR )
|
10
|
+
names.each_with_index do |name,i|
|
11
|
+
eval "#{ name } = #{ i }"
|
12
|
+
end
|
13
|
+
names
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.get_level(level)
|
17
|
+
case level
|
18
|
+
when Fixnum
|
19
|
+
level
|
20
|
+
when String
|
21
|
+
begin
|
22
|
+
Log.const_get(level.upcase)
|
23
|
+
rescue
|
24
|
+
Log.exception $!
|
25
|
+
end
|
26
|
+
when Symbol
|
27
|
+
get_level(level.to_s)
|
28
|
+
end || 0
|
29
|
+
end
|
14
30
|
|
15
31
|
class << self
|
16
32
|
attr_accessor :logfile, :severity, :nocolor, :tty_size
|
@@ -42,11 +58,15 @@ module Log
|
|
42
58
|
Term::ANSIColor.uncolor(str)
|
43
59
|
end
|
44
60
|
|
45
|
-
def self.
|
61
|
+
def self.reset_color
|
62
|
+
reset
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.color(severity, str = nil, reset = false)
|
46
66
|
return str || "" if nocolor
|
47
|
-
color =
|
48
|
-
color
|
49
|
-
color
|
67
|
+
color = reset ? Term::ANSIColor.reset : ""
|
68
|
+
color << SEVERITY_COLOR[severity] if Fixnum === severity
|
69
|
+
color << Term::ANSIColor.send(severity) if Symbol === severity and Term::ANSIColor.respond_to? severity
|
50
70
|
if str.nil?
|
51
71
|
color
|
52
72
|
else
|
@@ -92,6 +112,40 @@ module Log
|
|
92
112
|
end
|
93
113
|
end
|
94
114
|
|
115
|
+
def self.log_obj_inspect(obj, level, file = $stdout)
|
116
|
+
stack = caller
|
117
|
+
|
118
|
+
line = nil
|
119
|
+
while line.nil? or line =~ /util\/log\.rb/ and stack.any?
|
120
|
+
line = stack.shift
|
121
|
+
end
|
122
|
+
line ||= caller.first
|
123
|
+
|
124
|
+
level = Log.get_level level
|
125
|
+
name = Log::SEVERITY_NAMES[level] + ": "
|
126
|
+
Log.log Log.color(level, name, true) << line, level
|
127
|
+
Log.log "", level
|
128
|
+
Log.log Log.color(level, "=> ", true) << obj.inspect, level
|
129
|
+
Log.log "", level
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.log_obj_fingerprint(obj, level, file = $stdout)
|
133
|
+
stack = caller
|
134
|
+
|
135
|
+
line = nil
|
136
|
+
while line.nil? or line =~ /util\/log\.rb/ and stack.any?
|
137
|
+
line = stack.shift
|
138
|
+
end
|
139
|
+
line ||= caller.first
|
140
|
+
|
141
|
+
level = Log.get_level level
|
142
|
+
name = Log::SEVERITY_NAMES[level] + ": "
|
143
|
+
Log.log Log.color(level, name, true) << line, level
|
144
|
+
Log.log "", level
|
145
|
+
Log.log Log.color(level, "=> ", true) << Misc.fingerprint(obj), level
|
146
|
+
Log.log "", level
|
147
|
+
end
|
148
|
+
|
95
149
|
def self.debug(message = nil, &block)
|
96
150
|
log(message, DEBUG, &block)
|
97
151
|
end
|
@@ -157,52 +211,52 @@ def fff(object)
|
|
157
211
|
Log.debug{""}
|
158
212
|
end
|
159
213
|
|
160
|
-
def ddd(
|
161
|
-
|
162
|
-
Log.debug{"#{Log.color :cyan, "DEBUG:"} " << stack.first}
|
163
|
-
Log.debug{""}
|
164
|
-
Log.debug{"=> " << message.inspect}
|
165
|
-
Log.debug{""}
|
214
|
+
def ddd(obj, file = $stdout)
|
215
|
+
Log.log_obj_inspect(obj, :debug, file)
|
166
216
|
end
|
167
217
|
|
168
|
-
def lll(
|
169
|
-
|
170
|
-
Log.low{"#{Log.color :cyan, "LOW:"} " << stack.first}
|
171
|
-
Log.low{""}
|
172
|
-
Log.low{"=> " << message.inspect}
|
173
|
-
Log.low{""}
|
218
|
+
def lll(obj, file = $stdout)
|
219
|
+
Log.log_obj_inspect(obj, :low, file)
|
174
220
|
end
|
175
221
|
|
176
|
-
def mmm(
|
177
|
-
|
178
|
-
Log.low{"#{Log.color :cyan, "MEDIUM:"} " << stack.first}
|
179
|
-
Log.low{""}
|
180
|
-
Log.low{"=> " << message.inspect}
|
181
|
-
Log.low{""}
|
222
|
+
def mmm(obj, file = $stdout)
|
223
|
+
Log.log_obj_inspect(obj, :medium, file)
|
182
224
|
end
|
183
225
|
|
184
|
-
def
|
185
|
-
|
186
|
-
Log.high{"#{Log.color :cyan, "HIGH:"} " << stack.first}
|
187
|
-
Log.high{""}
|
188
|
-
Log.high{"=> " << message.inspect}
|
189
|
-
Log.high{""}
|
226
|
+
def iii(obj, file = $stdout)
|
227
|
+
Log.log_obj_inspect(obj, :info, file)
|
190
228
|
end
|
191
229
|
|
192
|
-
def
|
193
|
-
|
194
|
-
Log.info{"#{Log.color :cyan, "INFO:"} " << stack.first}
|
195
|
-
Log.info{""}
|
196
|
-
Log.info{"=> " << message.inspect}
|
197
|
-
Log.info{""}
|
230
|
+
def wwww(obj, file = $stdout)
|
231
|
+
Log.log_obj_inspect(obj, :warn, file)
|
198
232
|
end
|
199
233
|
|
200
|
-
def eee(
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
Log.
|
234
|
+
def eee(obj, file = $stdout)
|
235
|
+
Log.log_obj_inspect(obj, :error, file)
|
236
|
+
end
|
237
|
+
|
238
|
+
def ddf(obj, file = $stdout)
|
239
|
+
Log.log_obj_fingerprint(obj, :debug, file)
|
240
|
+
end
|
241
|
+
|
242
|
+
def llf(obj, file = $stdout)
|
243
|
+
Log.log_obj_fingerprint(obj, :low, file)
|
244
|
+
end
|
245
|
+
|
246
|
+
def mmf(obj, file = $stdout)
|
247
|
+
Log.log_obj_fingerprint(obj, :medium, file)
|
248
|
+
end
|
249
|
+
|
250
|
+
def iif(obj, file = $stdout)
|
251
|
+
Log.log_obj_fingerprint(obj, :info, file)
|
252
|
+
end
|
253
|
+
|
254
|
+
def wwwf(obj, file = $stdout)
|
255
|
+
Log.log_obj_fingerprint(obj, :warn, file)
|
256
|
+
end
|
257
|
+
|
258
|
+
def eef(obj, file = $stdout)
|
259
|
+
Log.log_obj_fingerprint(obj, :error, file)
|
206
260
|
end
|
207
261
|
|
208
262
|
if __FILE__ == $0
|
@@ -211,4 +265,8 @@ if __FILE__ == $0
|
|
211
265
|
(0..6).each do |level|
|
212
266
|
Log.log("Level #{level}", level)
|
213
267
|
end
|
268
|
+
|
269
|
+
require 'rbbt/util/misc'
|
270
|
+
eee [1,2,3]
|
271
|
+
eef [1,2,3]
|
214
272
|
end
|
data/lib/rbbt/util/misc.rb
CHANGED
@@ -35,7 +35,11 @@ module LaterString
|
|
35
35
|
end
|
36
36
|
|
37
37
|
module ConcurrentStream
|
38
|
-
attr_accessor :threads, :pids, :callback, :filename
|
38
|
+
attr_accessor :threads, :pids, :callback, :filename, :joined
|
39
|
+
|
40
|
+
def joined?
|
41
|
+
@joined
|
42
|
+
end
|
39
43
|
|
40
44
|
def join
|
41
45
|
|
@@ -57,10 +61,12 @@ module ConcurrentStream
|
|
57
61
|
@pids = []
|
58
62
|
end
|
59
63
|
|
60
|
-
if @callback
|
64
|
+
if @callback and not joined?
|
61
65
|
@callback.call
|
62
66
|
@callback = nil
|
63
67
|
end
|
68
|
+
|
69
|
+
@joined = true
|
64
70
|
end
|
65
71
|
|
66
72
|
def abort
|
@@ -147,11 +153,11 @@ module Misc
|
|
147
153
|
Process.kill :INT, parent_pid
|
148
154
|
Kernel.exit! -1
|
149
155
|
ensure
|
150
|
-
sin.close
|
156
|
+
sin.close if close and not sin.closed?
|
151
157
|
end
|
152
158
|
Kernel.exit! 0
|
153
159
|
}
|
154
|
-
sin.close if close
|
160
|
+
sin.close #if close
|
155
161
|
ConcurrentStream.setup sout, :pids => [pid]
|
156
162
|
else
|
157
163
|
thread = Thread.new(Thread.current) do |parent|
|
@@ -160,7 +166,7 @@ module Misc
|
|
160
166
|
rescue
|
161
167
|
parent.raise $!
|
162
168
|
ensure
|
163
|
-
sin.close if close
|
169
|
+
sin.close if close and not sin.closed?
|
164
170
|
end
|
165
171
|
end
|
166
172
|
ConcurrentStream.setup sout, :threads => [thread]
|
@@ -246,6 +252,10 @@ module Misc
|
|
246
252
|
alias tee_stream tee_stream_thread
|
247
253
|
end
|
248
254
|
|
255
|
+
def self.consume_stream(io)
|
256
|
+
Thread.pass while block = io.read(2048)
|
257
|
+
end
|
258
|
+
|
249
259
|
def self.format_paragraph(text, size = 80, indent = 0, offset = 0)
|
250
260
|
i = 0
|
251
261
|
re = /((?:\n\s*\n\s*)|(?:\n\s*(?=\*)))/
|
@@ -320,6 +330,14 @@ module Misc
|
|
320
330
|
str
|
321
331
|
end
|
322
332
|
|
333
|
+
def self.read_stream(stream, size)
|
334
|
+
str = ""
|
335
|
+
while (len=str.length) < size
|
336
|
+
str << stream.read(size-len)
|
337
|
+
end
|
338
|
+
str
|
339
|
+
end
|
340
|
+
|
323
341
|
def self.parse_cmd_params(str)
|
324
342
|
return str if Array === str
|
325
343
|
str.scan(/
|
@@ -531,9 +549,9 @@ module Misc
|
|
531
549
|
else
|
532
550
|
"'" << obj << "'"
|
533
551
|
end
|
534
|
-
when AnnotatedArray
|
552
|
+
when (defined? AnnotatedArray and AnnotatedArray)
|
535
553
|
"<A: #{fingerprint Annotated.purge(obj)} #{fingerprint obj.info}>"
|
536
|
-
when TSV::Parser
|
554
|
+
when (defined? TSV and TSV::Parser)
|
537
555
|
"<TSVStream:" + obj.filename + "--" << Misc.fingerprint(obj.options) << ">"
|
538
556
|
when IO
|
539
557
|
"<IO:" + (obj.respond_to?(:filename) ? obj.filename : obj.inspect) + ">"
|
@@ -545,7 +563,7 @@ module Misc
|
|
545
563
|
else
|
546
564
|
"[" << (obj.collect{|e| fingerprint(e) } * ",") << "]"
|
547
565
|
end
|
548
|
-
when TSV
|
566
|
+
when (defined? TSV and TSV)
|
549
567
|
obj.with_unnamed do
|
550
568
|
"TSV:{"<< fingerprint(obj.all_fields|| []).inspect << ";" << fingerprint(obj.keys).inspect << "}"
|
551
569
|
end
|
@@ -1301,6 +1319,7 @@ end
|
|
1301
1319
|
@hostanem ||= `hostname`.strip
|
1302
1320
|
end
|
1303
1321
|
|
1322
|
+
LOCK_MUTEX = Mutex.new
|
1304
1323
|
def self.lock(file, unlock = true)
|
1305
1324
|
return yield if file.nil?
|
1306
1325
|
FileUtils.mkdir_p File.dirname(File.expand_path(file)) unless File.exists? File.dirname(File.expand_path(file))
|
@@ -1310,24 +1329,49 @@ end
|
|
1310
1329
|
lock_path = File.expand_path(file + '.lock')
|
1311
1330
|
lockfile = Lockfile.new(lock_path)
|
1312
1331
|
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1332
|
+
hostname = Misc.hostname
|
1333
|
+
LOCK_MUTEX.synchronize do
|
1334
|
+
Misc.insist 3, 0.1 do
|
1335
|
+
begin
|
1336
|
+
if File.exists? lock_path
|
1337
|
+
info = Open.open(lock_path){|f| YAML.load(f) }
|
1338
|
+
raise "No info" unless info
|
1318
1339
|
|
1319
|
-
|
1320
|
-
|
1340
|
+
if hostname == info["host"] and not Misc.pid_exists?(info["pid"])
|
1341
|
+
Log.info("Removing lockfile: #{lock_path}. This pid #{Process.pid}. Content: #{info.inspect}")
|
1342
|
+
FileUtils.rm lock_path
|
1343
|
+
end
|
1344
|
+
end
|
1345
|
+
rescue Exception
|
1346
|
+
FileUtils.rm lock_path if File.exists? lock_path
|
1347
|
+
raise $!
|
1348
|
+
ensure
|
1349
|
+
lockfile = Lockfile.new(lock_path) unless File.exists? lock_path
|
1321
1350
|
end
|
1322
1351
|
end
|
1323
|
-
rescue
|
1324
|
-
Log.warn("Error checking lockfile #{lock_path}: #{$!.message}. Removing. Content: #{begin Open.read(lock_path) rescue "Could not open file" end}")
|
1325
|
-
FileUtils.rm lock_path if File.exists?(lock_path)
|
1326
|
-
lockfile = Lockfile.new(lock_path)
|
1327
|
-
retry
|
1328
1352
|
end
|
1329
1353
|
|
1354
|
+
#begin
|
1355
|
+
# Misc.insist 3 do
|
1356
|
+
# LOCK_MUTEX.synchronize do
|
1357
|
+
# if File.exists? lock_path and
|
1358
|
+
# Misc.hostname == (info = Open.open(lock_path){|f| YAML.load(f) })["host"] and
|
1359
|
+
# info["pid"] and not Misc.pid_exists?(info["pid"])
|
1360
|
+
|
1361
|
+
# Log.info("Removing lockfile: #{lock_path}. This pid #{Process.pid}. Content: #{info.inspect}")
|
1362
|
+
# FileUtils.rm lock_path
|
1363
|
+
# end
|
1364
|
+
# end
|
1365
|
+
# end
|
1366
|
+
#rescue
|
1367
|
+
# Log.warn("Error checking lockfile #{lock_path}: #{$!.message}. Removing. Content: #{begin Open.read(lock_path) rescue "Could not open file" end}")
|
1368
|
+
# FileUtils.rm lock_path if File.exists?(lock_path)
|
1369
|
+
# lockfile = Lockfile.new(lock_path)
|
1370
|
+
# retry
|
1371
|
+
#end
|
1372
|
+
|
1330
1373
|
begin
|
1374
|
+
|
1331
1375
|
lockfile.lock
|
1332
1376
|
res = yield lockfile
|
1333
1377
|
rescue Lockfile::StolenLockError
|
@@ -1338,7 +1382,6 @@ end
|
|
1338
1382
|
ensure
|
1339
1383
|
if unlock and lockfile.locked?
|
1340
1384
|
lockfile.unlock
|
1341
|
-
FileUtils.rm lock_path if File.exists? lock_path
|
1342
1385
|
end
|
1343
1386
|
end
|
1344
1387
|
|
data/lib/rbbt/workflow.rb
CHANGED
@@ -159,6 +159,7 @@ module Workflow
|
|
159
159
|
attr_accessor :helpers, :tasks
|
160
160
|
attr_accessor :task_dependencies, :task_description, :last_task
|
161
161
|
attr_accessor :asynchronous_exports, :synchronous_exports, :exec_exports
|
162
|
+
attr_accessor :step_cache
|
162
163
|
|
163
164
|
#{{{ ATTR DEFAULTS
|
164
165
|
|
@@ -180,6 +181,10 @@ module Workflow
|
|
180
181
|
@libdir = Path.caller_lib_dir if @libdir.nil?
|
181
182
|
@libdir
|
182
183
|
end
|
184
|
+
|
185
|
+
def step_cache
|
186
|
+
@step_cache ||= {}
|
187
|
+
end
|
183
188
|
|
184
189
|
|
185
190
|
def helpers
|
@@ -226,6 +231,28 @@ module Workflow
|
|
226
231
|
end
|
227
232
|
end
|
228
233
|
|
234
|
+
def get_job_step(step_path, task = nil, input_values = nil, dependencies = nil)
|
235
|
+
step_path = step_path.call if Proc === step_path
|
236
|
+
persist = input_values.nil? ? false : true
|
237
|
+
step = Persist.memory("Step", :key => step_path, :repo => step_cache, :persist => persist ) do
|
238
|
+
step = Step.new step_path, task, input_values, dependencies
|
239
|
+
|
240
|
+
helpers.each do |name, block|
|
241
|
+
(class << step; self; end).instance_eval do
|
242
|
+
define_method name, &block
|
243
|
+
end
|
244
|
+
end
|
245
|
+
step
|
246
|
+
|
247
|
+
end
|
248
|
+
|
249
|
+
step.task ||= task
|
250
|
+
step.inputs ||= input_values
|
251
|
+
step.dependencies = dependencies if dependencies and (step.dependencies.nil? or step.dependencies.length < dependencies.length)
|
252
|
+
|
253
|
+
step
|
254
|
+
end
|
255
|
+
|
229
256
|
def job(taskname, jobname = nil, inputs = {})
|
230
257
|
taskname = taskname.to_sym
|
231
258
|
jobname = DEFAULT_NAME if jobname.nil? or jobname.empty?
|
@@ -247,20 +274,12 @@ module Workflow
|
|
247
274
|
step_path = step_path taskname, jobname, input_values, dependencies, task.extension
|
248
275
|
end
|
249
276
|
|
250
|
-
|
251
|
-
|
252
|
-
helpers.each do |name, block|
|
253
|
-
(class << step; self; end).instance_eval do
|
254
|
-
define_method name, &block
|
255
|
-
end
|
256
|
-
end
|
257
|
-
|
258
|
-
step
|
277
|
+
get_job_step step_path, task, input_values, dependencies
|
259
278
|
end
|
260
279
|
|
261
280
|
def load_step(path)
|
262
281
|
task = task_for path
|
263
|
-
|
282
|
+
get_job_step path, tasks[task.to_sym]
|
264
283
|
end
|
265
284
|
|
266
285
|
def load_id(id)
|
@@ -279,7 +298,7 @@ module Workflow
|
|
279
298
|
def load_name(task, name)
|
280
299
|
task = tasks[task.to_sym] if String === task or Symbol === task
|
281
300
|
path = step_path task.name, name, [], [], task.extension
|
282
|
-
|
301
|
+
get_job_step path, task
|
283
302
|
end
|
284
303
|
|
285
304
|
def jobs(taskname, query = nil)
|
@@ -42,24 +42,29 @@ class Step
|
|
42
42
|
def info
|
43
43
|
return {} if info_file.nil? or not Open.exists? info_file
|
44
44
|
begin
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
Misc.insist(2,
|
52
|
-
|
53
|
-
|
45
|
+
@info_mutex.synchronize do
|
46
|
+
begin
|
47
|
+
return @info_cache if @info_cache and File.mtime(info_file) < @info_cache_time
|
48
|
+
rescue Exception
|
49
|
+
end
|
50
|
+
begin
|
51
|
+
@info_cache = Misc.insist(2, 1, info_file) do
|
52
|
+
Misc.insist(2, 0.5, info_file) do
|
53
|
+
Misc.insist(3, 0.1, info_file) do
|
54
|
+
Open.open(info_file) do |file|
|
55
|
+
INFO_SERIALIAZER.load(file) || {}
|
56
|
+
end
|
57
|
+
end
|
54
58
|
end
|
55
59
|
end
|
60
|
+
@info_cache_time = Time.now
|
61
|
+
@info_cache
|
56
62
|
end
|
57
63
|
end
|
58
|
-
@info_cache_time = Time.now
|
59
|
-
@info_cache
|
60
64
|
rescue Exception
|
61
65
|
Log.debug{"Error loading info file: " + info_file}
|
62
66
|
Open.write(info_file, INFO_SERIALIAZER.dump({:status => :error, :messages => ["Info file lost"]}))
|
67
|
+
self.abort
|
63
68
|
raise $!
|
64
69
|
end
|
65
70
|
end
|
@@ -69,7 +74,7 @@ class Step
|
|
69
74
|
value = Annotated.purge value if defined? Annotated
|
70
75
|
Open.lock(info_file) do
|
71
76
|
i = info
|
72
|
-
i[key] = value
|
77
|
+
i[key] = value
|
73
78
|
@info_cache = i
|
74
79
|
Open.write(info_file, INFO_SERIALIAZER.dump(i))
|
75
80
|
@info_cache_time = Time.now
|
@@ -143,6 +148,10 @@ class Step
|
|
143
148
|
path and path.exists?
|
144
149
|
end
|
145
150
|
|
151
|
+
def streaming?
|
152
|
+
IO === @result or status == :streaming
|
153
|
+
end
|
154
|
+
|
146
155
|
def running?
|
147
156
|
return nil if not Open.exists? info_file
|
148
157
|
return nil if info[:pid].nil?
|
@@ -239,6 +248,14 @@ class Step
|
|
239
248
|
end
|
240
249
|
{:inputs => info[:inputs], :provenance => provenance}
|
241
250
|
end
|
251
|
+
|
252
|
+
def provenance_paths
|
253
|
+
provenance = {}
|
254
|
+
dependencies.each do |dep|
|
255
|
+
provenance[dep.path] = dep.provenance_paths if File.exists? dep.path
|
256
|
+
end
|
257
|
+
provenance
|
258
|
+
end
|
242
259
|
end
|
243
260
|
|
244
261
|
module Workflow
|
data/lib/rbbt/workflow/step.rb
CHANGED
@@ -9,10 +9,11 @@ class Step
|
|
9
9
|
attr_accessor :path, :task, :inputs, :dependencies, :bindings
|
10
10
|
attr_accessor :pid
|
11
11
|
attr_accessor :exec
|
12
|
-
attr_accessor :result
|
12
|
+
attr_accessor :result, :mutex
|
13
13
|
|
14
14
|
def initialize(path, task = nil, inputs = nil, dependencies = nil, bindings = nil)
|
15
15
|
path = Path.setup(Misc.sanitize_filename(path)) if String === path
|
16
|
+
pat = path.call if Proc === path
|
16
17
|
@path = path
|
17
18
|
@task = task
|
18
19
|
@bindings = bindings
|
@@ -25,6 +26,7 @@ class Step
|
|
25
26
|
[dependencies]
|
26
27
|
end
|
27
28
|
@mutex = Mutex.new
|
29
|
+
@info_mutex = Mutex.new
|
28
30
|
@inputs = inputs || []
|
29
31
|
end
|
30
32
|
|
@@ -59,6 +61,7 @@ class Step
|
|
59
61
|
end
|
60
62
|
|
61
63
|
def prepare_result(value, description = nil, info = {})
|
64
|
+
#info = self.info
|
62
65
|
case
|
63
66
|
when IO === value
|
64
67
|
begin
|
@@ -98,8 +101,7 @@ class Step
|
|
98
101
|
def get_stream
|
99
102
|
@mutex.synchronize do
|
100
103
|
begin
|
101
|
-
|
102
|
-
IO === res ? res : nil
|
104
|
+
IO === @result ? @result : nil
|
103
105
|
ensure
|
104
106
|
@result = nil
|
105
107
|
end
|
@@ -112,6 +114,7 @@ class Step
|
|
112
114
|
end
|
113
115
|
|
114
116
|
def exec(no_load=false)
|
117
|
+
dependencies.each{|dependency| dependency.exec(no_load) }
|
115
118
|
@result = _exec
|
116
119
|
@result = @result.stream if TSV::Dumper === @result
|
117
120
|
no_load ? @result : prepare_result(@result, @task.result_description)
|
@@ -120,17 +123,17 @@ class Step
|
|
120
123
|
def join
|
121
124
|
stream = get_stream
|
122
125
|
begin
|
123
|
-
|
126
|
+
Misc.consume_stream stream if stream
|
124
127
|
rescue
|
125
128
|
stream.abort if stream.respond_to? :abort
|
126
129
|
raise $!
|
127
130
|
ensure
|
128
|
-
stream.join if stream.respond_to? :join
|
131
|
+
stream.join if stream.respond_to? :join and not stream.joined?
|
129
132
|
end
|
130
133
|
|
131
|
-
dependencies.each{|dep| dep.join }
|
132
134
|
|
133
135
|
if @pid.nil?
|
136
|
+
dependencies.each{|dep| dep.join }
|
134
137
|
self
|
135
138
|
else
|
136
139
|
begin
|
@@ -140,8 +143,9 @@ class Step
|
|
140
143
|
Log.debug{"Process #{ @pid } already finished: #{ path }"}
|
141
144
|
end if Misc.pid_exists? @pid
|
142
145
|
@pid = nil
|
146
|
+
dependencies.each{|dep| dep.join }
|
147
|
+
self
|
143
148
|
end
|
144
|
-
self
|
145
149
|
end
|
146
150
|
|
147
151
|
def checks
|
@@ -150,110 +154,113 @@ class Step
|
|
150
154
|
|
151
155
|
def run(no_load = false)
|
152
156
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
157
|
+
@mutex.synchronize do
|
158
|
+
result = Persist.persist "Job", @task.result_type, :file => path, :check => checks, :no_load => no_load ? :stream : false do
|
159
|
+
if Step === Step.log_relay_step and not self == Step.log_relay_step
|
160
|
+
relay_log(Step.log_relay_step) unless self.respond_to? :relay_step and self.relay_step
|
161
|
+
end
|
162
|
+
@exec = false
|
163
|
+
|
164
|
+
Open.rm info_file if Open.exists? info_file
|
165
|
+
|
166
|
+
set_info :pid, Process.pid
|
167
|
+
set_info :issued, Time.now
|
168
|
+
|
169
|
+
log(:preparing, "Preparing job: #{Misc.fingerprint dependencies}")
|
170
|
+
set_info :dependencies, dependencies.collect{|dep| [dep.task_name, dep.name]}
|
171
|
+
seen_deps = []
|
172
|
+
dependencies.uniq.each{|dependency|
|
173
|
+
Log.info "#{Log.color :magenta, "Checking dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""}"
|
174
|
+
begin
|
175
|
+
next if seen_deps.include? dependency.path
|
176
|
+
dependency.relay_log self
|
177
|
+
dependency.clean if not dependency.done? and dependency.error?
|
178
|
+
dependency.clean if dependency.streaming? and not dependency.running?
|
179
|
+
dependency.run true unless dependency.result
|
180
|
+
seen_deps.concat dependency.rec_dependencies.collect{|d| d.path}
|
181
|
+
rescue Exception
|
182
|
+
backtrace = $!.backtrace
|
183
|
+
set_info :backtrace, backtrace
|
184
|
+
log(:error, "Exception processing dependency #{Log.color :yellow, dependency.task.name.to_s} -- #{$!.class}: #{$!.message}")
|
185
|
+
raise $!
|
186
|
+
end
|
187
|
+
}
|
158
188
|
|
159
|
-
|
189
|
+
set_info :inputs, Misc.remove_long_items(Misc.zip2hash(task.inputs, @inputs)) unless task.inputs.nil?
|
160
190
|
|
161
|
-
|
162
|
-
|
191
|
+
set_info :started, (start_time = Time.now)
|
192
|
+
log :started, "#{Log.color :green, "Starting task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
|
163
193
|
|
164
|
-
set_info :dependencies, dependencies.collect{|dep| [dep.task.name, dep.name]}
|
165
|
-
log(:preparing, "Preparing job")
|
166
|
-
seen_deps = []
|
167
|
-
dependencies.each{|dependency|
|
168
|
-
Log.info "#{Log.color :magenta, "Checking dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task.name.to_s || ""}"
|
169
194
|
begin
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
195
|
+
result = _exec
|
196
|
+
rescue Aborted
|
197
|
+
log(:error, "Aborted")
|
198
|
+
|
199
|
+
children_pids = info[:children_pids]
|
200
|
+
if children_pids and children_pids.any?
|
201
|
+
Log.medium("Killing children: #{ children_pids * ", " }")
|
202
|
+
children_pids.each do |pid|
|
203
|
+
Log.medium("Killing child #{ pid }")
|
204
|
+
begin
|
205
|
+
Process.kill "INT", pid
|
206
|
+
rescue Exception
|
207
|
+
Log.medium("Exception killing child #{ pid }: #{$!.message}")
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
raise $!
|
175
213
|
rescue Exception
|
176
214
|
backtrace = $!.backtrace
|
215
|
+
|
216
|
+
# HACK: This fixes an strange behaviour in 1.9.3 where some
|
217
|
+
# backtrace strings are coded in ASCII-8BIT
|
218
|
+
backtrace.each{|l| l.force_encoding("UTF-8")} if String.instance_methods.include? :force_encoding
|
219
|
+
|
177
220
|
set_info :backtrace, backtrace
|
178
|
-
log(:error, "
|
221
|
+
log(:error, "#{$!.class}: #{$!.message}")
|
179
222
|
raise $!
|
180
223
|
end
|
181
|
-
}
|
182
|
-
|
183
|
-
set_info :inputs, Misc.remove_long_items(Misc.zip2hash(task.inputs, @inputs)) unless task.inputs.nil?
|
184
224
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
225
|
+
case result
|
226
|
+
when IO
|
227
|
+
log :streaming, "#{Log.color :magenta, "Streaming task result IO"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
|
228
|
+
ConcurrentStream.setup result do
|
229
|
+
begin
|
230
|
+
set_info :done, (done_time = Time.now)
|
231
|
+
set_info :time_elapsed, (time_elapsed = done_time - start_time)
|
232
|
+
log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i} -- #{path}"
|
233
|
+
rescue
|
234
|
+
Log.exception $!
|
235
|
+
end
|
236
|
+
end
|
237
|
+
when TSV::Dumper
|
238
|
+
log :streaming, "#{Log.color :magenta, "Streaming task result TSV::Dumper"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
|
239
|
+
ConcurrentStream.setup result.stream do
|
198
240
|
begin
|
199
|
-
|
200
|
-
|
201
|
-
|
241
|
+
set_info :done, (done_time = Time.now)
|
242
|
+
set_info :done, (done_time = Time.now)
|
243
|
+
set_info :time_elapsed, (time_elapsed = done_time - start_time)
|
244
|
+
log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i} -- #{path}"
|
245
|
+
rescue
|
246
|
+
Log.exception $!
|
202
247
|
end
|
203
248
|
end
|
249
|
+
else
|
250
|
+
set_info :done, (done_time = Time.now)
|
251
|
+
set_info :time_elapsed, (time_elapsed = done_time - start_time)
|
252
|
+
log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i}"
|
204
253
|
end
|
205
254
|
|
206
|
-
|
207
|
-
rescue Exception
|
208
|
-
backtrace = $!.backtrace
|
209
|
-
|
210
|
-
# HACK: This fixes an strange behaviour in 1.9.3 where some
|
211
|
-
# backtrace strings are coded in ASCII-8BIT
|
212
|
-
backtrace.each{|l| l.force_encoding("UTF-8")} if String.instance_methods.include? :force_encoding
|
213
|
-
|
214
|
-
set_info :backtrace, backtrace
|
215
|
-
log(:error, "#{$!.class}: #{$!.message}")
|
216
|
-
raise $!
|
255
|
+
result
|
217
256
|
end
|
218
257
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
ConcurrentStream.setup result do
|
223
|
-
begin
|
224
|
-
set_info :done, (done_time = Time.now)
|
225
|
-
set_info :time_elapsed, (time_elapsed = done_time - start_time)
|
226
|
-
log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i}"
|
227
|
-
rescue
|
228
|
-
Log.exception $!
|
229
|
-
end
|
230
|
-
end
|
231
|
-
when TSV::Dumper
|
232
|
-
log :streaming, "#{Log.color :magenta, "Streaming task result TSV::Dumper"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
|
233
|
-
ConcurrentStream.setup result.stream do
|
234
|
-
begin
|
235
|
-
set_info :done, (done_time = Time.now)
|
236
|
-
set_info :done, (done_time = Time.now)
|
237
|
-
set_info :time_elapsed, (time_elapsed = done_time - start_time)
|
238
|
-
log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i}"
|
239
|
-
rescue
|
240
|
-
Log.exception $!
|
241
|
-
end
|
242
|
-
end
|
258
|
+
if no_load
|
259
|
+
@result ||= result
|
260
|
+
self
|
243
261
|
else
|
244
|
-
|
245
|
-
set_info :time_elapsed, (time_elapsed = done_time - start_time)
|
246
|
-
log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i}"
|
262
|
+
@result = prepare_result result, @task.result_description
|
247
263
|
end
|
248
|
-
|
249
|
-
result
|
250
|
-
end
|
251
|
-
|
252
|
-
if no_load
|
253
|
-
@result = result
|
254
|
-
self
|
255
|
-
else
|
256
|
-
@result = prepare_result result, @task.result_description, info
|
257
264
|
end
|
258
265
|
end
|
259
266
|
|
@@ -266,11 +273,10 @@ class Step
|
|
266
273
|
begin
|
267
274
|
res = run(true)
|
268
275
|
io = get_stream
|
269
|
-
#io = res.result if IO === res.result
|
270
|
-
#io = res.result.stream if TSV::Dumper === res.result
|
271
276
|
if IO === io
|
272
|
-
io
|
273
|
-
io.
|
277
|
+
Misc.consume_stream(io)
|
278
|
+
io.close unless io.closed?
|
279
|
+
io.join if io.respond_to? :join and not io.joined?
|
274
280
|
end
|
275
281
|
rescue Aborted
|
276
282
|
Log.debug{"Forked process aborted: #{path}"}
|
@@ -363,6 +369,9 @@ class Step
|
|
363
369
|
rescue Exception
|
364
370
|
end
|
365
371
|
|
372
|
+
@result = nil
|
373
|
+
@pid = nil
|
374
|
+
|
366
375
|
begin
|
367
376
|
Open.rm info_file if Open.exists? info_file
|
368
377
|
Open.rm info_file + '.lock' if Open.exists? info_file + '.lock'
|
@@ -378,14 +387,17 @@ class Step
|
|
378
387
|
|
379
388
|
# A step result with no info_file means that it was manually
|
380
389
|
# placed. In that case, do not consider its dependencies
|
381
|
-
return [] if self.
|
390
|
+
return [] if Open.exists?(self.path.to_s) and not Open.exists? self.info_file
|
382
391
|
|
383
392
|
return [] if dependencies.nil? or dependencies.empty?
|
384
393
|
new_dependencies = dependencies.collect{|step|
|
385
394
|
step.rec_dependencies
|
386
|
-
}.flatten
|
395
|
+
}.flatten.uniq.compact
|
387
396
|
|
388
|
-
dependencies + new_dependencies
|
397
|
+
dependencies = self.dependencies ? self.dependencies + new_dependencies : new_dependencies
|
398
|
+
dependencies.flatten!
|
399
|
+
dependencies.uniq!
|
400
|
+
dependencies
|
389
401
|
end
|
390
402
|
|
391
403
|
def recursive_clean
|
@@ -398,7 +410,8 @@ class Step
|
|
398
410
|
end
|
399
411
|
|
400
412
|
def step(name)
|
401
|
-
|
413
|
+
@steps ||= {}
|
414
|
+
@steps[name] ||= rec_dependencies.select do |step|
|
402
415
|
step.task_name.to_sym == name.to_sym
|
403
416
|
end.first
|
404
417
|
end
|
@@ -81,7 +81,7 @@ def fix_options(workflow, task, job_options)
|
|
81
81
|
job_options.each do |name, value|
|
82
82
|
value = case input_types[name].to_sym
|
83
83
|
when :boolean
|
84
|
-
TrueClass
|
84
|
+
TrueClass === value or %w(true TRUE T yes).include? value
|
85
85
|
when :float
|
86
86
|
value.to_f
|
87
87
|
when :integer
|
@@ -322,7 +322,7 @@ begin
|
|
322
322
|
|
323
323
|
if options.delete(:provenance)
|
324
324
|
job.join
|
325
|
-
pp job.
|
325
|
+
pp job.provenance_paths
|
326
326
|
exit 0
|
327
327
|
end
|
328
328
|
|
data/test/rbbt/util/test_log.rb
CHANGED
@@ -2,6 +2,14 @@ require File.join(File.expand_path(File.dirname(__FILE__)), '../..', 'test_helpe
|
|
2
2
|
require 'rbbt/util/log'
|
3
3
|
|
4
4
|
class TestLog < Test::Unit::TestCase
|
5
|
+
def test_get_level
|
6
|
+
assert_equal 0, Log.get_level(:debug)
|
7
|
+
assert_equal 1, Log.get_level(:low)
|
8
|
+
assert_equal 1, Log.get_level("LOW")
|
9
|
+
assert_equal 1, Log.get_level(1)
|
10
|
+
assert_equal 0, Log.get_level(nil)
|
11
|
+
end
|
12
|
+
|
5
13
|
def test_color
|
6
14
|
assert Log.color(:green, "green")
|
7
15
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbbt-util
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.11.
|
4
|
+
version: 5.11.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miguel Vazquez
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|