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.
- checksums.yaml +4 -4
- data/lib/rbbt/hpc.rb +3 -0
- data/lib/rbbt/hpc/batch.rb +623 -0
- data/lib/rbbt/hpc/lsf.rb +119 -0
- data/lib/rbbt/hpc/orchestrate.rb +24 -19
- data/lib/rbbt/hpc/slurm.rb +62 -559
- data/lib/rbbt/resource/path.rb +3 -1
- data/lib/rbbt/tsv/accessor.rb +5 -2
- data/lib/rbbt/tsv/dumper.rb +1 -0
- data/lib/rbbt/tsv/parallel/traverse.rb +1 -1
- data/lib/rbbt/tsv/stream.rb +5 -6
- data/lib/rbbt/util/cmd.rb +15 -1
- data/lib/rbbt/util/config.rb +2 -2
- data/lib/rbbt/util/log.rb +22 -1
- data/lib/rbbt/util/log/progress.rb +17 -2
- data/lib/rbbt/util/log/progress/report.rb +36 -3
- data/lib/rbbt/util/misc/development.rb +2 -2
- data/lib/rbbt/util/misc/inspect.rb +17 -1
- data/lib/rbbt/util/misc/omics.rb +60 -1
- data/lib/rbbt/util/misc/options.rb +5 -0
- data/lib/rbbt/workflow/accessor.rb +7 -2
- data/lib/rbbt/workflow/definition.rb +7 -3
- data/lib/rbbt/workflow/step/accessor.rb +1 -1
- data/lib/rbbt/workflow/step/run.rb +9 -0
- data/lib/rbbt/workflow/usage.rb +13 -13
- data/lib/rbbt/workflow/util/archive.rb +5 -3
- data/lib/rbbt/workflow/util/provenance.rb +26 -21
- data/share/config.ru +3 -3
- data/share/rbbt_commands/{slurm → hpc}/clean +91 -18
- data/share/rbbt_commands/{slurm → hpc}/list +119 -31
- data/share/rbbt_commands/hpc/orchestrate +81 -0
- data/share/rbbt_commands/hpc/tail +81 -0
- data/share/rbbt_commands/hpc/task +80 -0
- data/test/rbbt/hpc/test_batch.rb +65 -0
- data/test/rbbt/hpc/test_slurm.rb +30 -0
- data/test/rbbt/util/misc/test_development.rb +11 -0
- data/test/rbbt/util/test_config.rb +13 -3
- data/test/test_helper.rb +3 -1
- metadata +16 -7
- data/share/rbbt_commands/slurm/orchestrate +0 -48
- data/share/rbbt_commands/slurm/task +0 -46
data/lib/rbbt/resource/path.rb
CHANGED
@@ -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
|
data/lib/rbbt/tsv/accessor.rb
CHANGED
@@ -713,8 +713,11 @@ module TSV
|
|
713
713
|
break
|
714
714
|
end
|
715
715
|
|
716
|
-
filename =
|
717
|
-
filename
|
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}
|
data/lib/rbbt/tsv/dumper.rb
CHANGED
@@ -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?
|
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
|
data/lib/rbbt/tsv/stream.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/rbbt/util/config.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
308
|
+
elsif step_file?(obj)
|
293
309
|
"Step file: " + obj
|
294
310
|
else
|
295
311
|
if obj.exists?
|
data/lib/rbbt/util/misc/omics.rb
CHANGED
@@ -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
|