rbbt-util 5.27.2 → 5.27.7

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
  SHA256:
3
- metadata.gz: 258aa01482866ef7b940790ad6f10d077a0cd721b972cbb939412c3691595acc
4
- data.tar.gz: 9adb68a2c9ddfa77a3be419dd106e4083e11933dd6653b4d6e0bfa921edab187
3
+ metadata.gz: 6551d632ae1f2289805a53ceaf9db01d0c0a029ea6c76176aed419e4d6a2a485
4
+ data.tar.gz: 72562729535554e718451adb87338503ff40a81874a9e0fed6f8eaf4e6aa0edc
5
5
  SHA512:
6
- metadata.gz: 4df9dcbc8280023faa1e6c2e6a9393a9ae66e4513a95cdeae94256f5fc61f0e6691e114cd1d40a900041e1769988b2a69751f282fc95c0c134acb44cac3ed40c
7
- data.tar.gz: b72bd064835be7c5dcfcf180ff87d6e22fced3f8833d9479f607ab64760594c7d7d25d84cd828b33f0a7d72208983b8c89e26d8924e91afc81ba5e5943ef462d
6
+ metadata.gz: 0d8c3ff2861dd4bbd835e3e41826f5fd6452bdd0b40fbd8378737effdffa6da051ce221e24f4bbacaf952725ccf7da09b533c8c414a7fd10480369ae528a4259
7
+ data.tar.gz: 1790b8f38f91dfbb582a394d86953156d90351a8d724fb9535a3bc72ebac5fbbfe24e88fe10cf943e2ed91ff059af68cf581bac333f5480096f85cf6e29b8018
@@ -4,20 +4,21 @@ class FixWidthTable
4
4
  def initialize(filename, value_size = nil, range = nil, update = false, in_memory = true)
5
5
  @filename = filename
6
6
 
7
- if update or %w(memory stringio).include?(filename.to_s.downcase) or not File.exist?(filename)
7
+ if update || %w(memory stringio).include?(filename.to_s.downcase) || ! File.exist?(filename)
8
8
  Log.debug "FixWidthTable create: #{ filename }"
9
9
  @value_size = value_size
10
10
  @range = range
11
11
  @record_size = @value_size + (@range ? 16 : 8)
12
12
  @write = true
13
13
 
14
- if %w(memory stringio).include? filename.to_s.downcase
14
+ if %w(memory stringio).include?(filename.to_s.downcase)
15
15
  @filename = :memory
16
16
  @file = StringIO.new
17
17
  else
18
18
  FileUtils.rm @filename if File.exist? @filename
19
19
  FileUtils.mkdir_p File.dirname(@filename) unless File.exist? @filename
20
- @file = File.open(@filename, 'wb')
20
+ #@file = File.open(@filename, 'wb')
21
+ @file = File.open(@filename, 'w:ASCII-8BIT')
21
22
  end
22
23
 
23
24
  @file.write [value_size].pack("L")
@@ -25,9 +26,9 @@ class FixWidthTable
25
26
 
26
27
  @size = 0
27
28
  else
28
- Log.debug "FixWidthTable up-to-date: #{ filename }"
29
+ Log.debug "FixWidthTable up-to-date: #{ filename } - (in_memory:#{in_memory})"
29
30
  if in_memory
30
- @file = StringIO.new(Open.read(@filename, :mode => 'r:ASCII-8BIT'), 'r')
31
+ @file = Open.open(@filename, :mode => 'r:ASCII-ASCII'){|f| StringIO.new f.read}
31
32
  else
32
33
  @file = File.open(@filename, 'r:ASCII-8BIT')
33
34
  end
@@ -148,13 +148,13 @@ module Persist
148
148
 
149
149
  data.write_and_read do
150
150
  yield data
151
- end
152
151
 
153
- FileUtils.mv data.persistence_path, path if File.exist? data.persistence_path and not File.exist? path
154
- tsv = CONNECTIONS[path] = CONNECTIONS.delete tmp_path
155
- tsv.persistence_path = path
152
+ FileUtils.mv data.persistence_path, path if File.exist? data.persistence_path and not File.exist? path
153
+ tsv = CONNECTIONS[path] = CONNECTIONS.delete tmp_path
154
+ tsv.persistence_path = path
156
155
 
157
- tsv.fix_io if tsv.respond_to? :fix_io
156
+ tsv.fix_io if tsv.respond_to? :fix_io
157
+ end
158
158
 
159
159
  data
160
160
  rescue Exception
@@ -9,25 +9,10 @@ module Persist
9
9
  @mutex ||= Mutex.new
10
10
  end
11
11
 
12
- def prefix(key)
13
- range(key, 1, key + MAX_CHAR, 1)
14
- end
15
-
16
- def get_prefix(key)
17
- keys = prefix(key)
18
- select(:key => keys)
19
- end
20
-
21
12
  def closed?
22
13
  @closed
23
14
  end
24
15
 
25
- def close
26
- @closed = true
27
- super
28
- self
29
- end
30
-
31
16
  def write?
32
17
  @writable
33
18
  end
@@ -47,8 +32,10 @@ module Persist
47
32
  def close(*args)
48
33
  begin
49
34
  super(*args)
35
+ @closed = true
50
36
  rescue NoMethodError
51
37
  end
38
+ self
52
39
  end
53
40
 
54
41
  def read(*args)
@@ -58,25 +45,14 @@ module Persist
58
45
  end
59
46
  end
60
47
 
61
- def collect
62
- res = []
63
- each do |key, value|
64
- res << if block_given?
65
- yield key, value
66
- else
67
- [key, value]
68
- end
69
- end
70
- res
71
- end
72
-
73
48
  def delete(key)
74
49
  out(key)
75
50
  end
76
51
 
77
52
  def lock
78
- #return yield if @locked
53
+ return yield if @locked
79
54
  lock_filename = Persist.persistence_path(persistence_path, {:dir => TSV.lock_dir})
55
+ Log.stack caller if $LOG
80
56
  Misc.lock(lock_filename) do
81
57
  begin
82
58
  @locked = true
@@ -87,6 +63,16 @@ module Persist
87
63
  end
88
64
  end
89
65
 
