rbbt-util 5.11.1 → 5.11.2

Sign up to get free protection for your applications and to get access to all the features.
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