rbbt-util 5.11.5 → 5.11.6

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: 6ec4bc56a7d0d260d93be40ee61d23c08f58d5a8
4
- data.tar.gz: 6f51a747302e936ed1e5953e929e5120fa5caa89
3
+ metadata.gz: 2230976fc29ab61ab320c1c007521196acaa9b5f
4
+ data.tar.gz: 60ea71f47e8afa071cdc84f7de115487ec0b1ac5
5
5
  SHA512:
6
- metadata.gz: db5a97b2787f182444de536059beb027d038573c0c3ac3196ec44ce18d2561fa3204a38229d3054e5c92594309fc4a488cc6e9116e370c4f2d383b28a8ed9e71
7
- data.tar.gz: 8a4fc523ae9266ceea9964f26f85834a8f5c0e0899a523bb938e2e813da191651215ec356432ee7b467f39b470328b32dda911d1b2cd9bd757fa467ad14d54ce
6
+ metadata.gz: 8f7bbea5678b31d6f49ce13f94dd0b7d3271ae6e187ea837265e202ee90e95c3cb8af27ae5ba8c05b3dd8fa5d0d6eca14ae7870685990ae391fdfb1273ddbac8
7
+ data.tar.gz: d4746fa8d4393a9f7c399ae766b1881bc41568793ed50722a4b4f101a54962146fead34931b393c8ca44b3ea17057f59b21f505d7336939b777ede2983f9ddc9
@@ -292,12 +292,14 @@ module Persist
292
292
 
293
293
  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
294
294
 
295
- if FalseClass != persist_options[:persist]
295
+ if FalseClass == persist_options[:persist]
296
+ yield
297
+ else
296
298
  other_options = Misc.process_options persist_options, :other
297
299
  path = persistence_path(name, persist_options, other_options || {})
298
300
 
299
301
  case
300
- when type.to_sym === :memory
302
+ when type.to_sym == :memory
301
303
  repo = persist_options[:repo] || Persist::MEMORY
302
304
  repo[path] ||= yield
303
305
 
@@ -410,7 +412,14 @@ module Persist
410
412
  res = tee_stream(res, path, type, res.respond_to?(:callback)? res.callback : nil)
411
413
  ConcurrentStream.setup res do
412
414
  begin
413
- lockfile.unlock
415
+ lockfile.unlock if lockfile.locked?
416
+ rescue
417
+ Log.warn "Lockfile exception: " << $!.message
418
+ end
419
+ end
420
+ res.abort_callback = Proc.new do
421
+ begin
422
+ lockfile.unlock if lockfile.locked?
414
423
  rescue
415
424
  Log.warn "Lockfile exception: " << $!.message
416
425
  end
@@ -425,6 +434,13 @@ module Persist
425
434
  Log.warn "Lockfile exception: " << $!.message
426
435
  end
427
436
  end
437
+ res.abort_callback = Proc.new do
438
+ begin
439
+ lockfile.unlock
440
+ rescue
441
+ Log.warn "Lockfile exception: " << $!.message
442
+ end
443
+ end
428
444
  raise KeepLocked.new res
429
445
  end
430
446
  end
@@ -440,21 +456,19 @@ module Persist
440
456
  else
441
457
  res.read
442
458
  end
459
+ res.join if res.respond_to? :join
443
460
  rescue
444
461
  res.abort if res.respond_to? :abort
445
462
  raise $!
446
- ensure
447
- res.join if res.respond_to? :join
448
463
  end
449
464
  when TSV::Dumper
450
465
  begin
451
466
  io = res.stream
452
467
  res = TSV.open(io)
468
+ io.join if io.respond_to? :join
453
469
  rescue
454
470
  io.abort if io.respond_to? :abort
455
471
  raise $!
456
- ensure
457
- io.join if io.respond_to? :join
458
472
  end
459
473
  end
460
474
 
@@ -472,8 +486,6 @@ module Persist
472
486
  end
473
487
  end
474
488
 
475
- else
476
- yield
477
489
  end
478
490
  end
479
491
 
@@ -83,13 +83,18 @@ module TSV
83
83
  def self.traverse_io(io, options = {}, &block)
84
84
  filename = io.filename if io.respond_to? :filename
85
85
  callback = Misc.process_options options, :callback
86
- if callback
87
- TSV::Parser.traverse(io, options) do |k,v|
88
- res = yield k, v
89
- callback.call res
86
+ begin
87
+ if callback
88
+ TSV::Parser.traverse(io, options) do |k,v|
89
+ res = yield k, v
90
+ callback.call res
91
+ end
92
+ else
93
+ TSV::Parser.traverse(io, options, &block)
90
94
  end
91
- else
92
- TSV::Parser.traverse(io, options, &block)
95
+ rescue
96
+ Log.error "Traverse IO error"
97
+ raise $!
93
98
  end
94
99
  end
95
100
 
@@ -305,6 +310,8 @@ module TSV
305
310
  rescue Exception
306
311
  Log.exception $!
307
312
  parent.raise $!
313
+ stream = obj_stream(into)
314
+ stream.abort if stream and stream.respond_to? :abort
308
315
  end
309
316
  end
310
317
  ConcurrentStream.setup(obj_stream(into), :threads => thread)
@@ -546,37 +546,6 @@ end
546
546
  res
547
547
  end
548
548
 