66
+ def lock_and_close
67
+ lock do
68
+ begin
69
+ yield
70
+ ensure
71
+ close
72
+ end
73
+ end
74
+ end
75
+
90
76
  def write_and_read
91
77
  if write?
92
78
  begin
@@ -97,7 +83,7 @@ module Persist
97
83
  end
98
84
 
99
85
  lock do
100
- write true if closed? or not write?
86
+ write(true) if closed? || !write?
101
87
  begin
102
88
  yield
103
89
  ensure
@@ -111,12 +97,12 @@ module Persist
111
97
  begin
112
98
  return yield
113
99
  ensure
114
- close
100
+ close unless @locked
115
101
  end
116
102
  end
117
103
 
118
104
  lock do
119
- write true if closed? || ! write?
105
+ write(true) if closed? || ! write?
120
106
  res = begin
121
107
  yield
122
108
  rescue Exception
@@ -130,11 +116,12 @@ module Persist
130
116
  end
131
117
 
132
118
  def read_and_close
133
- if read?
119
+ #return yield if @locked
120
+ if read? || write?
134
121
  begin
135
122
  return yield
136
123
  ensure
137
- close
124
+ close unless @locked
138
125
  end
139
126
  end
140
127
 
@@ -148,21 +135,85 @@ module Persist
148
135
  end
149
136
  end
150
137
 
151
-
152
138
  def merge!(hash)
153
139
  hash.each do |key,values|
154
140
  self[key] = values
155
141
  end
156
142
  end
157
143
 
158
-
159
144
  def range(*args)
160
- super(*args) #- TSV::ENTRY_KEYS.to_a
145
+ self.read_and_close do
146
+ super(*args)
147
+ end
161
148
  end
162
149
 
163
150
  def include?(*args)
164
- read if closed?
165
- super(*args) #- TSV::ENTRY_KEYS.to_a
151
+ self.read_and_close do
152
+ super(*args) #- TSV::ENTRY_KEYS.to_a
153
+ end
154
+ end
155
+
156
+ def [](*args)
157
+ self.read_and_close do
158
+ super(*args) #- TSV::ENTRY_KEYS.to_a
159
+ end
160
+ end
161
+
162
+ def []=(*args)
163
+ self.write_and_close do
164
+ super(*args) #- TSV::ENTRY_KEYS.to_a
165
+ end
166
+ end
167
+
168
+ def keys(*args)
169
+ self.read_and_close do
170
+ super(*args)
171
+ end
172
+ end
173
+
174
+
175
+ def prefix(key)
176
+ self.read_and_close do
177
+ range(key, 1, key + MAX_CHAR, 1)
178
+ end
179
+ end
180
+
181
+ def get_prefix(key)
182
+ keys = prefix(key)
183
+ select(:key => keys)
184
+ end
185
+
186
+
187
+ def size(*args)
188
+ self.read_and_close do
189
+ super(*args)
190
+ end
191
+ end
192
+
193
+ def each(*args, &block)
194
+ self.read_and_close do
195
+ super(*args, &block)
196
+ end
197
+ end
198
+
199
+ def collect
200
+ res = []
201
+ each do |key, value|
202
+ res << if block_given?
203
+ yield key, value
204
+ else
205
+ [key, value]
206
+ end
207
+ end
208
+ res
209
+ end
210
+
211
+ def values_at(*keys)
212
+ self.read_and_close do
213
+ keys.collect do |k|
214
+ self[k]
215
+ end
216
+ end
166
217
  end
167
218
  end
168
219
  end
@@ -16,7 +16,7 @@ module Persist
16
16
  end
17
17
 
18
18
  dir = File.dirname(File.expand_path(path))
19
- Open.mkdir(dir) unless Open.exists?(dir)
19
+ File.mkdir(dir) unless File.exists?(dir)
20
20
 
21
21
  tokyocabinet_class = TokyoCabinet::HDB if tokyocabinet_class == "HDB" or tokyocabinet_class.nil?
22
22
  tokyocabinet_class = TokyoCabinet::BDB if tokyocabinet_class == "BDB"
@@ -87,13 +87,15 @@ module Persist
87
87
  def self.open_tokyocabinet(path, write, serializer = nil, tokyocabinet_class = TokyoCabinet::HDB)
88
88
  write = true unless File.exist? path
89
89
 
90
- FileUtils.mkdir_p File.dirname(path) unless Open.exist?(File.dirname(path))
90
+ FileUtils.mkdir_p File.dirname(path) unless File.exist?(File.dirname(path))
91
91
 
92
92
  database = Persist::TCAdapter.open(path, write, tokyocabinet_class)
93
93
 
94
94
  unless serializer == :clean
95
95
  TSV.setup database
96
- database.serializer = serializer || database.serializer
96
+ database.write_and_read do
97
+ database.serializer = serializer
98
+ end if serializer && database.serializer != serializer
97
99
  end
98
100
 
99
101
  database
@@ -170,10 +170,12 @@ module Resource
170
170
  if type and not File.exist?(final_path) or force
171
171
  Log.medium "Producing: #{ final_path }"
172
172
  lock_filename = Persist.persistence_path(final_path, {:dir => Resource.lock_dir})
173
+
173
174
  Misc.lock lock_filename do
174
175
  FileUtils.rm_rf final_path if force and File.exist? final_path
175
- if not File.exist?(final_path) or force
176
- (remote_server and get_from_server(path, final_path)) or
176
+
177
+ if ! File.exist?(final_path) || force
178
+
177
179
  begin
178
180
  case type
179
181
  when :string
@@ -291,7 +293,7 @@ url='#{url}'
291
293
  rescue
292
294
  FileUtils.rm_rf final_path if File.exist? final_path
293
295
  raise $!
294
- end
296
+ end unless (remote_server && get_from_server(path, final_path))
295
297
  end
296
298
  end
297
299
  end
@@ -304,11 +306,12 @@ url='#{url}'
304
306
  resource ||= Rbbt
305
307
  (Path::STANDARD_SEARCH + resource.search_order + resource.search_paths.keys).uniq.each do |name|
306
308
  pattern = resource.search_paths[name]
