rbbt-util 5.30.9 → 5.31.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rbbt/hpc.rb +3 -0
  3. data/lib/rbbt/hpc/batch.rb +623 -0
  4. data/lib/rbbt/hpc/lsf.rb +119 -0
  5. data/lib/rbbt/hpc/orchestrate.rb +24 -19
  6. data/lib/rbbt/hpc/slurm.rb +62 -559
  7. data/lib/rbbt/resource/path.rb +3 -1
  8. data/lib/rbbt/tsv/accessor.rb +5 -2
  9. data/lib/rbbt/tsv/dumper.rb +1 -0
  10. data/lib/rbbt/tsv/parallel/traverse.rb +1 -1
  11. data/lib/rbbt/tsv/stream.rb +5 -6
  12. data/lib/rbbt/util/cmd.rb +15 -1
  13. data/lib/rbbt/util/config.rb +2 -2
  14. data/lib/rbbt/util/log.rb +22 -1
  15. data/lib/rbbt/util/log/progress.rb +17 -2
  16. data/lib/rbbt/util/log/progress/report.rb +36 -3
  17. data/lib/rbbt/util/misc/development.rb +2 -2
  18. data/lib/rbbt/util/misc/inspect.rb +17 -1
  19. data/lib/rbbt/util/misc/omics.rb +60 -1
  20. data/lib/rbbt/util/misc/options.rb +5 -0
  21. data/lib/rbbt/workflow/accessor.rb +7 -2
  22. data/lib/rbbt/workflow/definition.rb +7 -3
  23. data/lib/rbbt/workflow/step/accessor.rb +1 -1
  24. data/lib/rbbt/workflow/step/run.rb +9 -0
  25. data/lib/rbbt/workflow/usage.rb +13 -13
  26. data/lib/rbbt/workflow/util/archive.rb +5 -3
  27. data/lib/rbbt/workflow/util/provenance.rb +26 -21
  28. data/share/config.ru +3 -3
  29. data/share/rbbt_commands/{slurm → hpc}/clean +91 -18
  30. data/share/rbbt_commands/{slurm → hpc}/list +119 -31
  31. data/share/rbbt_commands/hpc/orchestrate +81 -0
  32. data/share/rbbt_commands/hpc/tail +81 -0
  33. data/share/rbbt_commands/hpc/task +80 -0
  34. data/test/rbbt/hpc/test_batch.rb +65 -0
  35. data/test/rbbt/hpc/test_slurm.rb +30 -0
  36. data/test/rbbt/util/misc/test_development.rb +11 -0
  37. data/test/rbbt/util/test_config.rb +13 -3
  38. data/test/test_helper.rb +3 -1
  39. metadata +16 -7
  40. data/share/rbbt_commands/slurm/orchestrate +0 -48
  41. data/share/rbbt_commands/slurm/task +0 -46
@@ -3,7 +3,7 @@ require 'rbbt/util/misc/indiferent_hash'
3
3
  require 'yaml'
4
4
 
5
5
  module Path
6
- attr_accessor :resource, :pkgdir, :original, :search_paths, :search_order, :libdir
6
+ attr_accessor :resource, :pkgdir, :original, :search_paths, :search_order, :libdir, :where
7
7
 
8
8
  def self.setup(string, pkgdir = nil, resource = nil, search_paths = nil, search_order = nil, libdir = nil)
9
9
  return string if string.nil?
@@ -99,6 +99,7 @@ module Path
99
99
 
100
100
  paths = paths.each do |p|