549
- def self.sensiblewrite(path, content = nil, &block)
550
- return if File.exists? path
551
- tmp_path = path + '.sensible_write'
552
- Misc.lock tmp_path do
553
- if not File.exists? path
554
- FileUtils.rm_f tmp_path if File.exists? tmp_path
555
- begin
556
- case
557
- when block_given?
558
- File.open(tmp_path, 'w', &block)
559
- when String === content
560
- File.open(tmp_path, 'w') do |f| f.write content end
561
- when (IO === content or StringIO === content or File === content)
562
- File.open(tmp_path, 'w') do |f|
563
- while block = content.read(2048);
564
- f.write block
565
- end
566
- end
567
- else
568
- File.open(tmp_path, 'w') do |f| end
569
- end
570
- FileUtils.mv tmp_path, path
571
- rescue Exception
572
- Log.error "Exception in sensiblewrite: #{$!.message} -- #{ Log.color :blue, path }"
573
- FileUtils.rm_f tmp_path if File.exists? tmp_path
574
- FileUtils.rm_f path if File.exists? path
575
- raise $!
576
- end
577
- end
578
- end
579
- end
580
549
 
581
550
  def self.add_defaults(options, defaults = {})
582
551
  case
@@ -1,19 +1,48 @@
1
1
  module ConcurrentStream
2
2
  attr_accessor :threads, :pids, :callback, :abort_callback, :filename, :joined
3
3
 
4
+ def self.setup(stream, options = {}, &block)
5
+ threads, pids, callback, filename = Misc.process_options options, :threads, :pids, :callback, :filename
6
+ stream.extend ConcurrentStream unless ConcurrentStream === stream
7
+
8
+ stream.threads ||= []
9
+ stream.pids ||= []
10
+ stream.threads.concat(Array === threads ? threads : [threads]) unless threads.nil?
11
+ stream.pids.concat(Array === pids ? pids : [pids]) unless pids.nil? or pids.empty?
12
+
13
+ callback = block if block_given?
14
+ if stream.callback and callback
15
+ old_callback = stream.callback
16
+ stream.callback = Proc.new do
17
+ old_callback.call
18
+ callback.call
19
+ end
20
+ else
21
+ stream.callback = callback
22
+ end
23
+
24
+ stream.filename = filename unless filename.nil?
25
+
26
+ stream
27
+ end
28
+
4
29
  def joined?
5
30
  @joined
6
31
  end
7
32
 
8
- def join
9
-
33
+ def join_threads
10
34
  if @threads and @threads.any?
11
35
  @threads.each do |t|
12
- t.join unless t == Thread.current
36
+ begin
37
+ ensure
38
+ t.join unless t == Thread.current
39
+ end
13
40
  end
14
41
  @threads = []
15
42
  end
43
+ end
16
44
 
45
+ def join_pids
17
46
  if @pids and @pids.any?
18
47
  @pids.each do |pid|
19
48
  begin
@@ -24,46 +53,38 @@ module ConcurrentStream
24
53
  end
25
54
  @pids = []
26
55
  end
56
+ end
27
57
 
58
+ def join_callback
28
59
  if @callback and not joined?
29
60
  @callback.call
30
61
  @callback = nil
31
62
  end
63
+ end
64
+
65
+ def join
66
+ join_threads
67
+ join_pids
68
+
69
+ join_callback
32
70
 
33
71
  @joined = true
34
72
  end
35
73
 
36
- def abort
37
- @threads.each{|t| t.raise Aborted.new unless t = Thread.current } if @threads
38
- @threads.each{|t| t.join unless t = Thread.current } if @threads
74
+ def abort_threads
75
+ @threads.each{|t| t.raise Aborted.new unless t == Thread.current } if @threads
76
+ end
77
+
78
+ def abort_pids
39
79
  @pids.each{|pid| Process.kill :INT, pid } if @pids
40
- @pids.each{|pid| Process.waitpid pid } if @pids
80
+ end
81
+
82
+ def abort
83
+ abort_threads
84
+ abort_pids
41
85
  @abort_callback.call if @abort_callback
42
86
  @abort_callback = nil
87
+ @callback = nil
43
88
  end
44
89
 
45
- def self.setup(stream, options = {}, &block)
46
- threads, pids, callback, filename = Misc.process_options options, :threads, :pids, :callback, :filename
47
- stream.extend ConcurrentStream unless ConcurrentStream === stream
48
-
49
- stream.threads ||= []
50
- stream.pids ||= []
51
- stream.threads.concat(Array === threads ? threads : [threads]) unless threads.nil?
52
- stream.pids.concat(Array === pids ? pids : [pids]) unless pids.nil? or pids.empty?
53
-
54
- callback = block if block_given?
55
- if stream.callback and callback
56
- old_callback = stream.callback
57
- stream.callback = Proc.new do
58
- old_callback.call
59
- callback.call
60
- end
61
- else
62
- stream.callback = callback
63
- end
64
-
65
- stream.filename = filename unless filename.nil?
66
-
67
- stream
68
- end
69
90
  end
@@ -3,14 +3,14 @@ Lockfile.refresh = false if ENV["RBBT_NO_LOCKFILE_REFRESH"] == "true"
3
3
  module Misc
4
4
 
5
5
  LOCK_MUTEX = Mutex.new
6
- def self.lock(file, unlock = true)
6
+ def self.lock(file, unlock = true, options = {})
7
7
  return yield if file.nil?
8
8
  FileUtils.mkdir_p File.dirname(File.expand_path(file)) unless File.exists? File.dirname(File.expand_path(file))
9
9
 
10
10
  res = nil
11
11
 
12
12
  lock_path = File.expand_path(file + '.lock')
13
- lockfile = Lockfile.new(lock_path)
13
+ lockfile = Lockfile.new(lock_path, options)
14
14
 
15
15
  hostname = Misc.hostname
16
16
  LOCK_MUTEX.synchronize do
@@ -28,7 +28,7 @@ module Misc
28
28
  end
29
29
  rescue Exception
30
30
  FileUtils.rm lock_path if File.exists? lock_path
31
- lockfile = Lockfile.new(lock_path) unless File.exists? lock_path
31
+ lockfile = Lockfile.new(lock_path, options) unless File.exists? lock_path
32
32
  raise $!
33
33
  end
34
34
  end
@@ -43,6 +43,9 @@ module Misc
43
43
  rescue KeepLocked
44
44
  unlock = false
45
45
  res = $!.payload
46
+ rescue Exception
47
+ lockfile.unlock if lockfile.locked?
48
+ raise $!
46
49
  ensure
47
50
  if unlock and lockfile.locked?
48
51
  lockfile.unlock
@@ -1,5 +1,12 @@
1
1
  module Misc
2
2
 
3
+ class << self
4
+ attr_accessor :sensiblewrite_dir
5
+ def sensiblewrite_dir
6
+ @sensiblewrite_dir = Rbbt.tmp.sensiblewrite
7
+ end
8
+ end
9
+
3
10
  PIPE_MUTEX = Mutex.new
4
11
 
5
12
  OPEN_PIPE_IN = []
@@ -21,7 +28,6 @@ module Misc
21
28
  end
22
29
  end
23
30
 
24
-
25
31
  def self.purge_pipes(*save)
26
32
  PIPE_MUTEX.synchronize do
27
33
  OPEN_PIPE_IN.each do |pipe|
@@ -43,12 +49,11 @@ module Misc
43
49
  sout.close
44
50
  begin
45
51
  yield sin
52
+ sin.close if close and not sin.closed?
46
53
  rescue
47
54
  Log.exception $!
48
55
  Process.kill :INT, parent_pid
49
56
  Kernel.exit! -1
50
- ensure
51
- sin.close if close and not sin.closed?
52
57
  end
53
58
  Kernel.exit! 0
54
59
  }
@@ -58,10 +63,9 @@ module Misc
58
63
  thread = Thread.new(Thread.current) do |parent|
59
64
  begin
60
65
  yield sin
66
+ sin.close if close and not sin.closed?
61
67
  rescue
62
68
  parent.raise $!
63
- ensure
64
- sin.close if close and not sin.closed?
65
69
  end
66
70
  end
67
71
  ConcurrentStream.setup sout, :threads => [thread]
@@ -84,8 +88,11 @@ module Misc
84
88
  begin stream_in1.write block; rescue Exception; Log.exception $!; skip1 = true end unless skip1
85
89
  begin stream_in2.write block; rescue Exception; Log.exception $!; skip2 = true end unless skip2
86
90
  end
91
+ raise "Error writing in stream_in1" if skip1
87
92
  raise "Error writing in stream_in2" if skip2
88
- raise "Error writing in stream_in2" if skip2
93
+ stream.join if stream.respond_to? :join
94
+ stream_in1.close
95
+ stream_in2.close
89
96
  rescue Aborted
90
97
  stream.abort if stream.respond_to? :abort
91
98
  raise $!
@@ -93,16 +100,11 @@ module Misc
93
100
  Log.exception $!
94
101
  rescue Exception
95
102
  Log.exception $!
96
- ensure
97
- stream_in1.close
98
- stream_in2.close
99
- stream.join if stream.respond_to? :join
100
103
  end
101
104
  end
102
105
  stream.close
103
106
  stream_in1.close
104
107
  stream_in2.close
105
- #stream.join if stream.respond_to? :join
106
108
 
107
109
  ConcurrentStream.setup stream_out1, :pids => [splitter_pid]
108
110
  ConcurrentStream.setup stream_out2, :pids => [splitter_pid]
@@ -122,18 +124,17 @@ module Misc
122
124
  begin stream_in1.write block; rescue Exception; Aborted === $! ? raise($!): Log.exception($!); skip1 = true end unless skip1
123
125
  begin stream_in2.write block; rescue Exception; Aborted === $! ? raise($!): Log.exception($!); skip2 = true end unless skip2
124
126
  end
127
+ stream_in1.close
128
+ stream_in2.close
129
+ stream.join if stream.respond_to? :join
125
130
  rescue Aborted
126
131
  stream.abort if stream.respond_to? :abort
127
- raise $!
132
+ parent.raise $!
128
133
  rescue IOError
129
134
  Log.exception $!
130
135
  rescue Exception
131
136
  Log.exception $!
132
137
  parent.raise $!
133
- ensure
134
- stream_in1.close
135
- stream_in2.close
136
- stream.join if stream.respond_to? :join
137
138
  end
138
139
  end
139
140
 
@@ -153,11 +154,9 @@ module Misc
153
154
  while block = io.read(2048)
154
155
  str << block
155
156
  end
157
+ io.join if io.respond_to? :join
156
158
  rescue
157
159
  io.abort if io.respond_to? :abort
158
- ensure
159
- io.join if io.respond_to? :join
160
- io.close if io.respond_to? :close
161
160
  end
162
161
  str
163
162
  end
@@ -167,12 +166,10 @@ module Misc
167
166
  while block = io.read(2048)
168
167
  return if io.eof?
169
168
  Thread.pass
170
- end
169
+ end
170
+ io.join if io.respond_to? :join
171
171
  rescue
172
172
  io.abort if io.respond_to? :abort
173
- ensure
174
- io.join if io.respond_to? :join
175
- io.close if io.respond_to? :close
176
173
  end
177
174
  end
178
175
 
@@ -213,12 +210,38 @@ module Misc
213
210
  end
214
211
  str
215
212
  end
216
- def self._read_stream(stream, size)
217
- str = ""
218
- while (len=str.length) < size
219
- str << (stream.read(size-len) or break)
213
+
214
+ def self.sensiblewrite(path, content = nil, &block)
215
+ return if File.exists? path
216
+ #tmp_path = path + '.sensible_write'
217
+ tmp_path = Persist.persistence_path(path, {:dir => Misc.sensiblewrite_dir})
218
+ Misc.lock tmp_path do
219
+ if not File.exists? path
220
+ FileUtils.rm_f tmp_path if File.exists? tmp_path
221
+ begin
222
+ case
223
+ when block_given?
224
+ File.open(tmp_path, 'w', &block)
225
+ when String === content
226
+ File.open(tmp_path, 'w') do |f| f.write content end
227
+ when (IO === content or StringIO === content or File === content)
228
+ File.open(tmp_path, 'w') do |f|
229
+ while block = content.read(2048);
230
+ f.write block
231
+ end
232
+ end
233
+ else
234
+ File.open(tmp_path, 'w') do |f| end
235
+ end
236
+ FileUtils.mv tmp_path, path
237
+ rescue Exception
238
+ Log.error "Exception in sensiblewrite: #{$!.message} -- #{ Log.color :blue, path }"
239
+ FileUtils.rm_f path if File.exists? path
240
+ raise $!
241
+ ensure
242
+ FileUtils.rm_f tmp_path if File.exists? tmp_path
243
+ end
244
+ end
220
245
  end
221
- str
222
246
  end
223
-
224
247
  end
@@ -236,13 +236,13 @@ module Open
236
236
  end
237
237
  end
238
238
 
239
- def self.lock(file, &block)
239
+ def self.lock(file, options = {}, &block)
240
240
  if (dir_sub_path = find_repo_dir(file))
241
241
  dir, sub_path = dir_sub_path
242
242
  repo = get_repo_from_dir(dir)
243
243
  Misc.lock_in_repo(repo, sub_path, &block)
244
244
  else
245
- Misc.lock(file, &block)
245
+ Misc.lock(file, true, options, &block)
246
246
  end
247
247
  end
248
248
 
@@ -73,7 +73,7 @@ class Step
73
73
  return nil if @exec or info_file.nil?
74
74
  value = Annotated.purge value if defined? Annotated
75
75
  lock_filename = Persist.persistence_path(info_file, {:dir => Step.lock_dir})
76
- Open.lock(info_file) do
76
+ Open.lock(info_file, :refresh => false) do
77
77
  i = info
78
78
  i[key] = value
79
79
  @info_cache = i
@@ -3,7 +3,7 @@ require 'rbbt/persist/tsv'
3
3
  require 'rbbt/util/log'
4
4
  require 'rbbt/util/semaphore'
5
5
  require 'rbbt/workflow/accessor'
6
-
6
+ require 'rbbt/workflow/step/run'
7
7
 
8
8
  class Step
9
9
  attr_accessor :path, :task, :inputs, :dependencies, :bindings
@@ -49,357 +49,63 @@ class Step
49
49
 
50
50
  class << self
51
51
  attr_accessor :log_relay_step
52
- end
53
-
54
- def relay_log(step)
55
- return self unless Task === self.task and not self.task.name.nil?
56
- if not self.respond_to? :original_log
57
- class << self
58
- attr_accessor :relay_step
59
- alias original_log log
60
- def log(status, message = nil)
61
- self.status = status
62
- message Log.uncolor message
63
- relay_step.log([task.name.to_s, status.to_s] * ">", message.nil? ? nil : message ) unless (relay_step.done? or relay_step.error? or relay_step.aborted?)
64
- end
65
- end
66
52
  end
67
- @relay_step = step
68
- self
69
- end
70
53
 
71
- def prepare_result(value, description = nil, info = {})
72
- case
73
- when IO === value
74
- begin
75
- case @task.result_type
76
- when :array
77
- array = []
78
- while line = value.gets
79
- array << line.strip
54
+ def relay_log(step)
55
+ return self unless Task === self.task and not self.task.name.nil?
56
+ if not self.respond_to? :original_log
57
+ class << self
58
+ attr_accessor :relay_step
59
+ alias original_log log
60
+ def log(status, message = nil)
61
+ self.status = status
62
+ message Log.uncolor message
63
+ relay_step.log([task.name.to_s, status.to_s] * ">", message.nil? ? nil : message ) unless (relay_step.done? or relay_step.error? or relay_step.aborted?)
80
64
  end
81
- array
82
- when :tsv
83
- TSV.open(value)
84
- else
85
- value.read
86
65
  end
87
- rescue Exception
88
- value.abort if value.respond_to? :abort
89
- ensure
90
- value.join if value.respond_to? :join
91
- value.close unless value.closed?
92
66
  end
93
- when (not defined? Entity or description.nil? or not Entity.formats.include? description)
94
- value
95
- when (Annotated === value and info.empty?)
96
- value
97
- when Annotated === value
98
- annotations = value.annotations
99
- info.each do |k,v|
100
- value.send("#{h}=", v) if annotations.include? k
101
- end
102
- value
103
- else
104
- Entity.formats[description].setup(value, info.merge(:format => description))
105
- end
106
- end
107
-
108
- def get_stream
109
- @mutex.synchronize do
110
- begin
111
- IO === @result ? @result : nil
112
- ensure
113
- @result = nil
114
- end
115
- end
116
- end
117
-
118
- def _exec
119
- @exec = true if @exec.nil?
120
- @task.exec_in((bindings ? bindings : self), *@inputs)
121
- end
122
-
123
- def exec(no_load=false)
124
- dependencies.each{|dependency| dependency.exec(no_load) }
125
- @result = _exec
126
- @result = @result.stream if TSV::Dumper === @result
127
- no_load ? @result : prepare_result(@result, @task.result_description)
128
- end
129
-
130
- def join
131
- stream = get_stream if @result
132
- begin
133
- Misc.consume_stream stream if stream
134
- rescue
135
- stream.abort if stream.respond_to? :abort
136
- raise $!
137
- ensure
138
- stream.join if stream.respond_to? :join and not stream.joined?
139
- end
140
-
141
- return if not Open.exists? info_file
142
- @pid ||= info[:pid]
143
-
144
- #while not done?
145
- # Misc.insist 2, 0.5 do
146
- # raise "Job error while joining: #{info[:messages].last}" if error?
147
- # raise "Job aborted while joining: #{info[:messages].last}" if aborted?
148
- # raise "Job vanished while joining: #{@pid}" if @pid and not Misc.pid_exists? @pid
149
- # end
150
- #end
151
-
152
- Misc.insist [0.1, 0.2, 0.5, 1] do
153
- @pid ||= info[:pid]
154
- end
155
-
156
- if @pid.nil?
157
- dependencies.each{|dep| dep.join }
158
- self
159
- else
160
- begin
161
- Log.debug{"Waiting for pid: #{@pid}"}
162
- Process.waitpid @pid
163
- rescue Errno::ECHILD
164
- Log.debug{"Process #{ @pid } already finished: #{ path }"}
165
- end if Misc.pid_exists? @pid
166
- @pid = nil
167
- dependencies.each{|dep| dep.join }
67
+ @relay_step = step
168
68
  self
169
69
  end
170
- self
171
- end
172
-
173
- def checks
174
- rec_dependencies.collect{|dependency| dependency.path }.uniq
175
- end
176
70
 
177
- def kill_children
178
- children_pids = info[:children_pids]
179
- if children_pids and children_pids.any?
180
- Log.medium("Killing children: #{ children_pids * ", " }")
181
- children_pids.each do |pid|
182
- Log.medium("Killing child #{ pid }")
71
+ def prepare_result(value, description = nil, info = {})
72
+ case
73
+ when IO === value
183
74
  begin
184
- Process.kill "INT", pid
185
- rescue Exception
186
- Log.medium("Exception killing child #{ pid }: #{$!.message}")
187
- end
188
- end
189
- end
190
- end
191
-
192
- def run_dependencies(seen = [])
193
- seen << self.path
194
- dependencies.uniq.each{|dependency|
195
- next if seen.include? dependency.path
196
- Log.info "#{Log.color :magenta, "Checking dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} -- #{Log.color :blue, dependency.path}"
197
- begin
198
- dependency.relay_log self
199
- dependency.clean if not dependency.done? and (dependency.error? or dependency.aborted?)
200
- dependency.clean if dependency.streaming? and not dependency.running?
201
- #dependency.run_dependencies(seen)
202
- dependency.run(ENV["RBBT_NO_STREAM"] != 'true') unless dependency.result or dependency.done?
203
- seen << dependency.path
204
- seen.concat dependency.rec_dependencies.collect{|d| d.path}
205
- rescue Exception
206
- backtrace = $!.backtrace
207
- set_info :backtrace, backtrace
208
- log(:error, "Exception processing dependency #{Log.color :yellow, dependency.task.name.to_s} -- #{$!.class}: #{$!.message}")
209
- raise $!
210
- end
211
- }
212
- end
213
-
214
- def run(no_load = false)
215
-
216
- result = nil
217
- begin
218
- @mutex.synchronize do
219
- no_load = no_load ? :stream : false
220
- result = Persist.persist "Job", @task.result_type, :file => path, :check => checks, :no_load => no_load do |lockfile|
221
- if Step === Step.log_relay_step and not self == Step.log_relay_step
222
- relay_log(Step.log_relay_step) unless self.respond_to? :relay_step and self.relay_step
223
- end
224
- @exec = false
225
-
226
- Open.rm info_file if Open.exists? info_file
227
-
228
- set_info :pid, Process.pid
229
- set_info :issued, Time.now
230
-
231
- log(:preparing, "Preparing job: #{Misc.fingerprint dependencies}")
232
- set_info :dependencies, dependencies.collect{|dep| [dep.task_name, dep.name]}
233
-
234
- run_dependencies
235
-
236
- set_info :inputs, Misc.remove_long_items(Misc.zip2hash(task.inputs, @inputs)) unless task.inputs.nil?
237
-
238
- set_info :started, (start_time = Time.now)
239
- log :started, "#{Log.color :green, "Starting task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
240
-
241
- begin
242
- result = _exec
243
- rescue Aborted
244
- log(:error, "Aborted")
245
-
246
- kill_children
247
- raise $!
248
- rescue Exception
249
- backtrace = $!.backtrace
250
-
251
- # HACK: This fixes an strange behaviour in 1.9.3 where some
252
- # backtrace strings are coded in ASCII-8BIT
253
- kill_children
254
- set_info :backtrace, backtrace
255
- log(:error, "#{$!.class}: #{$!.message}")
256
- backtrace.each{|l| l.force_encoding("UTF-8")} if String.instance_methods.include? :force_encoding
257
- raise $!
258
- end
259
-
260
- result = prepare_result result, @task.description, info if IO === result and ENV["RBBT_NO_STREAM"]
261
- result = prepare_result result.stream, @task.description, info if TSV::Dumper === result and ENV["RBBT_NO_STREAM"]
262
-
263
- case result
264
- when IO
265
- result = Misc.read_stream(result) if ENV["RBBT_NO_STREAM"]
266
-
267
- log :streaming, "#{Log.color :magenta, "Streaming task result IO"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
268
- ConcurrentStream.setup result do
269
- begin
270
- set_info :done, (done_time = Time.now)
271
- set_info :time_elapsed, (time_elapsed = done_time - start_time)
272
- log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i} -- #{path}"
273
- rescue
274
- Log.exception $!
275
- ensure
276
- join
277
- end
278
- end
279
- result.abort_callback = Proc.new do
280
- begin
281
- log :error, "#{Log.color :red, "ERROR -- streamming aborted"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] -- #{path}"
282
- rescue
283
- Log.exception $!
284
- ensure
285
- join
286
- end
287
- end
288
- when TSV::Dumper
289
- log :streaming, "#{Log.color :magenta, "Streaming task result TSV::Dumper"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
290
- ConcurrentStream.setup result.stream do
291
- begin
292
- set_info :done, (done_time = Time.now)
293
- set_info :done, (done_time = Time.now)
294
- set_info :time_elapsed, (time_elapsed = done_time - start_time)
295
- log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i} -- #{path}"
296
- rescue
297
- Log.exception $!
298
- ensure
299
- join
300
- end
301
- end
302
- result.stream.abort_callback = Proc.new do
303
- begin
304
- log :error, "#{Log.color :red, "ERROR -- streamming aborted"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] -- #{path}"
305
- rescue
306
- Log.exception $!
307
- end
75
+ case @task.result_type
76
+ when :array
77
+ array = []
78
+ while line = value.gets
79
+ array << line.strip
308
80
  end
81
+ array
82
+ when :tsv
83
+ TSV.open(value)
309
84
  else
310
- set_info :done, (done_time = Time.now)
311
- set_info :time_elapsed, (time_elapsed = done_time - start_time)
312
- log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i}"
85
+ value.read
313
86
  end
314
-
315
- result
316
- end
317
-
318
- if no_load
319
- @result ||= result
320
- self
321
- else
322
- @result = prepare_result result, @task.result_description
323
- end
324
- end
325
- ensure
326
- join unless no_load
327
- end
328
- end
329
-
330
- def fork(semaphore = nil)
331
- raise "Can not fork: Step is waiting for proces #{@pid} to finish" if not @pid.nil? and not Process.pid == @pid
332
- @pid = Process.fork do
333
- begin
334
- RbbtSemaphore.wait_semaphore(semaphore) if semaphore
335
- FileUtils.mkdir_p File.dirname(path) unless Open.exists? File.dirname(path)
336
- begin
337
- res = run
338
- rescue Aborted
339
- Log.debug{"Forked process aborted: #{path}"}
340
- log :aborted, "Aborted"
341
- raise $!
342
- rescue Exception
343
- Log.debug("Exception '#{$!.message}' caught on forked process: #{path}")
344
- raise $!
345
- ensure
346
- join
347
- end
348
-
349
- begin
350
- children_pids = info[:children_pids]
351
- if children_pids
352
- children_pids.each do |pid|
353
- if Misc.pid_exists? pid
354
- begin
355
- Process.waitpid pid
356
- rescue Errno::ECHILD
357
- Log.low "Waiting on #{ pid } failed: #{$!.message}"
358
- end
359
- end
360
- end
361
- set_info :children_done, Time.now
362
- end
363
- rescue Exception
364
- Log.debug("Exception waiting for children: #{$!.message}")
365
- exit -1
366
- end
367
- set_info :pid, nil
368
- exit 0
87
+ rescue Exception
88
+ value.abort if value.respond_to? :abort
369
89
  ensure
370
- RbbtSemaphore.post_semaphore(semaphore) if semaphore
90
+ value.join if value.respond_to? :join
91
+ value.close unless value.closed?
371
92
  end
372
- end
373
- set_info :forked, true
374
- Process.detach(@pid)
375
- self
376
- end
377
-
378
- def abort
379
- @pid ||= info[:pid]
380
-
381
- #return true unless info[:forked]
382
-
383
- case @pid
384
- when nil
385
- Log.medium "Could not abort #{path}: no pid"
386
- false
387
- when Process.pid
388
- Log.medium "Could not abort #{path}: same process"
389
- false
390
- else
391
- Log.medium "Aborting #{path}: #{ @pid }"
392
- begin
393
- Process.kill("KILL", @pid)
394
- Process.waitpid @pid
395
- rescue Exception
396
- Log.debug("Aborted job #{@pid} was not killed: #{$!.message}")
93
+ when (not defined? Entity or description.nil? or not Entity.formats.include? description)
94
+ value
95
+ when (Annotated === value and info.empty?)
96
+ value
97
+ when Annotated === value
98
+ annotations = value.annotations
99
+ info.each do |k,v|
100
+ value.send("#{h}=", v) if annotations.include? k
397
101
  end
398
- log(:aborted, "Job aborted")
399
- true
102
+ value
103
+ else
104
+ Entity.formats[description].setup(value, info.merge(:format => description))
400
105
  end
401
106
  end
402
107
 
108
+
403
109
  def child(&block)
404
110
  child_pid = Process.fork &block
405
111
  children_pids = info[:children_pids]
@@ -0,0 +1,325 @@
1
+ class Step
2
+
3
+ attr_reader :stream
4
+
5
+ def get_stream
6
+ @mutex.synchronize do
7
+ @stream = begin
8
+ IO === @result ? @result : nil
9
+ ensure
10
+ @result = nil
11
+ end
12
+ end
13
+ end
14
+
15
+ def _exec
16
+ @exec = true if @exec.nil?
17
+ @task.exec_in((bindings ? bindings : self), *@inputs)
18
+ end
19
+
20
+ def exec(no_load=false)
21
+ dependencies.each{|dependency| dependency.exec(no_load) }
22
+ @result = _exec
23
+ @result = @result.stream if TSV::Dumper === @result
24
+ no_load ? @result : prepare_result(@result, @task.result_description)
25
+ end
26
+
27
+ def checks
28
+ rec_dependencies.collect{|dependency| dependency.path }.uniq
29
+ end
30
+
31
+ def kill_children
32
+ children_pids = info[:children_pids]
33
+ if children_pids and children_pids.any?
34
+ Log.medium("Killing children: #{ children_pids * ", " }")
35
+ children_pids.each do |pid|
36
+ Log.medium("Killing child #{ pid }")
37
+ begin
38
+ Process.kill "INT", pid
39
+ rescue Exception
40
+ Log.medium("Exception killing child #{ pid }: #{$!.message}")
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ def run_dependencies(seen = [])
47
+ seen << self.path
48
+ dependencies.uniq.each{|dependency|
49
+ next if seen.include? dependency.path
50
+ Log.info "#{Log.color :magenta, "Checking dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} -- #{Log.color :blue, dependency.path}"
51
+ begin
52
+ dependency.relay_log self
53
+ dependency.clean if not dependency.done? and (dependency.error? or dependency.aborted?)
54
+ dependency.clean if dependency.streaming? and not dependency.running?
55
+ #dependency.run_dependencies(seen)
56
+ dependency.run(ENV["RBBT_NO_STREAM"] != 'true') unless dependency.result or dependency.done?
57
+ seen << dependency.path
58
+ seen.concat dependency.rec_dependencies.collect{|d| d.path}
59
+ rescue Exception
60
+ backtrace = $!.backtrace
61
+ set_info :backtrace, backtrace
62
+ log(:error, "Exception processing dependency #{Log.color :yellow, dependency.task.name.to_s} -- #{$!.class}: #{$!.message}")
63
+ raise $!
64
+ end
65
+ }
66
+ end
67
+
68
+ def run(no_load = false)
69
+
70
+ result = nil
71
+ begin
72
+ @mutex.synchronize do
73
+ no_load = no_load ? :stream : false
74
+ result = Persist.persist "Job", @task.result_type, :file => path, :check => checks, :no_load => no_load do |lockfile|
75
+ if Step === Step.log_relay_step and not self == Step.log_relay_step
76
+ relay_log(Step.log_relay_step) unless self.respond_to? :relay_step and self.relay_step
77
+ end
78
+ @exec = false
79
+
80
+ Open.rm info_file if Open.exists? info_file
81
+
82
+ set_info :pid, Process.pid
83
+ set_info :issued, Time.now
84
+
85
+ log(:preparing, "Preparing job: #{Misc.fingerprint dependencies}")
86
+ set_info :dependencies, dependencies.collect{|dep| [dep.task_name, dep.name]}
87
+
88
+ run_dependencies
89
+
90
+ set_info :inputs, Misc.remove_long_items(Misc.zip2hash(task.inputs, @inputs)) unless task.inputs.nil?
91
+
92
+ set_info :started, (start_time = Time.now)
93
+ log :started, "#{Log.color :green, "Starting task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
94
+
95
+ begin
96
+ result = _exec
97
+ rescue Aborted
98
+ log(:error, "Aborted")
99
+
100
+ kill_children
101
+ raise $!
102
+ rescue Exception
103
+ backtrace = $!.backtrace
104
+
105
+ # HACK: This fixes an strange behaviour in 1.9.3 where some
106
+ # backtrace strings are coded in ASCII-8BIT
107
+ kill_children
108
+ set_info :backtrace, backtrace
109
+ log(:error, "#{$!.class}: #{$!.message}")
110
+ backtrace.each{|l| l.force_encoding("UTF-8")} if String.instance_methods.include? :force_encoding
111
+ raise $!
112
+ end
113
+
114
+ result = prepare_result result, @task.description, info if IO === result and ENV["RBBT_NO_STREAM"]
115
+ result = prepare_result result.stream, @task.description, info if TSV::Dumper === result and ENV["RBBT_NO_STREAM"]
116
+
117
+ case result
118
+ when IO
119
+ result = Misc.read_stream(result) if ENV["RBBT_NO_STREAM"]
120
+
121
+ log :streaming, "#{Log.color :magenta, "Streaming task result IO"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
122
+ ConcurrentStream.setup result do
123
+ begin
124
+ set_info :done, (done_time = Time.now)
125
+ set_info :time_elapsed, (time_elapsed = done_time - start_time)
126
+ log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i} -- #{path}"
127
+ rescue
128
+ Log.exception $!
129
+ ensure
130
+ join
131
+ end
132
+ end
133
+ result.abort_callback = Proc.new do
134
+ begin
135
+ log :error, "#{Log.color :red, "ERROR -- streamming aborted"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] -- #{path}" if status == :streaming
136
+ stop_dependencies
137
+ abort_stream
138
+ rescue
139
+ Log.exception $!
140
+ ensure
141
+ join
142
+ end
143
+ end
144
+ when TSV::Dumper
145
+ log :streaming, "#{Log.color :magenta, "Streaming task result TSV::Dumper"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
146
+ ConcurrentStream.setup result.stream do
147
+ begin
148
+ set_info :done, (done_time = Time.now)
149
+ set_info :done, (done_time = Time.now)
150
+ set_info :time_elapsed, (time_elapsed = done_time - start_time)
151
+ log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i} -- #{path}"
152
+ rescue
153
+ Log.exception $!
154
+ ensure
155
+ join
156
+ end
157
+ end
158
+ result.stream.abort_callback = Proc.new do
159
+ begin
160
+ log :error, "#{Log.color :red, "ERROR -- streamming aborted"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] -- #{path}" if status == :streaming
161
+ stop_dependencies
162
+ abort_stream
163
+ rescue
164
+ Log.exception $!
165
+ ensure
166
+ join
167
+ end
168
+ end
169
+ else
170
+ set_info :done, (done_time = Time.now)
171
+ set_info :time_elapsed, (time_elapsed = done_time - start_time)
172
+ log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i}"
173
+ end
174
+
175
+ result
176
+ end
177
+
178
+ if no_load
179
+ @result ||= result
180
+ self
181
+ else
182
+ @result = prepare_result result, @task.result_description
183
+ end
184
+ end
185
+ ensure
186
+ join unless no_load
187
+ end
188
+ end
189
+
190
+ def fork(semaphore = nil)
191
+ raise "Can not fork: Step is waiting for proces #{@pid} to finish" if not @pid.nil? and not Process.pid == @pid
192
+ @pid = Process.fork do
193
+ begin
194
+ RbbtSemaphore.wait_semaphore(semaphore) if semaphore
195
+ FileUtils.mkdir_p File.dirname(path) unless Open.exists? File.dirname(path)
196
+ begin
197
+ res = run
198
+ rescue Aborted
199
+ Log.debug{"Forked process aborted: #{path}"}
200
+ log :aborted, "Aborted"
201
+ raise $!
202
+ rescue Exception
203
+ Log.debug("Exception '#{$!.message}' caught on forked process: #{path}")
204
+ raise $!
205
+ ensure
206
+ join
207
+ end
208
+
209
+ begin
210
+ children_pids = info[:children_pids]
211
+ if children_pids
212
+ children_pids.each do |pid|
213
+ if Misc.pid_exists? pid
214
+ begin
215
+ Process.waitpid pid
216
+ rescue Errno::ECHILD
217
+ Log.low "Waiting on #{ pid } failed: #{$!.message}"
218
+ end
219
+ end
220
+ end
221
+ set_info :children_done, Time.now
222
+ end
223
+ rescue Exception
224
+ Log.debug("Exception waiting for children: #{$!.message}")
225
+ exit -1
226
+ end
227
+ set_info :pid, nil
228
+ exit 0
229
+ ensure
230
+ RbbtSemaphore.post_semaphore(semaphore) if semaphore
231
+ end
232
+ end
233
+ set_info :forked, true
234
+ Process.detach(@pid)
235
+ self
236
+ end
237
+
238
+ def stop_dependencies
239
+ dependencies.each do |dep|
240
+ dep.abort unless dep.done?
241
+ end
242
+ end
243
+
244
+ def abort_pid
245
+ @pid ||= info[:pid]
246
+
247
+ case @pid
248
+ when nil
249
+ Log.medium "Could not abort #{path}: no pid"
250
+ false
251
+ when Process.pid
252
+ Log.medium "Could not abort #{path}: same process"
253
+ false
254
+ else
255
+ Log.medium "Aborting #{path}: #{ @pid }"
256
+ begin
257
+ Process.kill("KILL", @pid)
258
+ Process.waitpid @pid
259
+ rescue Exception
260
+ Log.debug("Aborted job #{@pid} was not killed: #{$!.message}")
261
+ end
262
+ true
263
+ end
264
+ end
265
+
266
+ def abort_stream
267
+ stream = get_stream if @result
268
+ stream ||= @stream
269
+ if stream
270
+ stream.abort if stream.respond_to? :abort
271
+ end
272
+ end
273
+
274
+ def abort
275
+ begin
276
+ abort_pid
277
+ stop_dependencies
278
+ abort_stream
279
+ ensure
280
+ log(:aborted, "Job aborted")
281
+ end
282
+ end
283
+
284
+ def join_stream
285
+ stream = get_stream if @result
286
+ if stream
287
+ begin
288
+ Misc.consume_stream stream
289
+ stream.join if stream.respond_to? :join # and not stream.joined?
290
+ rescue Exception
291
+ stream.abort if stream.respond_to? :abort
292
+ self.abort
293
+ raise $!
294
+ end
295
+ end
296
+ end
297
+
298
+ def join
299
+
300
+ join_stream
301
+
302
+ return if not Open.exists? info_file
303
+ @pid ||= info[:pid]
304
+
305
+ Misc.insist [0.1, 0.2, 0.5, 1] do
306
+ @pid ||= info[:pid]
307
+ end
308
+
309
+ if @pid.nil?
310
+ dependencies.each{|dep| dep.join }
311
+ self
312
+ else
313
+ begin
314
+ Log.debug{"Waiting for pid: #{@pid}"}
315
+ Process.waitpid @pid
316
+ rescue Errno::ECHILD
317
+ Log.debug{"Process #{ @pid } already finished: #{ path }"}
318
+ end if Misc.pid_exists? @pid
319
+ @pid = nil
320
+ dependencies.each{|dep| dep.join }
321
+ self
322
+ end
323
+ self
324
+ end
325
+ end
@@ -413,9 +413,13 @@ when Step
413
413
  end unless io.closed?
414
414
  io.join if io.respond_to? :join
415
415
  rescue Exception
416
- io.abort if io.respond_to? :abort
417
- ensure
418
- io.join if io.respond_to? :join
416
+ Log.exception $!
417
+ begin
418
+ io.abort if io.respond_to? :abort
419
+ io.join
420
+ ensure
421
+ exit -1
422
+ end
419
423
  end
420
424
  else
421
425
  res.join
@@ -75,6 +75,7 @@ class TestPersist < Test::Unit::TestCase
75
75
  end
76
76
 
77
77
  assert_equal 10, stream.read.split("\n").length
78
+ stream.join
78
79
  end
79
80
  end
80
81
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbbt-util
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.11.5
4
+ version: 5.11.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miguel Vazquez
@@ -205,6 +205,7 @@ files:
205
205
  - lib/rbbt/workflow/doc.rb
206
206
  - lib/rbbt/workflow/soap.rb
207
207
  - lib/rbbt/workflow/step.rb
208
+ - lib/rbbt/workflow/step/run.rb
208
209
  - lib/rbbt/workflow/task.rb
209
210
  - lib/rbbt/workflow/usage.rb
210
211
  - share/Rlib/util.R