307
- next if patterns.nil?
309
+ next if pattern.nil?
310
+ pattern = pattern.sub('{PWD}', Dir.pwd)
308
311
  if String === pattern and pattern.include?('{')
309
312
  regexp = "^" + pattern.gsub(/{([^}]+)}/,'(?<\1>[^/]+)') + "(?:/(?<REST>.*))?/?$"
310
313
  if m = path.match(regexp)
311
- if m["PKGDIR"] == resource.pkgdir
314
+ if ! m.named_captures.include?("PKGDIR") || m["PKGDIR"] == resource.pkgdir
312
315
  return self[m["TOPLEVEL"]][m["SUBPATH"]][m["REST"]]
313
316
  end
314
317
  end
@@ -199,7 +199,7 @@ module Path
199
199
  next if res
200
200
  next unless paths.include? w
201
201
  path = find(w, caller_lib, paths)
202
- res = path if File.exist? path
202
+ res = path if File.exist?(path)
203
203
  end if res.nil?
204
204
 
205
205
  (paths.keys - STANDARD_SEARCH - search_order).each do |w|
@@ -241,8 +241,8 @@ module Path
241
241
  sub('{REMOVE}/', '').
242
242
  sub('{REMOVE}', '')
243
243
 
244
- path = path + '.gz' if File.exist? path + '.gz'
245
- path = path + '.bgz' if File.exist? path + '.bgz'
244
+ path = path + '.gz' if File.exist?(path + '.gz')
245
+ path = path + '.bgz' if File.exist?(path + '.bgz')
246
246
 
247
247
  self.annotate path
248
248
 
@@ -243,7 +243,7 @@ module TSV
243
243
  end
244
244
 
245
245
  def []=(key, value, clean = false)
246
- return super(key, value) if clean or value.nil? or TSV::CleanSerializer == self.serializer_module
246
+ return super(key, value) if clean || value.nil? || TSV::CleanSerializer == self.serializer_module
247
247
  super(key, @serializer_module.dump(value))
248
248
  end
249
249
 
@@ -366,11 +366,11 @@ module TSV
366
366
  keys.length
367
367
  end
368
368
 
369
- def values_at(*keys)
370
- keys.collect do |key|
371
- self[key]
372
- end
373
- end
369
+ #def _values_at(*keys)
370
+ # keys.collect do |key|
371
+ # self[key]
372
+ # end
373
+ #end
374
374
 
375
375
  def chunked_values_at(keys, max = 5000)
376
376
  Misc.ordered_divide(keys, max).inject([]) do |acc,c|
@@ -10,7 +10,8 @@ module TSV
10
10
 
11
11
  identifiers = Organism.identifiers(tsv.namespace) if identifiers.nil? and tsv.namespace
12
12
 
13
- if not tsv.fields.include? format
13
+
14
+ if ! tsv.fields.include?(format)
14
15
  new = {}
15
16
  tsv.each do |k,v|
16
17
  if v === String or v === Array
@@ -32,6 +33,7 @@ module TSV
32
33
  tsv = tsv.attach identifiers, :fields => [format], :persist_input => true
33
34
  end
34
35
 
36
+
35
37
  tsv = tsv.reorder(format, tsv.fields[0..-2])
36
38
 
37
39
  tsv = tsv.to_flat if orig_type == :flat
@@ -89,6 +89,7 @@ module TSV
89
89
  stream
90
90
  end
91
91
 
92
+ all_fields = fields
92
93
  key_field = key_fields.compact.first
93
94
  if same_fields
94
95
  fields = fields.first
@@ -15,6 +15,14 @@ end
15
15
  class Aborted < StandardError; end
16
16
 
17
17
  class TryAgain < StandardError; end
18
+
19
+ class TryThis < StandardError
20
+ attr_accessor :payload
21
+ def initialize(payload = nil)
22
+ @payload = payload
23
+ end
24
+ end
25
+
18
26
  class SemaphoreInterrupted < TryAgain; end
19
27
  class LockInterrupted < TryAgain; end
20
28
 
@@ -18,6 +18,8 @@ module Misc
18
18
 
19
19
  BLOCK_SIZE=1024 * 8
20
20
 
21
+ SKIP_TAG="[SKIP TAG]"
22
+
21
23
  PIPE_MUTEX = Mutex.new
22
24
 
23
25
  OPEN_PIPE_IN = []
@@ -29,7 +31,7 @@ module Misc
29
31
 
30
32
  [sout, sin]
31
33
  end
32
- Log.debug{"Creating pipe #{[res.last.inspect,res.first.inspect] * " => "}"}
34
+ Log.debug{"Creating pipe #{[res.last.inspect, res.first.inspect] * " => "}"}
33
35
  res
34
36
  end
35
37
 
@@ -255,6 +257,11 @@ module Misc
255
257
  end
256
258
  tee1, *rest = Misc.tee_stream stream_dup, num + 1
257
259
  stream.reopen(tee1)
260
+
261
+ #ToDo: I can't explain why the @threads variable appears with the value of
262
+ # @filename
263
+ stream.instance_variable_set(:@threads, nil) if stream.instance_variables.include?(:@threads)
264
+
258
265
  tee1.annotate(stream)
259
266
  rest
260
267
  end
@@ -537,18 +544,29 @@ module Misc
537
544
  end
538
545
  end
539
546
 
547
+ def self.buffer_stream(stream)
548
+ sout, sin = Misc.pipe
549
+ Misc.consume_stream(stream, true, sin)
550
+ sout
551
+ end
552
+
540
553
  def self._paste_streams(streams, output, lines = nil, sep = "\t", header = nil, &block)
541
554
  output.puts header if header
542
555
  streams = streams.collect do |stream|
543
556
  if defined? Step and Step === stream
544
- stream.get_stream || stream.join.path.open
557
+ io = stream.get_stream
558
+ if io
559
+ buffer_stream(io)
560
+ else
561
+ stream.join.path.open
562
+ end
545
563
  else
546
564
  stream
547
565
  end
548
566
  end
549
567
 
550
568
  begin
551
- done_streams = []
569
+
552
570
  lines ||= streams.collect{|s| s.gets }
553
571
  keys = []
554
572
  parts = []
@@ -564,6 +582,7 @@ module Misc
564
582
  end
565
583
  sizes = parts.collect{|p| p.nil? ? 0 : p.length }
566
584
  last_min = nil
585
+
567
586
  while lines.compact.any?
568
587
  if block_given?
569
588
  min = keys.compact.sort(&block).first
@@ -571,14 +590,23 @@ module Misc
571
590
  min = keys.compact.sort.first
572
591
  end
573
592
  str = []
593
+ threads = []
574
594
  keys.each_with_index do |key,i|
575
595
  case key
576
596
  when min
577
- str << [parts[i] * sep]
597
+ if parts[i] == [SKIP_TAG]
598
+ str << [sep * (sizes[i]-1)] if sizes[i] > 0
599
+ else
600
+ str << [parts[i] * sep]
601
+ end
602
+
578
603
  line = lines[i] = streams[i].gets
579
- if line.nil?
604
+
605
+ if line.nil?
580
606
  keys[i] = nil
581
607
  parts[i] = nil
608
+ streams[i].close unless streams[i].closed?
609
+ streams[i].join if streams[i].respond_to?(:join)
582
610
  else
583
611
  k, *p = line.chomp.split(sep, -1)
584
612
  keys[i] = k
@@ -589,10 +617,12 @@ module Misc
589
617
  end
590
618
  end
591
619
 
592
- output.puts [min, str*sep] * sep
620
+ output.puts [min, str.flatten*sep] * sep
593
621
  end
622
+
594
623
  streams.each do |stream|
595
- stream.join if stream.respond_to? :join
624
+ stream.close unless stream.closed?
625
+ stream.join if stream.respond_to?(:join)
596
626
  end
597
627
  rescue
598
628
  Log.exception $!
@@ -607,7 +607,7 @@ module Workflow
607
607
  end
608
608
 
609
609
  def self.load_step(path)
610
- Path.setup(path) unless Path === path
610
+ path = Path.setup(path.dup) unless Path === path
611
611
  path = path.find
612
612
 
613
613
  begin
@@ -35,6 +35,7 @@ module Workflow
35
35
  input_use = rec_input_use(name)
36
36
  input_defaults = rec_input_defaults(name)
37
37
  input_options = rec_input_options(name)
38
+ extension = task.extension
38
39
  export = case
39
40
  when (synchronous_exports.include?(name.to_sym) or synchronous_exports.include?(name.to_s))
40
41
  :synchronous
@@ -60,7 +61,8 @@ module Workflow
60
61
  :input_use => input_use,
61
62
  :result_type => result_type,
62
63
  :result_description => result_description,
63
- :dependencies => dependencies
64
+ :dependencies => dependencies,
65
+ :extension => extension
64
66
  }
65
67
  end
66
68
  end
@@ -18,6 +18,7 @@ module Workflow
18
18
  :description => "",
19
19
  :result_type => nil,
20
20
  :result_description => "",
21
+ :resumable => false,
21
22
  :extension => nil)
22
23
 
23
24
 
@@ -33,6 +34,10 @@ module Workflow
33
34
  @extension = extension
34
35
  end
35
36
 
37
+ def resumable
38
+ @resumable = true
39
+ end
40
+
36
41
  def returns(description)
37
42
  @result_description = description
38
43
  end
@@ -118,6 +123,7 @@ module Workflow
118
123
  :input_descriptions => consume_input_descriptions,
119
124
  :required_inputs => consume_required_inputs,
120
125
  :extension => consume_extension,
126
+ :resumable => consume_resumable,
121
127
  :input_options => consume_input_options
122
128
  }
123
129
 
@@ -137,13 +137,15 @@ class RemoteWorkflow
137
137
 
138
138
  post_thread = Thread.new(Thread.current) do |parent|
139
139
  bl = lambda do |rok|
140
- if Net::HTTPOK === rok
140
+ if Net::HTTPOK === rok
141
141
  _url = rok["RBBT-STREAMING-JOB-URL"]
142
142
  @url = File.join(task_url, File.basename(_url)) if _url
143
143
  rok.read_body do |c,_a, _b|
144
144
  sin.write c
145
145
  end
146
146
  sin.close
147
+ elsif Net::HTTPSeeOther === rok
148
+ raise TryThis.new(rok)
147
149
  else
148
150
  err = StringIO.new
149
151
  rok.read_body do |c,_a, _b|
@@ -156,7 +158,7 @@ class RemoteWorkflow
156
158
  err.rewind
157
159
  err.read
158
160
  end
159
- ne = @adaptor.parse_exception text
161
+ ne = RemoteWorkflow.parse_exception text
160
162
  case ne
161
163
  when String
162
164
  parent.raise e.class, ne
@@ -173,7 +175,11 @@ class RemoteWorkflow
173
175
  end
174
176
 
175
177
  Log.debug{ "RestClient execute: #{ task_url } - #{Misc.fingerprint task_params}" }
176
- RestClient::Request.execute(:method => :post, :url => task_url, :payload => task_params, :block_response => bl)
178
+ begin
179
+ RestClient::Request.execute(:method => :post, :url => task_url, :payload => task_params, :block_response => bl)
180
+ rescue TryThis
181
+ RestClient::Request.execute(:method => :get, :url => $!.payload.header[:location], :block_response => bl)
182
+ end
177
183
  end
178
184
 
179
185
  # It seems like now response body are now decoded by Net::HTTP after 2.1
@@ -25,8 +25,13 @@ class RemoteStep < Step
25
25
  end
26
26
 
27
27
  def cache_file
28
- digest = Misc.obj2digest([base_url, task, base_name, inputs])
29
- Rbbt.var.cache.REST[[task, clean_name, digest] * "."].find
28
+ begin
29
+ digest = Misc.obj2digest([base_url, task, base_name, inputs])
30
+ Rbbt.var.cache.REST[[task, clean_name, digest].compact * "."].find
31
+ rescue
32
+ Log.exception $!
33
+ raise $!
34
+ end
30
35
  end
31
36
 
32
37
  def cache_files
@@ -62,7 +67,6 @@ class RemoteStep < Step
62
67
  no_load ? Misc.add_GET_param(path, "_format", "raw") : @result
63
68
  end
64
69
 
65
-
66
70
  def self.get_streams(inputs, stream_input = nil)