101
101
  p.original = File.join(found.original, p.sub(/^#{found}/, ''))
102
+ p.where = where
102
103
  end if found.original and pattern
103
104
 
104
105
  location_paths[where] = paths
@@ -256,6 +257,7 @@ module Path
256
257
  end
257
258
 
258
259
  res.original = self.original || self
260
+ res.where = where
259
261
 
260
262
  res
261
263
  end
@@ -713,8 +713,11 @@ module TSV
713
713
  break
714
714
  end
715
715
 
716
- filename = Path === filename ? filename.find : (filename || "No filename")
717
- filename + " [" + persistence_path + "]" if respond_to?(:persistence_path) and persistence_path
716
+ filename = @filename
717
+ filename = "No filename" if filename.nil? || filename.empty?
718
+ filename.find if Path === filename
719
+ filename = File.basename(filename) + " [" + File.basename(persistence_path) + "]" if respond_to?(:persistence_path) and persistence_path
720
+
718
721
  with_unnamed do
719
722
  <<-EOF
720
723
  Filename = #{filename}
@@ -78,6 +78,7 @@ module TSV
78
78
  end
79
79
 
80
80
  def close_in
81
+ @in_stream.join if @in_stream.respond_to?(:join) && ! @in_stream.joined?
81
82
  @in_stream.close unless @in_stream.closed?
82
83
  end
83
84
 
@@ -610,7 +610,7 @@ module TSV
610
610
  thread = Thread.new do
611
611
  begin
612
612
  traverse_run(obj, threads, cpus, options, &block)
613
- into.close if into.respond_to?(:close) and not (into.respond_to? :closed? and into.closed?)
613
+ into.close if into.respond_to?(:close) and not (into.respond_to?(:closed?) and into.closed?)
614
614
  rescue Exception
615
615
  abort_stream obj
616
616
  abort_stream into
@@ -294,20 +294,19 @@ module TSV
294
294
  end
295
295
 
296
296
 
297
- def self.reorder_stream_tsv(stream, key_field, fields=nil, zipped = true)
297
+ def self.reorder_stream_tsv(stream, key_field, fields=nil, zipped = true, bar = nil)
298
298
  parser = TSV::Parser.new TSV.get_stream(stream), :key_field => key_field, :fields => fields
299
299
  dumper_options = parser.options
300
300
  dumper = TSV::Dumper.new dumper_options
301
301
  dumper.init
302
302
  case parser.type
303
303
  when :single
304
- TSV.traverse parser, :into => dumper do |keys,values|
304
+ TSV.traverse parser, :into => dumper, :bar => bar do |keys,values|
305
305
  key = keys.first
306
306
  [key, [values]]
307
307
  end
308
308
  when :double
309
- TSV.traverse parser, :into => dumper do |keys,values|
310
- raise [keys, values].inspect if keys.include? 'gain'
309
+ TSV.traverse parser, :into => dumper, :bar => bar do |keys,values|
311
310
  res = []
312
311
  keys.each_with_index do |key,i|
313
312
  vs = zipped ? values.collect{|l| l.length == 1 ? l : [l[i]] } : values
@@ -317,12 +316,12 @@ module TSV
317
316
  res
318
317
  end
319
318
  when :list
320
- TSV.traverse parser, :into => dumper do |keys,values|
319
+ TSV.traverse parser, :into => dumper, :bar => bar do |keys,values|
321
320
  key = keys === Array ? keys.first : keys
322
321
  [key, values]
323
322
  end
324
323
  when :flat
325
- TSV.traverse parser, :into => dumper do |keys,values|
324
+ TSV.traverse parser, :into => dumper, :bar => bar do |keys,values|
326
325
  key = keys === Array ? keys.first : keys
327
326
  [key, values]
328
327
  end
data/lib/rbbt/util/cmd.rb CHANGED
@@ -101,6 +101,7 @@ module CMD
101
101
  no_fail = options.delete(:nofail) if no_fail.nil?
102
102
  no_wait = options.delete(:no_wait)
103
103
  xvfb = options.delete(:xvfb)
104
+ bar = options.delete(:progress_bar)
104
105
 
105
106
  dont_close_in = options.delete(:dont_close_in)
106
107
 
@@ -183,6 +184,7 @@ module CMD
183
184
 
184
185
  err_thread = Thread.new do
185
186
  while line = serr.gets
187
+ bar.process(line) if bar
186
188
  sout.log = line
187
189
  Log.log "STDERR [#{pid}]: " + line, stderr
188
190
  end if Integer === stderr and log
@@ -220,6 +222,8 @@ module CMD
220
222
  def self.cmd_pid(*args)
221
223
  all_args = *args
222
224
 
225
+ bar = all_args.last[:progress_bar] if Hash === all_args.last
226
+
223
227
  all_args << {} unless Hash === all_args.last
224
228
 
225
229
  level = all_args.last[:log] || 0
@@ -233,17 +237,27 @@ module CMD
233
237
  io = cmd(*all_args)
234
238
  pid = io.pids.first
235
239
 
240
+ line = "" if bar
236
241
  while c = io.getc
237
242
  STDERR << c if Log.severity <= level
243
+ line << c if bar
238
244
  if c == "\n"
245
+ bar.process(line) if bar
239
246
  if pid
240
247
  Log.logn "STDOUT [#{pid}]: ", level
241
248
  else
242
249
  Log.logn "STDOUT: ", level
243
250
  end
251
+ line = "" if bar
244
252
  end
245
253
  end
246
- io.join
254
+ begin
255
+ io.join
256
+ bar.remove if bar
257
+ rescue
258
+ bar.remove(true) if bar
259
+ raise $!
260
+ end
247
261
 
248
262
  nil
249
263
  end
@@ -90,6 +90,8 @@ module Rbbt::Config
90
90
  options = tokens.pop if Hash === tokens.last
91
91
  default = options.nil? ? nil : options[:default]
92
92
 
93
+ tokens = ["key:" + key] if tokens.empty?
94
+
93
95
  tokens = tokens.flatten
94
96
  file, _sep, line = caller.reject{|l|
95
97
  l =~ /rbbt\/(?:resource\.rb|workflow\.rb)/ or
@@ -106,7 +108,6 @@ module Rbbt::Config
106
108
 
107
109
  entries = CACHE[key.to_s]
108
110
  priorities = {}
109
- tokens = tokens + ["key:" << key.to_s]
110
111
  tokens.each do |token|
111
112
  token_prio = match entries, token.to_s
112
113
  token_prio.each do |prio, values|
@@ -145,7 +146,6 @@ module Rbbt::Config
145
146
  Rbbt::Config.load_file(Rbbt.etc.config_profile[config].find)
146
147
  else
147
148
  key, value, *tokens = config.split(/\s/)
148
- tokens = ['key:' << key << '::0'] if tokens.empty?
149
149
  tokens = tokens.collect do |tok|
150
150
  tok, _sep, prio = tok.partition("::")
151
151
  prio = "0" if prio.nil? or prio.empty?
data/lib/rbbt/util/log.rb CHANGED
@@ -341,10 +341,31 @@ module Log
341
341
  end unless stack.nil?
342
342
  end
343
343
 
344
- def self.tsv(tsv)
344
+ def self.tsv(tsv, example = false)
345
345
  STDERR.puts Log.color :magenta, "TSV log: " << Log.last_caller(caller).gsub('`',"'")
346
346
  STDERR.puts Log.color(:blue, "=> "<< Misc.fingerprint(tsv), true)
347
347
  STDERR.puts Log.color(:cyan, "=> " << tsv.summary)
348
+ if example && ! tsv.empty?
349
+ key = case example
350
+ when TrueClass, :first, "first"
351
+ tsv.keys.first
352
+ when :random, "random"
353
+ tsv.keys.shuffle.first
354
+ else
355
+ example
356
+ end
357
+
358
+ values = tsv[key]
359
+ values = [values] if tsv.type == :flat || tsv.type == :single
360
+ if values.nil?
361
+ STDERR.puts Log.color(:blue, "Key (#{tsv.key_field}) not present: ") + key
362
+ else
363
+ STDERR.puts Log.color(:blue, "Key (#{tsv.key_field}): ") + key
364
+ tsv.fields.zip(values).each do |field,value|
365
+ STDERR.puts Log.color(:magenta, field + ": ") + (Array === value ? value * ", " : value.to_s)
366
+ end
367
+ end
368
+ end
348
369
  end
349
370
 
350
371
  def self.stack(stack)
@@ -18,11 +18,11 @@ module Log
18
18
  attr_accessor :default_file
19
19
  end
20
20
 
21
- attr_accessor :max, :ticks, :frequency, :depth, :desc, :file, :bytes
21
+ attr_accessor :max, :ticks, :frequency, :depth, :desc, :file, :bytes, :process, :callback
22
22
 
23
23
  def initialize(max = nil, options = {})
24
24
  options = Misc.add_defaults options, :depth => 0, :num_reports => 100, :io => STDERR, :severity => Log.severity, :frequency => 2
25
- depth, num_reports, desc, io, severity, file, bytes, frequency = Misc.process_options options, :depth, :num_reports, :desc, :io, :severity, :file, :bytes, :frequency
25
+ depth, num_reports, desc, io, severity, file, bytes, frequency, process, callback = Misc.process_options options, :depth, :num_reports, :desc, :io, :severity, :file, :bytes, :frequency, :process, :callback
26
26
 
27
27
  @max = max
28
28
  @ticks = 0
@@ -34,6 +34,8 @@ module Log
34
34
  @desc = desc.nil? ? "" : desc.gsub(/\n/,' ')
35
35
  @file = file
36
36
  @bytes = bytes
37
+ @process = process
38
+ @callback = callback
37
39
  end
38
40
 
39
41
  def percent
@@ -80,5 +82,18 @@ module Log
80
82
  step = pos - (@ticks || 0)
81
83
  tick(step)
82
84
  end
85
+
86
+ def process(elem)
87
+ case res = @process.call(elem)
88
+ when FalseClass
89
+ nil
90
+ when TrueClass
91
+ tick
92
+ when Integer
93
+ pos(res)
94
+ when Float
95
+ pos(res * max)
96
+ end
97
+ end
83
98
  end
84
99
  end
@@ -124,6 +124,29 @@ module Log
124
124
  str
125
125
  end
126
126
 
127
+ def load(info)
128
+ info.each do |key, value|
129
+ case key.to_sym
130
+ when :start
131
+ @start = value
132
+ when :last_time
133
+ @last_time = value
134
+ when :last_count
135
+ @last_count = value
136
+ when :last_percent
137
+ @last_percent = value
138
+ when :desc
139
+ @desc = value
140
+ when :ticks
141
+ @ticks = value
142
+ when :max
143
+ @max = value
144
+ when :mean
145
+ @mean = value
146
+ end
147
+ end
148
+ end
149
+
127
150
  def save
128
151
  info = {:start => @start, :last_time => @last_time, :last_count => @last_count, :last_percent => @last_percent, :desc => @desc, :ticks => @ticks, :max => @max, :mean => @mean}
129
152
  info.delete_if{|k,v| v.nil?}
@@ -154,7 +177,7 @@ module Log
154
177
  bars << self unless BARS.include? self
155
178
 
156
179
  print(io, Log.up_lines(bars.length) << Log.color(:magenta, "···Progress\n") << Log.down_lines(bars.length+1)) if Log::ProgressBar.offset == 0
157
- print(io, Log.up_lines(@depth) << report_msg << Log.down_lines(@depth))
180
+ print(io, Log.up_lines(@depth) << report_msg << "\n" << Log.down_lines(@depth - 1))
158
181
  @last_time = Time.now
159
182
  @last_count = ticks
160
183
  @last_percent = percent if max and max > 0
@@ -175,7 +198,10 @@ module Log
175
198
  done_msg << " - " << thr_msg
176
199
  done_msg << Log.color(:magenta, " · " << desc)
177
200
  print(io, Log.up_lines(@depth) << done_msg << Log.down_lines(@depth))
178
- Open.rm file if file and Open.exists? file
201
+
202
+ Open.rm file if file and Open.exists?(file)
203
+
204
+ @callback.call self if @callback
179
205
  end
180
206
 
181
207
  def error(io = STDERR)
@@ -192,7 +218,14 @@ module Log
192
218
  done_msg << " - " << thr_msg
193
219
  done_msg << Log.color(:magenta, " · " << desc)
194
220
  print(io, Log.up_lines(@depth) << done_msg << Log.down_lines(@depth))
195
- Open.rm file if file and Open.exists? file
221
+
222
+ Open.rm file if file and Open.exists?(file)
223
+
224
+ begin
225
+ @callback.call self
226
+ rescue
227
+ Log.debug "Callback failed for filed progress bar: #{$!.message}"
228
+ end if @callback
196
229
  end
197
230
  end
198
231
  end
@@ -428,9 +428,9 @@ def self.add_libdir(dir=nil)
428
428
  end
429
429
  end
430
430
 
431
-
432
- def self.ssh_run(server, script)
431
+ def self.ssh_run(server, script = nil, &block)
433
432
  Log.debug "Run ssh script in #{server}:\n#{script}"
433
+
434
434
  CMD.cmd("ssh '#{server}' 'shopt -s expand_aliases; bash -l -c \"ruby\"' ", :in => script, :log => true).read
435
435
  end
436
436
 
@@ -271,6 +271,22 @@ module Misc
271
271
  end
272
272
 
273
273
 
274
+ def self.step_file?(path)
275
+ return true if defined?(Step) && Step === path.resource
276
+ return false unless path.include?('.files/')
277
+ parts = path.split("/")
278
+ job = parts.select{|p| p =~ /\.files$/}.first
279
+ if job
280
+ i = parts.index job
281
+ begin
282
+ workflow, task = parts.values_at i - 2, i - 1
283
+ return Kernel.const_get(workflow).tasks.include? task.to_sym
284
+ rescue
285
+ end
286
+ end
287
+ false
288
+ end
289
+
274
290
  def self.obj2str(obj)
275
291
  _obj = obj
276
292
  obj = Annotated.purge(obj) if Annotated === obj
@@ -289,7 +305,7 @@ module Misc
289
305
  when (defined?(Path) and Path)
290
306
  if defined?(Step) && Open.exists?(Step.info_file(obj))
291
307
  obj2str(Workflow.load_step(obj))
292
- elsif defined?(Step) && Step === obj.resource
308
+ elsif step_file?(obj)
293
309
  "Step file: " + obj
294
310
  else
295
311
  if obj.exists?
@@ -312,11 +312,23 @@ module Misc
312
312
  end
313
313
  end
314
314
 
315
+ def self.sort_genomic_locations_by_contig(stream, contigs, sep = ":")
316
+ ext_stream = TSV.traverse stream, :type => :array, :into => :stream do |line|
317
+ chr = line.partition(sep).first
318
+ num = contigs.index chr
319
+ num.to_s + sep + line
320
+ end
321
+
322
+ TSV.traverse sort_stream(ext_stream, '#', "-k1,1n -k3,3n -t#{sep}"), :type => :array, :into => :stream do |line|
323
+ line.partition(sep).last
324
+ end
325
+ end
326
+
315
327
  def self.sort_genomic_locations_strict(stream, sep = ":")
316
328
  sort_stream(stream, '#', "-k1,1V -k2,2n -t#{sep}")
317
329
  end
318
330
 
319
- def self.sort_genomic_locations(stream)
331
+ def self.sort_genomic_locations(stream, sep = ":")
320
332
  sort_stream(stream, '#', "-k1,1 -k2,2n -t#{sep}")
321
333
  end
322
334
 
@@ -386,6 +398,7 @@ module Misc
386
398
  cmp
387
399
  end
388
400
  end
401
+
389
402
  def self.intersect_streams_cmp_chr(chr1, chr2)
390
403
  chr1 <=> chr2
391
404
  end
@@ -492,4 +505,50 @@ module Misc
492
505
  end
493
506
  end
494
507
  end
508
+
509
+ def self.genomic_mutations_to_BED(mutations, chr_prefix = false, sort_order = :normal)
510
+ io = if Array === sort_order
511
+
512
+ case chr_prefix.to_s.downcase
513
+ when "remove"
514
+ sort_order = sort_order.collect{|chr| "chr" + chr } unless sort_order.first.include?('chr')
515
+ when "true", "add"
516
+ sort_order = sort_order.collect{|chr| chr.sub('chr', '') } if sort_order.first.include?('chr')
517
+ end
518
+
519
+ sort_genomic_locations_by_contig(mutations, sort_order)
520
+
521
+ else
522
+
523
+ case sort_order.to_s
524
+ when 'strict'
525
+ sort_genomic_locations_strict(mutations)
526
+ else
527
+ sort_genomic_locations(mutations)
528
+ end
529
+
530
+ end
531
+
532
+ TSV.traverse io, :type => :array, :into => :stream do |mutation|
533
+ chr, pos, mut, *rest = mutation.split(":")
534
+ size = case mut
535
+ when nil
536
+ 1
537
+ when /^\+(.*)/
538
+ 1 + $1.length
539
+ when /^\-(.*)/
540
+ $1.length
541
+ else
542
+ mut.length
543
+ end
544
+
545
+ case chr_prefix.to_s.downcase
546
+ when "true", "add"
547
+ chr = "chr" + chr if ! chr.include?('chr')
548
+ when "remove"
549
+ chr = chr.sub("chr", '') if chr.include?('chr')
550
+ end
551
+ [chr, pos.to_i - 1, pos.to_i - 1 + size, mutation] * "\t"
552
+ end
553
+ end
495
554
  end