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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ee7693bddd82af53509c8ed2e5414f1a86ac51ce
4
- data.tar.gz: 5122a7d8c8404d7a045e571310cfb34c3e808bbe
3
+ metadata.gz: 06c3a98f22b69a5738d6c9b478a2cee9a4e52e66
4
+ data.tar.gz: d60e07e6371c2c6c88359d6b028e7c7fdcbd0c64
5
5
  SHA512:
6
- metadata.gz: e75a716cf8fd069b161d3f167217b0a329eac88d1458e6133fdbc0b3e51cfcd647e6c53cf2e4cbe9a28ab5499e2822138797688eb75239fffe458975195b6ad3
7
- data.tar.gz: ae968a716ff89c35ba2a07300ac56cba42452692a75e2b811051d360fd64ce51c4f95aba36a9d974234450cdfdab846ddd31a367383a41ac80b1b49f177ac303
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
- saver_pid = Process.fork do
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
- Kernel.exit! -1
214
+ stream.abort if stream.respond_to? :abort
215
+ parent.raise $!
192
216
  end
193
- Kernel.exit! 0
194
217
  end
195
- file.close
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.tee_stream_thread(stream, path, type, callback = nil)
200
- file, out = Misc.tee_stream(stream)
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
- Thread.current["name"] = "file saver: " + path
205
- Misc.lock(path) do
206
- save_file(path, type, file)
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
- Log.error "Tee stream thread aborted"
210
- stream.abort if stream.respond_to? :abort
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
- stream.abort if stream.respond_to? :abort
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
- parent.raise $!
270
+ Process.kill :INT, parent_pid
271
+ Kernel.exit! -1
215
272
  end
216
273
  end
217
- ConcurrentStream.setup(out, :threads => saver_thread, :filename => path)
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
- lockfile.unlock
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
- lockfile.unlock
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.high "Error in persist: #{path}#{Open.exists?(path) ? Log.color(:red, " Erasing") : ""}"
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, options.merge(:repo => repo, :persist => true, :file => file), &block
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, StringIO
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
- raise Aborted
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
- traverse_obj(obj, options) do |*p|
195
- q.process *p
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
- into = options[:into]
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
- case obj.result
247
- when IO
248
- close_streams << obj.result
249
- when TSV::Dumper
250
- close_streams << obj.result.in_stream
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
- sin.abort if sin.respond_to? :abort
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, StringIO
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
 
@@ -37,7 +37,7 @@ class RbbtProcessQueue
37
37
  end
38
38
 
39
39
  write_length = str.length
40
- IO.select(nil, [stream])
40
+ #IO.select(nil, [stream])
41
41
  wrote = stream.write(str)
42
42
  while wrote < write_length
43
43
  wrote += stream.write(str[wrote..-1])
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
- DEBUG = 0
8
- LOW = 1
9
- MEDIUM = 2
10
- HIGH = 3
11
- INFO = 4
12
- WARN = 5
13
- ERROR = 6
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.color(severity, str = nil)
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 = SEVERITY_COLOR[severity] if Fixnum === severity
48
- color = Term::ANSIColor.send(severity) if Symbol === severity and Term::ANSIColor.respond_to? severity
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(message, file = $stdout)
161
- stack = caller
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(message, file = $stdout)
169
- stack = caller
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(message, file = $stdout)
177
- stack = caller
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 hhh(message, file = $stdout)
185
- stack = caller
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 iii(message, file = $stdout)
193
- stack = caller
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(message, file = $stdout)
201
- stack = caller
202
- Log.error{"#{Log.color :cyan, "INFO:"} " << stack.first}
203
- Log.error{""}
204
- Log.error{"=> " << message.inspect}
205
- Log.error{""}
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
@@ -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 unless sin.closed?
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
- begin
1314
- Misc.insist 3 do
1315
- if File.exists? lock_path and
1316
- Misc.hostname == (info = Open.open(lock_path){|f| YAML.load(f) })["host"] and
1317
- info["pid"] and not Misc.pid_exists?(info["pid"])
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
- Log.info("Removing lockfile: #{lock_path}. This pid #{Process.pid}. Content: #{info.inspect}")
1320
- FileUtils.rm lock_path
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
- step = Step.new step_path, task, input_values, dependencies
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
- Step.new path, tasks[task.to_sym]
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
- Step.new path, task
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
- return @info_cache if @info_cache and File.mtime(info_file) < @info_cache_time
46
- rescue Exception
47
- end
48
- begin
49
- @info_cache = Misc.insist(3, 5, info_file) do
50
- Misc.insist(2, 2, info_file) do
51
- Misc.insist(2, 0.5, info_file) do
52
- Open.open(info_file) do |file|
53
- INFO_SERIALIAZER.load(file) || {}
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 #File === value ? value.filename : 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
@@ -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
- res = @result
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
- stream.read if stream
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
- result = Persist.persist "Job", @task.result_type, :file => path, :check => checks, :no_load => no_load ? :stream : false do
154
- if Step === Step.log_relay_step and not self == Step.log_relay_step
155
- relay_log(Step.log_relay_step) unless self.respond_to? :relay_step and self.relay_step
156
- end
157
- @exec = false
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
- Open.rm info_file if Open.exists? info_file
189
+ set_info :inputs, Misc.remove_long_items(Misc.zip2hash(task.inputs, @inputs)) unless task.inputs.nil?
160
190
 
161
- set_info :pid, Process.pid
162
- set_info :issued, Time.now
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
- next if seen_deps.include? dependency.path
171
- dependency.relay_log self
172
- dependency.clean if not dependency.done? and dependency.error?
173
- dependency.run true unless dependency.done?
174
- seen_deps.concat dependency.rec_dependencies.collect{|d| d.path}
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, "Exception processing dependency #{Log.color :yellow, dependency.task.name.to_s} -- #{$!.class}: #{$!.message}")
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
- set_info :started, (start_time = Time.now)
186
- log :started, "#{Log.color :green, "Starting task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
187
-
188
- begin
189
- result = _exec
190
- rescue Aborted
191
- log(:error, "Aborted")
192
-
193
- children_pids = info[:children_pids]
194
- if children_pids and children_pids.any?
195
- Log.medium("Killing children: #{ children_pids * ", " }")
196
- children_pids.each do |pid|
197
- Log.medium("Killing child #{ pid }")
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
- Process.kill "INT", pid
200
- rescue Exception
201
- Log.medium("Exception killing child #{ pid }: #{$!.message}")
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
- raise $!
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
- case result
220
- when IO
221
- log :streaming, "#{Log.color :magenta, "Streaming task result IO"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
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
- set_info :done, (done_time = Time.now)
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.read
273
- io.join if io.respond_to? :join
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.done? and not Open.exists? self.info_file
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
- rec_dependencies.select do |step|
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 == value or %w(true TRUE T yes).include? value
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.provenance
325
+ pp job.provenance_paths
326
326
  exit 0
327
327
  end
328
328
 
@@ -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.1
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-05 00:00:00.000000000 Z
11
+ date: 2014-04-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake