rbbt-util 5.32.16 → 5.32.21
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/hpc/slurm.rb +1 -0
- data/lib/rbbt/resource/path.rb +6 -6
- data/lib/rbbt/tsv/parallel/traverse.rb +1 -1
- data/lib/rbbt/util/log.rb +15 -4
- data/lib/rbbt/util/misc/inspect.rb +3 -1
- data/lib/rbbt/util/open.rb +1 -0
- data/lib/rbbt/workflow.rb +43 -1
- data/lib/rbbt/workflow/accessor.rb +15 -242
- data/lib/rbbt/workflow/definition.rb +7 -4
- data/lib/rbbt/workflow/dependencies.rb +196 -0
- data/lib/rbbt/workflow/step.rb +4 -184
- data/lib/rbbt/workflow/step/accessor.rb +1 -311
- data/lib/rbbt/workflow/step/dependencies.rb +75 -3
- data/lib/rbbt/workflow/step/info.rb +294 -0
- data/lib/rbbt/workflow/step/status.rb +146 -0
- data/lib/rbbt/workflow/usage.rb +4 -2
- data/lib/rbbt/workflow/util/orchestrator.rb +1 -1
- data/lib/rbbt/workflow/util/provenance.rb +16 -4
- data/share/rbbt_commands/system/clean +1 -0
- data/share/rbbt_commands/workflow/prov +1 -1
- metadata +5 -2
|
@@ -26,6 +26,7 @@ class Step
|
|
|
26
26
|
threads = jobs.collect do |j|
|
|
27
27
|
Thread.new do
|
|
28
28
|
begin
|
|
29
|
+
j.soft_grace
|
|
29
30
|
j.join unless j.done?
|
|
30
31
|
rescue Exception
|
|
31
32
|
Log.error "Exception waiting for job: #{Log.color :blue, j.path}"
|
|
@@ -206,45 +207,6 @@ class Step
|
|
|
206
207
|
#@status_lock
|
|
207
208
|
end
|
|
208
209
|
|
|
209
|
-
def info(check_lock = true)
|
|
210
|
-
return {:status => :noinfo} if info_file.nil? or not Open.exists? info_file
|
|
211
|
-
begin
|
|
212
|
-
Misc.insist do
|
|
213
|
-
begin
|
|
214
|
-
return @info_cache if @info_cache and @info_cache_time and Open.ctime(info_file) < @info_cache_time
|
|
215
|
-
rescue Exception
|
|
216
|
-
raise $!
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
begin
|
|
220
|
-
@info_cache = Misc.insist(3, 1.6, info_file) do
|
|
221
|
-
Misc.insist(2, 1, info_file) do
|
|
222
|
-
Misc.insist(3, 0.2, info_file) do
|
|
223
|
-
raise TryAgain, "Info locked" if check_lock and info_lock.locked?
|
|
224
|
-
info_lock.lock if check_lock and false
|
|
225
|
-
begin
|
|
226
|
-
Open.open(info_file, :mode => 'rb') do |file|
|
|
227
|
-
Step.load_serialized_info(file)
|
|
228
|
-
end
|
|
229
|
-
ensure
|
|
230
|
-
info_lock.unlock if check_lock and false
|
|
231
|
-
end
|
|
232
|
-
end
|
|
233
|
-
end
|
|
234
|
-
end
|
|
235
|
-
@info_cache_time = Time.now
|
|
236
|
-
@info_cache
|
|
237
|
-
end
|
|
238
|
-
end
|
|
239
|
-
rescue Exception
|
|
240
|
-
Log.debug{"Error loading info file: " + info_file}
|
|
241
|
-
Log.exception $!
|
|
242
|
-
Open.rm info_file
|
|
243
|
-
Misc.sensiblewrite(info_file, Step.serialize_info({:status => :error, :messages => ["Info file lost"]}))
|
|
244
|
-
raise $!
|
|
245
|
-
end
|
|
246
|
-
end
|
|
247
|
-
|
|
248
210
|
def init_info(force = false)
|
|
249
211
|
return nil if @exec || info_file.nil? || (Open.exists?(info_file) && ! force)
|
|
250
212
|
Open.lock(info_file, :lock => info_lock) do
|
|
@@ -286,274 +248,6 @@ class Step
|
|
|
286
248
|
end
|
|
287
249
|
end
|
|
288
250
|
|
|
289
|
-
def status
|
|
290
|
-
begin
|
|
291
|
-
info[:status]
|
|
292
|
-
rescue Exception
|
|
293
|
-
Log.error "Exception reading status: #{$!.message}"
|
|
294
|
-
:error
|
|
295
|
-
end
|
|
296
|
-
end
|
|
297
|
-
|
|
298
|
-
def status=(status)
|
|
299
|
-
set_info(:status, status)
|
|
300
|
-
end
|
|
301
|
-
|
|
302
|
-
def messages
|
|
303
|
-
if messages = info[:messages]
|
|
304
|
-
messages
|
|
305
|
-
else
|
|
306
|
-
set_info(:messages, []) if self.respond_to?(:set_info)
|
|
307
|
-
end
|
|
308
|
-
end
|
|
309
|
-
|
|
310
|
-
def message(message)
|
|
311
|
-
message = Log.uncolor(message)
|
|
312
|
-
set_info(:messages, (messages || []) << message)
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
def self.status_color(status)
|
|
316
|
-
status = status.split(">").last
|
|
317
|
-
case status
|
|
318
|
-
when "starting"
|
|
319
|
-
:yellow
|
|
320
|
-
when "error", "aborted"
|
|
321
|
-
:red
|
|
322
|
-
when "done"
|
|
323
|
-
:green
|
|
324
|
-
else
|
|
325
|
-
:cyan
|
|
326
|
-
end
|
|
327
|
-
end
|
|
328
|
-
|
|
329
|
-
def self.log_block(status, message, path, &block)
|
|
330
|
-
start = Time.now
|
|
331
|
-
status = status.to_s
|
|
332
|
-
status_color = self.status_color status
|
|
333
|
-
|
|
334
|
-
Log.info do
|
|
335
|
-
now = Time.now
|
|
336
|
-
str = Log.color :reset
|
|
337
|
-
str << "#{ Log.color status_color, status}"
|
|
338
|
-
str << ": #{ message }" if message and message != :result
|
|
339
|
-
str << " -- #{Log.color :blue, path.to_s}" if path
|
|
340
|
-
str << " #{Log.color :yellow, Process.pid}"
|
|
341
|
-
str
|
|
342
|
-
end
|
|
343
|
-
res = yield
|
|
344
|
-
eend = Time.now
|
|
345
|
-
Log.info do
|
|
346
|
-
now = Time.now
|
|
347
|
-
str = "#{ Log.color :cyan, status.to_s } +#{Log.color :green, "%.2f" % (eend - start)}"
|
|
348
|
-
str << ": #{ res }" if message == :result
|
|
349
|
-
str << " -- #{Log.color :blue, path.to_s}" if path
|
|
350
|
-
str << " #{Log.color :yellow, Process.pid}"
|
|
351
|
-
str
|
|
352
|
-
end
|
|
353
|
-
res
|
|
354
|
-
end
|
|
355
|
-
|
|
356
|
-
def self.log_string(status, message, path)
|
|
357
|
-
Log.info do
|
|
358
|
-
|
|
359
|
-
status = status.to_s
|
|
360
|
-
status_color = self.status_color status
|
|
361
|
-
|
|
362
|
-
str = Log.color :reset
|
|
363
|
-
str << "#{ Log.color status_color, status}"
|
|
364
|
-
str << ": #{ message }" if message
|
|
365
|
-
str << " -- #{Log.color :blue, path.to_s}" if path
|
|
366
|
-
str << " #{Log.color :yellow, Process.pid}"
|
|
367
|
-
str
|
|
368
|
-
end
|
|
369
|
-
end
|
|
370
|
-
|
|
371
|
-
def self.log_progress(status, options = {}, path = nil, &block)
|
|
372
|
-
options = Misc.add_defaults options, :severity => Log::INFO, :file => (@exec ? nil : path)
|
|
373
|
-
max = Misc.process_options options, :max
|
|
374
|
-
Log::ProgressBar.with_bar(max, options) do |bar|
|
|
375
|
-
begin
|
|
376
|
-
res = yield bar
|
|
377
|
-
raise KeepBar.new res if IO === res
|
|
378
|
-
res
|
|
379
|
-
rescue
|
|
380
|
-
Log.exception $!
|
|
381
|
-
raise $!
|
|
382
|
-
end
|
|
383
|
-
end
|
|
384
|
-
end
|
|
385
|
-
|
|
386
|
-
def log_progress(status, options = {}, &block)
|
|
387
|
-
Step.log_progress(status, options, file(:progress), &block)
|
|
388
|
-
end
|
|
389
|
-
|
|
390
|
-
def progress_bar(msg = "Progress", options = nil)
|
|
391
|
-
if Hash === msg and options.nil?
|
|
392
|
-
options = msg
|
|
393
|
-
msg = nil
|
|
394
|
-
end
|
|
395
|
-
options = {} if options.nil?
|
|
396
|
-
|
|
397
|
-
max = options[:max]
|
|
398
|
-
Log::ProgressBar.new_bar(max, {:desc => msg, :file => (@exec ? nil : file(:progress))}.merge(options))
|
|
399
|
-
end
|
|
400
|
-
|
|
401
|
-
def self.log(status, message, path, &block)
|
|
402
|
-
if block
|
|
403
|
-
if Hash === message
|
|
404
|
-
log_progress(status, message, path, &block)
|
|
405
|
-
else
|
|
406
|
-
log_block(status, message, path, &block)
|
|
407
|
-
end
|
|
408
|
-
else
|
|
409
|
-
log_string(status, message, path)
|
|
410
|
-
end
|
|
411
|
-
end
|
|
412
|
-
|
|
413
|
-
def log(status, message = nil, &block)
|
|
414
|
-
self.status = status
|
|
415
|
-
if message
|
|
416
|
-
self.message Log.uncolor(message)
|
|
417
|
-
end
|
|
418
|
-
Step.log(status, message, path, &block)
|
|
419
|
-
end
|
|
420
|
-
|
|
421
|
-
def exception(ex, msg = nil)
|
|
422
|
-
ex_class = ex.class.to_s
|
|
423
|
-
backtrace = ex.backtrace if ex.respond_to?(:backtrace)
|
|
424
|
-
message = ex.message if ex.respond_to?(:message)
|
|
425
|
-
set_info :backtrace, backtrace
|
|
426
|
-
set_info :exception, {:class => ex_class, :message => message, :backtrace => backtrace}
|
|
427
|
-
if msg.nil?
|
|
428
|
-
log :error, "#{ex_class} -- #{message}"
|
|
429
|
-
else
|
|
430
|
-
log :error, "#{msg} -- #{message}"
|
|
431
|
-
end
|
|
432
|
-
self._abort
|
|
433
|
-
end
|
|
434
|
-
|
|
435
|
-
def get_exception
|
|
436
|
-
if info[:exception].nil?
|
|
437
|
-
return Aborted if aborted?
|
|
438
|
-
return Exception.new(messages.last) if error?
|
|
439
|
-
Exception.new ""
|
|
440
|
-
else
|
|
441
|
-
ex_class, ex_message, ex_backtrace = info[:exception].values_at :class, :message, :backtrace
|
|
442
|
-
begin
|
|
443
|
-
klass = Kernel.const_get(ex_class)
|
|
444
|
-
ex = klass.new ex_message
|
|
445
|
-
ex.set_backtrace ex_backtrace unless ex_backtrace.nil? or ex_backtrace.empty?
|
|
446
|
-
ex
|
|
447
|
-
rescue
|
|
448
|
-
Log.exception $!
|
|
449
|
-
Exception.new ex_message
|
|
450
|
-
end
|
|
451
|
-
end
|
|
452
|
-
end
|
|
453
|
-
|
|
454
|
-
def recoverable_error?
|
|
455
|
-
return true if aborted?
|
|
456
|
-
return false unless error?
|
|
457
|
-
begin
|
|
458
|
-
return true unless info[:exception]
|
|
459
|
-
klass = Kernel.const_get(info[:exception][:class])
|
|
460
|
-
! (klass <= RbbtException)
|
|
461
|
-
rescue Exception
|
|
462
|
-
true
|
|
463
|
-
end
|
|
464
|
-
end
|
|
465
|
-
|
|
466
|
-
def started?
|
|
467
|
-
Open.exists?(path) or (Open.exists?(pid_file) && Open.exists?(info_file))
|
|
468
|
-
end
|
|
469
|
-
|
|
470
|
-
def waiting?
|
|
471
|
-
Open.exists?(info_file) and not started?
|
|
472
|
-
end
|
|
473
|
-
|
|
474
|
-
def dirty_files
|
|
475
|
-
rec_dependencies = self.rec_dependencies(true)
|
|
476
|
-
return [] if rec_dependencies.empty?
|
|
477
|
-
canfail_paths = self.canfail_paths
|
|
478
|
-
|
|
479
|
-
dirty_files = rec_dependencies.reject{|dep|
|
|
480
|
-
(defined?(WorkflowRemoteClient) && WorkflowRemoteClient::RemoteStep === dep) ||
|
|
481
|
-
! Open.exists?(dep.info_file) ||
|
|
482
|
-
(dep.path && (Open.exists?(dep.path) || Open.remote?(dep.path))) ||
|
|
483
|
-
((dep.error? || dep.aborted?) && (! dep.recoverable_error? || canfail_paths.include?(dep.path)))
|
|
484
|
-
}
|
|
485
|
-
end
|
|
486
|
-
|
|
487
|
-
def dirty?
|
|
488
|
-
return true if Open.exists?(pid_file) && ! ( Open.exists?(info_file) || done? )
|
|
489
|
-
return false unless done? || status == :done
|
|
490
|
-
return false unless ENV["RBBT_UPDATE"] == "true"
|
|
491
|
-
|
|
492
|
-
status = self.status
|
|
493
|
-
|
|
494
|
-
if done? and not (status == :done or status == :ending or status == :producing) and not status == :noinfo
|
|
495
|
-
return true
|
|
496
|
-
end
|
|
497
|
-
|
|
498
|
-
if status == :done and not done?
|
|
499
|
-
return true
|
|
500
|
-
end
|
|
501
|
-
|
|
502
|
-
if dirty_files.any?
|
|
503
|
-
Log.low "Some dirty files found for #{self.path}: #{Misc.fingerprint dirty_files}"
|
|
504
|
-
true
|
|
505
|
-
else
|
|
506
|
-
! self.updated?
|
|
507
|
-
end
|
|
508
|
-
end
|
|
509
|
-
|
|
510
|
-
def done?
|
|
511
|
-
path and Open.exists? path
|
|
512
|
-
end
|
|
513
|
-
|
|
514
|
-
def streaming?
|
|
515
|
-
(IO === @result) or (not @saved_stream.nil?) or status == :streaming
|
|
516
|
-
end
|
|
517
|
-
|
|
518
|
-
def noinfo?
|
|
519
|
-
status == :noinfo
|
|
520
|
-
end
|
|
521
|
-
|
|
522
|
-
def running?
|
|
523
|
-
return false if ! (started? || status == :ending)
|
|
524
|
-
return nil unless Open.exist?(self.pid_file)
|
|
525
|
-
pid = Open.read(self.pid_file).to_i
|
|
526
|
-
|
|
527
|
-
return false if done? or error? or aborted?
|
|
528
|
-
|
|
529
|
-
if Misc.pid_exists?(pid)
|
|
530
|
-
pid
|
|
531
|
-
else
|
|
532
|
-
done? or error? or aborted?
|
|
533
|
-
end
|
|
534
|
-
end
|
|
535
|
-
|
|
536
|
-
def stalled?
|
|
537
|
-
started? && ! (done? || running? || done? || error? || aborted?)
|
|
538
|
-
end
|
|
539
|
-
|
|
540
|
-
def missing?
|
|
541
|
-
status == :done && ! Open.exists?(path)
|
|
542
|
-
end
|
|
543
|
-
|
|
544
|
-
def error?
|
|
545
|
-
status == :error
|
|
546
|
-
end
|
|
547
|
-
|
|
548
|
-
def nopid?
|
|
549
|
-
! Open.exists?(pid_file) && ! (status.nil? || status == :aborted || status == :done || status == :error || status == :cleaned)
|
|
550
|
-
end
|
|
551
|
-
|
|
552
|
-
def aborted?
|
|
553
|
-
status = self.status
|
|
554
|
-
status == :aborted || ((status != :ending && status != :dependencies && status != :cleaned && status != :noinfo && status != :setup && status != :noinfo) && nopid?)
|
|
555
|
-
end
|
|
556
|
-
|
|
557
251
|
# {{{ INFO
|
|
558
252
|
|
|
559
253
|
def files_dir
|
|
@@ -650,10 +344,6 @@ class Step
|
|
|
650
344
|
provenance
|
|
651
345
|
end
|
|
652
346
|
|
|
653
|
-
def resumable?
|
|
654
|
-
task && task.resumable
|
|
655
|
-
end
|
|
656
|
-
|
|
657
347
|
def config(key, *tokens)
|
|
658
348
|
options = tokens.pop if Hash === tokens.last
|
|
659
349
|
options ||= {}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
class Step
|
|
3
2
|
|
|
4
3
|
STREAM_CACHE = {}
|
|
@@ -127,7 +126,7 @@ class Step
|
|
|
127
126
|
end
|
|
128
127
|
|
|
129
128
|
def input_dependencies
|
|
130
|
-
(
|
|
129
|
+
@input_dependencies ||= (recursive_inputs.flatten.select{|i| Step === i } + recursive_inputs.flatten.select{|dep| Path === dep && Step === dep.resource }.collect{|dep| dep.resource })
|
|
131
130
|
end
|
|
132
131
|
|
|
133
132
|
def execute_dependency(dependency, log = true)
|
|
@@ -207,7 +206,7 @@ class Step
|
|
|
207
206
|
if dup and step.streaming? and not step.result.nil?
|
|
208
207
|
if dep_step[step.path] and dep_step[step.path].length > 1
|
|
209
208
|
stream = step.result
|
|
210
|
-
other_steps = dep_step[step.path]
|
|
209
|
+
other_steps = dep_step[step.path].uniq.reject{|d| d.overriden }
|
|
211
210
|
return unless other_steps.length > 1
|
|
212
211
|
log_dependency_exec(step, "duplicating #{other_steps.length}")
|
|
213
212
|
copies = Misc.tee_stream_thread_multiple(stream, other_steps.length)
|
|
@@ -369,6 +368,7 @@ class Step
|
|
|
369
368
|
end
|
|
370
369
|
next unless step.dependencies and step.dependencies.any?
|
|
371
370
|
(step.dependencies + step.input_dependencies).each do |step_dep|
|
|
371
|
+
next unless step.dependencies.include?(step_dep)
|
|
372
372
|
next if step_dep.done? or step_dep.running? or (ComputeDependency === step_dep and (step_dep.compute == :nodup or step_dep.compute == :ignore))
|
|
373
373
|
dep_step[step_dep.path] ||= []
|
|
374
374
|
dep_step[step_dep.path] << step
|
|
@@ -483,4 +483,76 @@ class Step
|
|
|
483
483
|
kill_children
|
|
484
484
|
end
|
|
485
485
|
|
|
486
|
+
def overriden?
|
|
487
|
+
return true if @overriden
|
|
488
|
+
return true if dependencies.select{|dep| dep.overriden? }.any?
|
|
489
|
+
info[:archived_info].each do |f,i|
|
|
490
|
+
return true if i[:overriden] || i["overriden"]
|
|
491
|
+
end if info[:archived_info]
|
|
492
|
+
return false
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
def overriden
|
|
496
|
+
@overriden
|
|
497
|
+
#if @overriden.nil?
|
|
498
|
+
# return false if dependencies.nil?
|
|
499
|
+
# dependencies.select{|dep| dep.overriden? }.any?
|
|
500
|
+
#else
|
|
501
|
+
# @overriden
|
|
502
|
+
#end
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
def overriden_deps
|
|
506
|
+
ord = []
|
|
507
|
+
deps = dependencies.dup
|
|
508
|
+
while dep = deps.shift
|
|
509
|
+
case dep.overriden
|
|
510
|
+
when FalseClass
|
|
511
|
+
next
|
|
512
|
+
when Symbol
|
|
513
|
+
ord << dep
|
|
514
|
+
else
|
|
515
|
+
deps += dep.dependencies
|
|
516
|
+
end
|
|
517
|
+
end
|
|
518
|
+
ord
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
def dependencies=(dependencies)
|
|
522
|
+
@dependencies = dependencies
|
|
523
|
+
set_info :dependencies, dependencies.collect{|dep| [dep.task_name, dep.name, dep.path]} if dependencies
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
#connected = true means that dependency searching ends when a result is done
|
|
527
|
+
#but dependencies are absent, meanining that the file could have been dropped
|
|
528
|
+
#in
|
|
529
|
+
def rec_dependencies(connected = false, seen = [])
|
|
530
|
+
|
|
531
|
+
# A step result with no info_file means that it was manually
|
|
532
|
+
# placed. In that case, do not consider its dependencies
|
|
533
|
+
return [] if ! (defined? WorkflowRemoteClient && WorkflowRemoteClient::RemoteStep === self) && ! Open.exists?(self.info_file) && Open.exists?(self.path.to_s)
|
|
534
|
+
|
|
535
|
+
return [] if dependencies.nil? or dependencies.empty?
|
|
536
|
+
|
|
537
|
+
new_dependencies = []
|
|
538
|
+
if self.overriden?
|
|
539
|
+
archived_deps = []
|
|
540
|
+
else
|
|
541
|
+
archived_deps = self.info[:archived_info] ? self.info[:archived_info].keys : []
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
dependencies.each{|step|
|
|
545
|
+
#next if self.done? && Open.exists?(info_file) && info[:dependencies] && info[:dependencies].select{|task,name,path| path == step.path }.empty?
|
|
546
|
+
next if archived_deps.include? step.path
|
|
547
|
+
next if seen.include? step.path
|
|
548
|
+
next if self.done? && connected && ! updatable?
|
|
549
|
+
|
|
550
|
+
r = step.rec_dependencies(connected, new_dependencies.collect{|d| d.path})
|
|
551
|
+
new_dependencies.concat r
|
|
552
|
+
new_dependencies << step
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
new_dependencies.uniq
|
|
556
|
+
end
|
|
557
|
+
|
|
486
558
|
end
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
class Step
|
|
2
|
+
def info(check_lock = true)
|
|
3
|
+
return {:status => :noinfo} if info_file.nil? || ! Open.exists?(info_file)
|
|
4
|
+
|
|
5
|
+
begin
|
|
6
|
+
Misc.insist do
|
|
7
|
+
|
|
8
|
+
begin
|
|
9
|
+
return @info_cache if @info_cache and @info_cache_time and Open.ctime(info_file) < @info_cache_time
|
|
10
|
+
rescue Exception
|
|
11
|
+
raise $!
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
begin
|
|
16
|
+
@info_cache = Misc.insist(3, 1.6, info_file) do
|
|
17
|
+
Misc.insist(2, 1, info_file) do
|
|
18
|
+
Misc.insist(3, 0.2, info_file) do
|
|
19
|
+
raise TryAgain, "Info locked" if check_lock and info_lock.locked?
|
|
20
|
+
info_lock.lock if check_lock and false
|
|
21
|
+
begin
|
|
22
|
+
Open.open(info_file, :mode => 'rb') do |file|
|
|
23
|
+
Step.load_serialized_info(file)
|
|
24
|
+
end
|
|
25
|
+
ensure
|
|
26
|
+
info_lock.unlock if check_lock and false
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
@info_cache_time = Time.now
|
|
32
|
+
@info_cache
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
rescue Exception
|
|
36
|
+
Log.debug{"Error loading info file: " + info_file}
|
|
37
|
+
Log.exception $!
|
|
38
|
+
Open.rm info_file
|
|
39
|
+
Misc.sensiblewrite(info_file, Step.serialize_info({:status => :error, :messages => ["Info file lost"]}))
|
|
40
|
+
raise $!
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def load_inputs_from_info
|
|
45
|
+
if info[:inputs]
|
|
46
|
+
info_inputs = info[:inputs]
|
|
47
|
+
if task && task.respond_to?(:inputs) && task.inputs
|
|
48
|
+
IndiferentHash.setup info_inputs
|
|
49
|
+
@inputs = NamedArray.setup info_inputs.values_at(*task.inputs.collect{|name| name.to_s}), task.inputs
|
|
50
|
+
else
|
|
51
|
+
@inputs = NamedArray.setup info_inputs.values, info_inputs.keys
|
|
52
|
+
end
|
|
53
|
+
else
|
|
54
|
+
nil
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def load_dependencies_from_info
|
|
59
|
+
relocated = nil
|
|
60
|
+
@dependencies = (self.info[:dependencies] || []).collect do |task,name,dep_path|
|
|
61
|
+
if Open.exists?(dep_path) || Open.exists?(dep_path + '.info')
|
|
62
|
+
Workflow._load_step dep_path
|
|
63
|
+
else
|
|
64
|
+
next if FalseClass === relocated
|
|
65
|
+
new_path = Workflow.relocate(path, dep_path)
|
|
66
|
+
relocated = true if Open.exists?(new_path) || Open.exists?(new_path + '.info')
|
|
67
|
+
Workflow._load_step new_path
|
|
68
|
+
end
|
|
69
|
+
end.compact
|
|
70
|
+
@relocated = relocated
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def archive_deps
|
|
75
|
+
self.set_info :archived_info, archived_info
|
|
76
|
+
self.set_info :archived_dependencies, info[:dependencies]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def archived_info
|
|
80
|
+
return info[:archived_info] if info[:archived_info]
|
|
81
|
+
|
|
82
|
+
archived_info = {}
|
|
83
|
+
dependencies.each do |dep|
|
|
84
|
+
if Symbol === dep.overriden && ! Open.exists?(dep.info_file)
|
|
85
|
+
archived_info[dep.path] = dep.overriden
|
|
86
|
+
else
|
|
87
|
+
archived_info[dep.path] = dep.info
|
|
88
|
+
end
|
|
89
|
+
archived_info.merge!(dep.archived_info)
|
|
90
|
+
end if dependencies
|
|
91
|
+
|
|
92
|
+
archived_info
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def archived_inputs
|
|
96
|
+
return {} unless info[:archived_dependencies]
|
|
97
|
+
archived_info = self.archived_info
|
|
98
|
+
|
|
99
|
+
all_inputs = IndiferentHash.setup({})
|
|
100
|
+
deps = info[:archived_dependencies].collect{|p| p.last}
|
|
101
|
+
seen = []
|
|
102
|
+
while path = deps.pop
|
|
103
|
+
dep_info = archived_info[path]
|
|
104
|
+
if dep_info
|
|
105
|
+
dep_info[:inputs].each do |k,v|
|
|
106
|
+
all_inputs[k] = v unless all_inputs.include?(k)
|
|
107
|
+
end if dep_info[:inputs]
|
|
108
|
+
deps.concat(dep_info[:dependencies].collect{|p| p.last } - seen) if dep_info[:dependencies]
|
|
109
|
+
deps.concat(dep_info[:archived_dependencies].collect{|p| p.last } - seen) if dep_info[:archived_dependencies]
|
|
110
|
+
end
|
|
111
|
+
seen << path
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
all_inputs
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def status
|
|
118
|
+
begin
|
|
119
|
+
info[:status]
|
|
120
|
+
rescue Exception
|
|
121
|
+
Log.error "Exception reading status: #{$!.message}"
|
|
122
|
+
:error
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def status=(status)
|
|
127
|
+
set_info(:status, status)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def messages
|
|
131
|
+
if messages = info[:messages]
|
|
132
|
+
messages
|
|
133
|
+
else
|
|
134
|
+
set_info(:messages, []) if self.respond_to?(:set_info)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def message(message)
|
|
139
|
+
message = Log.uncolor(message)
|
|
140
|
+
set_info(:messages, (messages || []) << message)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def self.status_color(status)
|
|
144
|
+
status = status.split(">").last
|
|
145
|
+
case status
|
|
146
|
+
when "starting"
|
|
147
|
+
:yellow
|
|
148
|
+
when "error", "aborted"
|
|
149
|
+
:red
|
|
150
|
+
when "done"
|
|
151
|
+
:green
|
|
152
|
+
else
|
|
153
|
+
:cyan
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def self.log_block(status, message, path, &block)
|
|
158
|
+
start = Time.now
|
|
159
|
+
status = status.to_s
|
|
160
|
+
status_color = self.status_color status
|
|
161
|
+
|
|
162
|
+
Log.info do
|
|
163
|
+
now = Time.now
|
|
164
|
+
str = Log.color :reset
|
|
165
|
+
str << "#{ Log.color status_color, status}"
|
|
166
|
+
str << ": #{ message }" if message and message != :result
|
|
167
|
+
str << " -- #{Log.color :blue, path.to_s}" if path
|
|
168
|
+
str << " #{Log.color :yellow, Process.pid}"
|
|
169
|
+
str
|
|
170
|
+
end
|
|
171
|
+
res = yield
|
|
172
|
+
eend = Time.now
|
|
173
|
+
Log.info do
|
|
174
|
+
now = Time.now
|
|
175
|
+
str = "#{ Log.color :cyan, status.to_s } +#{Log.color :green, "%.2f" % (eend - start)}"
|
|
176
|
+
str << ": #{ res }" if message == :result
|
|
177
|
+
str << " -- #{Log.color :blue, path.to_s}" if path
|
|
178
|
+
str << " #{Log.color :yellow, Process.pid}"
|
|
179
|
+
str
|
|
180
|
+
end
|
|
181
|
+
res
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def self.log_string(status, message, path)
|
|
185
|
+
Log.info do
|
|
186
|
+
|
|
187
|
+
status = status.to_s
|
|
188
|
+
status_color = self.status_color status
|
|
189
|
+
|
|
190
|
+
str = Log.color :reset
|
|
191
|
+
str << "#{ Log.color status_color, status}"
|
|
192
|
+
str << ": #{ message }" if message
|
|
193
|
+
str << " -- #{Log.color :blue, path.to_s}" if path
|
|
194
|
+
str << " #{Log.color :yellow, Process.pid}"
|
|
195
|
+
str
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def self.log_progress(status, options = {}, path = nil, &block)
|
|
200
|
+
options = Misc.add_defaults options, :severity => Log::INFO, :file => (@exec ? nil : path)
|
|
201
|
+
max = Misc.process_options options, :max
|
|
202
|
+
Log::ProgressBar.with_bar(max, options) do |bar|
|
|
203
|
+
begin
|
|
204
|
+
res = yield bar
|
|
205
|
+
raise KeepBar.new res if IO === res
|
|
206
|
+
res
|
|
207
|
+
rescue
|
|
208
|
+
Log.exception $!
|
|
209
|
+
raise $!
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def log_progress(status, options = {}, &block)
|
|
215
|
+
Step.log_progress(status, options, file(:progress), &block)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def progress_bar(msg = "Progress", options = nil)
|
|
219
|
+
if Hash === msg and options.nil?
|
|
220
|
+
options = msg
|
|
221
|
+
msg = nil
|
|
222
|
+
end
|
|
223
|
+
options = {} if options.nil?
|
|
224
|
+
|
|
225
|
+
max = options[:max]
|
|
226
|
+
Log::ProgressBar.new_bar(max, {:desc => msg, :file => (@exec ? nil : file(:progress))}.merge(options))
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def self.log(status, message, path, &block)
|
|
230
|
+
if block
|
|
231
|
+
if Hash === message
|
|
232
|
+
log_progress(status, message, path, &block)
|
|
233
|
+
else
|
|
234
|
+
log_block(status, message, path, &block)
|
|
235
|
+
end
|
|
236
|
+
else
|
|
237
|
+
log_string(status, message, path)
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def log(status, message = nil, &block)
|
|
242
|
+
self.status = status
|
|
243
|
+
if message
|
|
244
|
+
self.message Log.uncolor(message)
|
|
245
|
+
end
|
|
246
|
+
Step.log(status, message, path, &block)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def exception(ex, msg = nil)
|
|
250
|
+
ex_class = ex.class.to_s
|
|
251
|
+
backtrace = ex.backtrace if ex.respond_to?(:backtrace)
|
|
252
|
+
message = ex.message if ex.respond_to?(:message)
|
|
253
|
+
set_info :backtrace, backtrace
|
|
254
|
+
set_info :exception, {:class => ex_class, :message => message, :backtrace => backtrace}
|
|
255
|
+
if msg.nil?
|
|
256
|
+
log :error, "#{ex_class} -- #{message}"
|
|
257
|
+
else
|
|
258
|
+
log :error, "#{msg} -- #{message}"
|
|
259
|
+
end
|
|
260
|
+
self._abort
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def get_exception
|
|
264
|
+
if info[:exception].nil?
|
|
265
|
+
return Aborted if aborted?
|
|
266
|
+
return Exception.new(messages.last) if error?
|
|
267
|
+
Exception.new ""
|
|
268
|
+
else
|
|
269
|
+
ex_class, ex_message, ex_backtrace = info[:exception].values_at :class, :message, :backtrace
|
|
270
|
+
begin
|
|
271
|
+
klass = Kernel.const_get(ex_class)
|
|
272
|
+
ex = klass.new ex_message
|
|
273
|
+
ex.set_backtrace ex_backtrace unless ex_backtrace.nil? or ex_backtrace.empty?
|
|
274
|
+
ex
|
|
275
|
+
rescue
|
|
276
|
+
Log.exception $!
|
|
277
|
+
Exception.new ex_message
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def recoverable_error?
|
|
283
|
+
return true if aborted?
|
|
284
|
+
return false unless error?
|
|
285
|
+
begin
|
|
286
|
+
return true unless info[:exception]
|
|
287
|
+
klass = Kernel.const_get(info[:exception][:class])
|
|
288
|
+
! (klass <= RbbtException)
|
|
289
|
+
rescue Exception
|
|
290
|
+
true
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
end
|