67
71
  new_inputs = {}
68
72
  inputs.each do |k,v|
@@ -240,6 +244,7 @@ class RemoteStep < Step
240
244
  return true if cache_files.any?
241
245
  init_job unless @url
242
246
  Log.debug{ "Joining RemoteStep: #{path}" }
247
+
243
248
  if IO === @result
244
249
  res = @result
245
250
  @result = nil
@@ -253,6 +258,7 @@ class RemoteStep < Step
253
258
  sleep 1 unless self.done? || self.aborted? || self.error?
254
259
  while not (self.done? || self.aborted? || self.error?)
255
260
  sleep 3
261
+ iif [self.done?, self.status, self.info]
256
262
  end
257
263
  end
258
264
 
@@ -129,7 +129,7 @@ class RemoteStep
129
129
  end
130
130
  end
131
131
 
132
- def _run_job(cache_type = :async)
132
+ def _run_job(cache_type = :asynchronous)
133
133
  get_streams
134
134
 
135
135
  task_url = URI.encode(File.join(base_url, task.to_s))
@@ -142,7 +142,13 @@ class RemoteStep
142
142
  else
143
143
  @adaptor.execute_job(base_url, task, task_params, cache_type)
144
144
  end
145
+ end
146
+
145
147
 
148
+ def produce(*args)
149
+ @started = true
150
+ _run_job
146
151
  end
152
+
147
153
  end
148
154
  end
@@ -612,6 +612,10 @@ class Step
612
612
  provenance
613
613
  end
614
614
 
615
+ def resumable?
616
+ task && task.resumable
617
+ end
618
+
615
619
  def config(key, *tokens)
616
620
  options = tokens.pop if Hash === tokens.last
617
621
  options ||= {}
@@ -92,7 +92,7 @@ class Step
92
92
  (job.done? && job.dirty?) || (job.error? && job.dirty?) ||
93
93
  (!(job.noinfo? || job.done? || job.error? || job.aborted? || job.running?))
94
94
 
95
- job.clean
95
+ job.clean unless job.resumable? && (job.updated? && ! job.dirty?)
96
96
  job.set_info :status, :cleaned
97
97
  end
98
98
 
@@ -144,14 +144,18 @@ class Step
144
144
 
145
145
  dependency.status_lock.synchronize do
146
146
  if dependency.aborted? || (dependency.error? && dependency.recoverable_error? && ! canfail_paths.include?(dependency.path) && ! already_failed.include?(dependency.path)) || (!Open.remote?(dependency.path) && dependency.missing?)
147
- Log.warn "Cleaning dep. on exec #{Log.color :blue, dependency.path} (missing: #{dependency.missing?}; error #{dependency.error?})"
148
- dependency.clean
149
- already_failed << dependency.path
150
- raise TryAgain
147
+ if dependency.resumable?
148
+ dependency.status = :resume
149
+ else
150
+ Log.warn "Cleaning dep. on exec #{Log.color :blue, dependency.path} (missing: #{dependency.missing?}; error #{dependency.error?})"
151
+ dependency.clean
152
+ already_failed << dependency.path
153
+ raise TryAgain
154
+ end
151
155
  end
152
156
  end
153
157
 
154
- if ! (dependency.started? || dependency.error?)
158
+ if dependency.status == :resume || ! (dependency.started? || dependency.error?)
155
159
  log_dependency_exec(dependency, :starting)
156
160
  dependency.run(true)
157
161
  raise TryAgain
@@ -362,7 +366,7 @@ class Step
362
366
  (step.dependencies + step.input_dependencies).each do |step_dep|
363
367
  next if step_dep.done? or step_dep.running? or (ComputeDependency === step_dep and (step_dep.compute == :nodup or step_dep.compute == :ignore))
364
368
  dep_step[step_dep.path] ||= []
365
- dep_step[step_dep.path] << step_dep
369
+ dep_step[step_dep.path] << step
366
370
  end
367
371
  end
368
372
 
@@ -610,7 +610,7 @@ class Step
610
610
  end
611
611
 
612
612
  def _clean_finished
613
- if Open.exists? path and not status == :done
613
+ if Open.exists?(path) && status != :done
614
614
  Log.warn "Aborted job had finished. Removing result -- #{ path }"
615
615
  begin
616
616
  Open.rm path
@@ -2,7 +2,7 @@ require 'rbbt/util/misc'
2
2
  require 'rbbt/persist'
3
3
 
4
4
  module Task
5
- attr_accessor :inputs, :input_types, :result_type, :input_defaults, :input_descriptions, :input_options, :required_inputs, :description, :name, :result_description, :extension, :workflow
5
+ attr_accessor :inputs, :input_types, :result_type, :input_defaults, :input_descriptions, :input_options, :required_inputs, :description, :name, :result_description, :extension, :workflow, :resumable
6
6
 
7
7
  def self.setup(options = {}, &block)
8
8
  block.extend Task
@@ -125,6 +125,7 @@ class Step
125
125
  def self.migrate(path, search_path, options = {})
126
126
  resource=Rbbt
127
127
 
128
+ orig_path = path
128
129
  other_rsync_args = options[:rsync]
129
130
 
130
131
  recursive = options[:recursive]
@@ -154,6 +155,7 @@ puts files * "\n"
154
155
  else
155
156
  if File.exists?(path)
156
157
  path = resource.identify(path)
158
+ raise "Resource #{resource} could not identify #{orig_path}" if path.nil?
157
159
  else
158
160
  path = Path.setup(path)
159
161
  end
@@ -178,7 +180,7 @@ puts resource[path].find(search_path)
178
180
  subpath_files = {}
179
181
  paths.sort.each do |path|
180
182
  parts = path.split("/")
181
- subpath = parts[0..-4] * "/"
183
+ subpath = parts[0..-4] * "/" + "/"
182
184
 
183
185
  if subpath_files.keys.any? && subpath.start_with?(subpath_files.keys.last)
184
186
  subpath = subpath_files.keys.last
@@ -190,6 +192,7 @@ puts resource[path].find(search_path)
190
192
  subpath_files[subpath] << source
191
193
  end
192
194
 
195
+ synced_files = []
193
196
  subpath_files.each do |subpath, files|
194
197
  if options[:target]
195
198
  CMD.cmd("ssh #{options[:target]} mkdir -p '#{File.dirname(target)}'")
@@ -204,11 +207,15 @@ puts resource[path].find(search_path)
204
207
  end
205
208
  target = [options[:target], target] * ":" if options[:target]
206
209
 
210
+ next if File.exists?(source) && File.exists?(target) && File.expand_path(source) == File.expand_path(target)
211
+
207
212
  files_and_dirs = Set.new( files )
208
213
  files.each do |file|
214
+ synced_files << File.join(subpath, file)
215
+
209
216
  parts = file.split("/")[0..-2].reject{|p| p.empty?}
210
217
  while parts.any?
211
- files_and_dirs << parts * "/"
218
+ files_and_dirs << parts * "/"
212
219
  parts.pop
213
220
  end
214
221
  end
@@ -218,8 +225,7 @@ puts resource[path].find(search_path)
218
225
 
219
226
  cmd = "rsync #{MAIN_RSYNC_ARGS} --progress #{test_str} --files-from='#{tmp_include_file}' #{source}/ #{target}/ #{other_rsync_args}"
220
227
 
221
- cmd << " && rm -Rf #{source}" if options[:delete]
222
-
228
+ #cmd << " && rm -Rf #{source}" if options[:delete]
223
229
  if options[:print]
224
230
  ppp Open.read(tmp_include_file)
225
231
  puts cmd
@@ -228,6 +234,26 @@ puts resource[path].find(search_path)
228
234
  end
229
235
  end
230
236
  end
237
+
238
+ if options[:delete] && synced_files.any?
239
+ puts Log.color :magenta, "About to erase these files:"
240
+ synced_files.each do |p|
241
+ puts Log.color :red, p
242
+ end
243
+
244
+ if options[:non_interactive]
245
+ response = 'yes'
246
+ else
247
+ puts Log.color :magenta, "Type 'yes' if you are sure:"
248
+ response = STDIN.gets.chomp
249
+ end
250
+
251
+ if response == 'yes'
252
+ synced_files.each do |p|
253
+ Open.rm p
254
+ end
255
+ end
256
+ end
231
257
  end
232
258
 
233
259
  def self.purge(path, recursive = false)
@@ -71,7 +71,7 @@ get_pkg(){
71
71
  local url="$2"
72
72
 
73
73
  if [ ! -f "$OPT_SRC_DIR/$name.pkg" ]; then
74
- wget "$url" -O "$OPT_SRC_DIR/$name.pkg" || wget "$url" -O "$OPT_SRC_DIR/$name.pkg" --no-check-certificate
74
+ wget "$url" -O "$OPT_SRC_DIR/$name.pkg" || wget "$url" -O "$OPT_SRC_DIR/$name.pkg" --no-check-certificate || (rm -f "$OPT_SRC_DIR/$name.pkg"; echo "Error downloading"; exit -1)
75
75
  fi
76
76
  }
77
77
 
@@ -85,7 +85,7 @@ uncompress_pkg(){
85
85
  mkdir -p "$OPT_BUILD_DIR"
86
86
  cd "$OPT_BUILD_DIR"
87
87
 
88
- (tar xvfz $pkg || tar xvfJ $pkg || tar xvfj $pkg || unzip $pkg || echo "Error decompressing") 2> /dev/null
88
+ (tar xvfz $pkg || tar xvfJ $pkg || tar xvfj $pkg || unzip $pkg || (echo "Error decompressing" & cd & rmdir "$OPT_BUILD_DIR" & exit -1 ) ) 2> /dev/null
89
89
 
90
90
  cd "$old_pwd"
91
91
  }
