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.
@@ -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
- (inputs.flatten.select{|i| Step === i} + inputs.flatten.select{|dep| Path === dep && Step === dep.resource}.collect{|dep| dep.resource})
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