@@ -207,6 +207,8 @@ prepare_make(){
207
207
 
208
208
  [ -d src -a ! -e CMakeLists.txt -a ! -e Makefile -a ! -e configure ] && cd src
209
209
 
210
+ [ -f bootstrap ] && (./bootstrap || exit -1)
211
+
210
212
  if [ -f config/m4 ]; then
211
213
  libtoolize --force
212
214
  aclocal
@@ -275,6 +277,8 @@ build_make(){
275
277
  setup "$name"
276
278
  clean_build
277
279
  fi
280
+
281
+ cd "$old_pwd"
278
282
  }
279
283
 
280
284
  buid_cmake(){
@@ -489,7 +493,7 @@ install_jar(){
489
493
  local url="$2"
490
494
 
491
495
  [ -d "$OPT_DIR/$name/" ] || mkdir -p "$OPT_DIR/$name/"
492
- wget "$url" -O "$OPT_DIR/$name/$name.jar" --no-check-certificate
496
+ wget "$url" -O "$OPT_DIR/jars/$name.jar" || wget "$url" -O "$OPT_DIR/jars/$name.jar" --no-check-certificate || (rm "$OPT_DIR/jars/$name.jar"; exit -1)
493
497
  link "$OPT_DIR/$name/$name.jar" "$OPT_JAR_DIR/$name.jar"
494
498
  }
495
499
 
@@ -3,7 +3,7 @@
3
3
  require 'rbbt-util'
4
4
  require 'rbbt/util/simpleopt'
5
5
  require 'rbbt/workflow'
6
- require 'rbbt/workflow/remote/ssh/get'
6
+ require 'rbbt/workflow/remote_workflow'
7
7
 
8
8
  $0 = "rbbt #{$previous_commands*""} #{ File.basename(__FILE__) }" if $previous_commands
9
9
 
@@ -34,4 +34,6 @@ end
34
34
 
35
35
  path, search_path, _sep, *other = ARGV
36
36
 
37
+ search_path = 'user' if search_path.nil?
38
+
37
39
  Step.migrate(path, search_path, options)
@@ -187,7 +187,7 @@ workflows.sort.each do |workflow,tasks|
187
187
  if info_fields and info_fields.any?
188
188
  info = begin
189
189
  Open.open(i[:info_file]) do |f|
190
- Step::INFO_SERIALIAZER.load(f)
190
+ Step::INFO_SERIALIZER.load(f)
191
191
  end
192
192
  rescue
193
193
  {:status => :noinfo}
@@ -198,9 +198,10 @@ workflows.sort.each do |workflow,tasks|
198
198
  else
199
199
  info = begin
200
200
  Open.open(i[:info_file]) do |f|
201
- Step::INFO_SERIALIAZER.load(f)
201
+ Step::INFO_SERIALIZER.load(f)
202
202
  end
203
203
  rescue
204
+ Log.exception $!
204
205
  {:status => :noinfo}
205
206
  end
206
207
  IndiferentHash.setup(info)
@@ -41,7 +41,7 @@ def list_jobs(options)
41
41
  clean_file = file.sub('.info','')
42
42
  begin
43
43
  next if File.exist? clean_file and $quick
44
- info = Step::INFO_SERIALIAZER.load(Open.read(file, :mode => 'rb'))
44
+ info = Step::INFO_SERIALIZER.load(Open.read(file, :mode => 'rb'))
45
45
  next if (File.exist?(clean_file) or info[:status] == :done) and (info[:children_pids].nil? or info[:children_done] or info[:children_pids].select{|pid| Misc.pid_exists? pid}.empty?)
46
46
  rescue Exception
47
47
  puts "Error parsing info file: #{ file }"
@@ -86,7 +86,7 @@ def clean_jobs(options)
86
86
  info = nil
87
87
  next if File.exist? clean_file
88
88
  begin
89
- info = Step::INFO_SERIALIAZER.load(Open.read(file, :mode => 'rb'))
89
+ info = Step::INFO_SERIALIZER.load(Open.read(file, :mode => 'rb'))
90
90
  rescue Exception
91
91
  Log.debug "Error process #{ file }"
92
92
  remove_job file if options[:errors]
@@ -117,7 +117,7 @@ begin
117
117
  end
118
118
  else
119
119
  if options[:file]
120
- info = Step::INFO_SERIALIAZER.load(Open.read(options[:file], :mode => 'rb'))
120
+ info = Step::INFO_SERIALIZER.load(Open.read(options[:file], :mode => 'rb'))
121
121
  print_job options[:file], info
122
122
  else
123
123
  list_jobs options
@@ -4,6 +4,7 @@ require 'rbbt/tsv/stream'
4
4
  require 'rbbt'
5
5
 
6
6
  class TestStream < Test::Unit::TestCase
7
+
7
8
  def test_collapse_stream
8
9
  text=<<-EOF
9
10
  #: :sep=" "
@@ -65,7 +66,7 @@ row3 AAA BBB CCC
65
66
 
66
67
  text2=<<-EOF
67
68
  #: :sep=" "
68
- #Row Labela Labelb
69
+ #Row Labela Labelb
69
70
  row1 a b
70
71
  row3 aaa bbb
71
72
  row2 aa bb
@@ -100,7 +101,7 @@ row1 A B C
100
101
 
101
102
  text2=<<-EOF
102
103
  #: :sep=" "
103
- #Row Labela Labelb
104
+ #Row Labela Labelb
104
105
  row2 aa bb
105
106
  EOF
106
107
 
@@ -132,7 +133,7 @@ row1 A B C
132
133
 
133
134
  text2=<<-EOF
134
135
  #: :sep=" "
135
- #Row Labela Labelb
136
+ #Row Labela Labelb
136
137
  row2 aa bb
137
138
  EOF
138
139
 
@@ -285,7 +285,7 @@ line4
285
285
  begin
286
286
  Misc.consume_stream(sio, false, STDOUT)
287
287
  rescue
288
- Log.exception $!
288
+ raise $!
289
289
  end
290
290
  end
291
291
  end
@@ -4,6 +4,27 @@ require 'rbbt/workflow'
4
4
  module DepWorkflow
5
5
  extend Workflow
6
6
 
7
+ input :input_file, :file, "Input file", nil, :stream => true
8
+ task :s1 => :array do |input_file|
9
+ TSV.traverse input_file, :type => :array, :into => :stream, :bar => "Task1" do |line|
10
+ line + "\t" << "Task1"
11
+ end
12
+ end
13
+
14
+ dep :s1
15
+ task :s2 => :array do |input_file|
16
+ TSV.traverse step(:s1), :type => :array, :into => :stream, :bar => "Task2" do |line|
17
+ next [line.split("\t").first, Misc::SKIP_TAG] * "\t" if rand < 0.9
18
+ line + "\t" << "Task2"
19
+ end
20
+ end
21
+
22
+ dep :s1
23
+ dep :s2
24
+ task :s3 => :array do |input_file|
25
+ Misc.paste_streams(dependencies.reverse)
26
+ end
27
+
7
28
  input :input_file, :file, "Input file", nil, :stream => true
8
29
  task :task1 => :array do |input_file|
9
30
  TSV.traverse input_file, :type => :array, :into => :stream, :bar => "Task1" do |line|
@@ -28,9 +49,7 @@ module DepWorkflow
28
49
  dep :task2
29
50
  dep :task3
30
51
  task :task4 => :array do
31
- s1 = TSV.get_stream step(:task2)
32
- s2 = TSV.get_stream step(:task3)
33
- Misc.paste_streams([s1, s2])
52
+ Misc.paste_streams(dependencies)
34
53
  end
35
54
 
36
55
  dep :task4
@@ -43,9 +62,7 @@ module DepWorkflow
43
62
  dep :task2
44
63
  dep :task5
45
64
  task :task6 => :array do
46
- s1 = TSV.get_stream step(:task2)
47
- s2 = TSV.get_stream step(:task5)
48
- Misc.paste_streams([s1, s2])
65
+ Misc.paste_streams(dependencies)
49
66
  end
50
67
 
51
68
  input :stream_file, :file, "Streamed file", nil, :stream => true
@@ -81,6 +98,26 @@ module ComputeWorkflow
81
98
 
82
99
  end
83
100
 
101
+ module ResumeWorkflow
102
+ extend Workflow
103
+
104
+ resumable
105
+ task :resume => :string do
106
+ if file('foo').exists?
107
+ 'done'
108
+ else
109
+ Open.mkdir files_dir
110
+ Open.touch(file('foo'))
111
+ raise
112
+ end
113
+ end
114
+
115
+ dep :resume
116
+ task :reverse => :string do
117
+ step(:resume).load.reverse
118
+ end
119
+ end
120
+
84
121
  class TestWorkflowDependency < Test::Unit::TestCase
85
122
  def test_task1
86
123
  size = 10000
@@ -114,8 +151,25 @@ class TestWorkflowDependency < Test::Unit::TestCase
114
151
  end
115
152
  end
116
153
 
154
+ def test_task3
155
+ size = 100000
156
+ content = (0..size).to_a.collect{|num| "Line #{num}" } * "\n"
157
+ TmpFile.with_file(content) do |input_file|
158
+ job = DepWorkflow.job(:task3, "TEST", :input_file => input_file)
159
+ io = TSV.get_stream job.run(:stream)
160
+ last_line = nil
161
+ while line = io.gets
162
+ last_line = line.strip
163
+ end
164
+ io.join
165
+
166
+ assert_equal "Line #{size}\tTask1\tTask3", last_line
167
+ end
168
+ end
169
+
117
170
  def test_task4
118
- size = 1000
171
+ size = 100000
172
+ Log.severity = 0
119
173
  content = (0..size).to_a.collect{|num| "Line #{num}" } * "\n"
120
174
  last_line = nil
121
175
  TmpFile.with_file(content) do |input_file|
@@ -131,7 +185,7 @@ class TestWorkflowDependency < Test::Unit::TestCase
131
185
  end
132
186
 
133
187
  def test_task5
134
- size = 1000
188
+ size = 10000
135
189
  content = (0..size).to_a.collect{|num| "Line #{num}" } * "\n"
136
190
  last_line = nil
137
191
  TmpFile.with_file(content) do |input_file|
@@ -145,20 +199,44 @@ class TestWorkflowDependency < Test::Unit::TestCase
145
199
  assert_equal "Line #{size}\tTask1\tTask2\tTask1\tTask3\tTask5", last_line
146
200
  end
147
201
 
148
- def test_task6
202
+ def test_s3
149
203
  size = 100000
150
- content = (0..size).to_a.collect{|num| "Line #{num}" } * "\n"
204
+ content = (1..size).to_a.collect{|num| "Line #{num}" } * "\n"
151
205
  last_line = nil
152
206
  Log.severity = 0
153
207
  TmpFile.with_file(content) do |input_file|
154
208
  begin
155
- job = DepWorkflow.job(:task6, "TEST", :input_file => input_file)
156
- job.run(:stream)
157
- io = TSV.get_stream job
158
- while line = io.gets
159
- last_line = line.strip
209
+ job = DepWorkflow.job(:s3, "TEST", :input_file => input_file)
210
+ job.recursive_clean
211
+ job.run(:stream)
212
+ io = TSV.get_stream job
213
+ while line = io.gets
214
+ last_line = line.strip
215
+ end
216
+ io.join if io.respond_to? :join
217
+ rescue Exception
218
+ job.abort
219
+ raise $!
160
220
  end
161
- io.join
221
+ end
222
+ assert last_line.include? "Line #{size}"
223
+ end
224
+
225
+ def test_task6
226
+ size = 100000
227
+ content = (1..size).to_a.collect{|num| "Line #{num}" } * "\n"
228
+ last_line = nil
229
+ Log.severity = 0
230
+ TmpFile.with_file(content) do |input_file|
231
+ begin
232
+ job = DepWorkflow.job(:task6, "TEST", :input_file => input_file)
233
+ job.recursive_clean
234
+ job.run(:stream)
235
+ io = TSV.get_stream job
236
+ while line = io.gets
237
+ last_line = line.strip
238
+ end
239
+ io.join
162
240
  rescue Exception
163
241
  job.abort
164
242
  raise $!
@@ -168,7 +246,7 @@ class TestWorkflowDependency < Test::Unit::TestCase
168
246
  end
169
247
 
170
248
  def test_task8
171
- size = 100000
249
+ size = 10000
172
250
  content = (0..size).to_a.collect{|num| "Line #{num}" } * "\n"
173
251
  last_line = nil
174
252
  Log.severity = 0
@@ -204,5 +282,16 @@ class TestWorkflowDependency < Test::Unit::TestCase
204
282
  assert_equal "Line #{size}\tTask1\tTask2", last_line
205
283
  end
206
284
  end
285
+
286
+ def test_resume
287
+ Log.severity = 0
288
+ job = ResumeWorkflow.job(:reverse)
289
+ job.recursive_clean
290
+ assert_raise do
291
+ job.run
292
+ end
293
+ assert job.dependencies.first.file('foo').exists?
294
+ assert_equal 'done'.reverse, job.run
295
+ end
207
296
  end
208
297
 
@@ -61,6 +61,18 @@ class TestRemoteWorkflow < Test::Unit::TestCase
61
61
  def test_rest
62
62
  Log.with_severity 0 do
63
63
 
64
+ remote_workflow_server(TestWFRest) do |client|
65
+ job = client.job(:hi, nil, {})
66
+ job.clean
67
+ job = client.job(:hi, nil, {})
68
+ assert ! job.done?
69
+ job.run
70
+ job.produce
71
+ job = client.job(:hi, nil, {})
72
+ assert job.done?
73
+ sleep 1
74
+ end
75
+
64
76
  remote_workflow_server(TestWFRest) do |client|
65
77
  assert_equal "Hello World", client.job(:hi, nil, {}).run.chomp
66
78
  assert_equal "Hello Miguel", client.job(:hi, nil, {:name => :Miguel}).run.chomp
@@ -78,7 +90,7 @@ class TestRemoteWorkflow < Test::Unit::TestCase
78
90
 
79
91
  def _test_ssh
80
92
  Log.severity = 0
81
- client = RemoteWorkflow.new "ssh://turbo:Translation", "Translation"
93
+ client = RemoteWorkflow.new "ssh://#{ENV["HOSTNAME"]}:Translation", "Translation"
82
94
  job = client.job("translate", "SSH-TEST-1", :genes => ["TP53","KRAS"])
83
95
  assert_equal 2, job.run.select{|l| l =~ /ENSG/}.length
84
96
  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.27.2
4
+ version: 5.27.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miguel Vazquez
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-29 00:00:00.000000000 Z
11
+ date: 2020-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake