rbbt-util 5.11.9 → 5.12.0
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 +4 -4
- data/lib/rbbt/persist.rb +1 -1
- data/lib/rbbt/tsv.rb +1 -0
- data/lib/rbbt/tsv/dumper.rb +1 -2
- data/lib/rbbt/tsv/parallel/traverse.rb +2 -2
- data/lib/rbbt/tsv/parser.rb +6 -2
- data/lib/rbbt/tsv/stream.rb +55 -0
- data/lib/rbbt/tsv/util.rb +7 -1
- data/lib/rbbt/util/misc.rb +5 -762
- data/lib/rbbt/util/misc/concurrent_stream.rb +15 -0
- data/lib/rbbt/util/misc/development.rb +122 -0
- data/lib/rbbt/util/misc/inspect.rb +3 -3
- data/lib/rbbt/util/misc/manipulation.rb +136 -0
- data/lib/rbbt/util/misc/math.rb +50 -0
- data/lib/rbbt/util/misc/objects.rb +79 -0
- data/lib/rbbt/util/misc/omics.rb +10 -0
- data/lib/rbbt/util/misc/options.rb +280 -0
- data/lib/rbbt/util/misc/pipes.rb +140 -20
- data/lib/rbbt/util/misc/system.rb +90 -0
- data/lib/rbbt/util/tar.rb +0 -7
- data/lib/rbbt/workflow/accessor.rb +3 -3
- data/lib/rbbt/workflow/step/run.rb +69 -15
- data/lib/rbbt/workflow/task.rb +7 -5
- data/test/rbbt/tsv/test_stream.rb +92 -0
- data/test/rbbt/tsv/test_util.rb +1 -3
- data/test/rbbt/util/misc/test_pipes.rb +79 -0
- data/test/rbbt/workflow/test_task.rb +1 -0
- metadata +10 -2
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'net/smtp'
|
2
|
+
|
3
|
+
module Misc
|
4
|
+
|
5
|
+
def self.hostname
|
6
|
+
@hostanem ||= `hostname`.strip
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.pid_exists?(pid)
|
10
|
+
return false if pid.nil?
|
11
|
+
begin
|
12
|
+
Process.getpgid(pid.to_i)
|
13
|
+
true
|
14
|
+
rescue Errno::ESRCH
|
15
|
+
false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.send_email(from, to, subject, message, options = {})
|
20
|
+
IndiferentHash.setup(options)
|
21
|
+
options = Misc.add_defaults options, :from_alias => nil, :to_alias => nil, :server => 'localhost', :port => 25, :user => nil, :pass => nil, :auth => :login
|
22
|
+
|
23
|
+
server, port, user, pass, from_alias, to_alias, auth = Misc.process_options options, :server, :port, :user, :pass, :from_alias, :to_alias, :auth
|
24
|
+
|
25
|
+
msg = <<-END_OF_MESSAGE
|
26
|
+
From: #{from_alias} <#{from}>
|
27
|
+
To: #{to_alias} <#{to}>
|
28
|
+
Subject: #{subject}
|
29
|
+
|
30
|
+
#{message}
|
31
|
+
END_OF_MESSAGE
|
32
|
+
|
33
|
+
Net::SMTP.start(server, port, server, user, pass, auth) do |smtp|
|
34
|
+
smtp.send_message msg, from, to
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.env_add(var, value, sep = ":", prepend = true)
|
39
|
+
ENV[var] ||= ""
|
40
|
+
return if ENV[var] =~ /(#{sep}|^)#{Regexp.quote value}(#{sep}|$)/
|
41
|
+
if prepend
|
42
|
+
ENV[var] = value + sep + ENV[var]
|
43
|
+
else
|
44
|
+
ENV[var] += sep + ENV[var]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.path_relative_to(basedir, path)
|
49
|
+
path = File.expand_path(path) unless path[0] == "/"
|
50
|
+
basedir = File.expand_path(basedir) unless basedir[0] == "/"
|
51
|
+
|
52
|
+
if path.index(basedir) == 0
|
53
|
+
if basedir[-1] == "/"
|
54
|
+
return path[basedir.length..-1]
|
55
|
+
else
|
56
|
+
return path[basedir.length+1..-1]
|
57
|
+
end
|
58
|
+
else
|
59
|
+
return nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.common_path(dir, file)
|
64
|
+
file = File.expand_path file
|
65
|
+
dir = File.expand_path dir
|
66
|
+
|
67
|
+
return true if file == dir
|
68
|
+
while File.dirname(file) != file
|
69
|
+
file = File.dirname(file)
|
70
|
+
return true if file == dir
|
71
|
+
end
|
72
|
+
|
73
|
+
return false
|
74
|
+
end
|
75
|
+
|
76
|
+
# WARN: probably not thread safe...
|
77
|
+
def self.in_dir(dir)
|
78
|
+
old_pwd = FileUtils.pwd
|
79
|
+
res = nil
|
80
|
+
begin
|
81
|
+
FileUtils.mkdir_p dir unless File.exists? dir
|
82
|
+
FileUtils.cd dir
|
83
|
+
res = yield
|
84
|
+
ensure
|
85
|
+
FileUtils.cd old_pwd
|
86
|
+
end
|
87
|
+
res
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
data/lib/rbbt/util/tar.rb
CHANGED
@@ -43,13 +43,6 @@ module Misc
|
|
43
43
|
|
44
44
|
string = tar.string
|
45
45
|
|
46
|
-
#chunk_size = 1024
|
47
|
-
#Zlib::GzipWriter.wrap(gz) do |writer|
|
48
|
-
# while chunk = tar.read(chunk_size) do
|
49
|
-
# writer.write chunk
|
50
|
-
# end
|
51
|
-
# writer.close
|
52
|
-
#end
|
53
46
|
z = Zlib::GzipWriter.new(gz)
|
54
47
|
z.write string
|
55
48
|
z.close
|
@@ -49,9 +49,9 @@ class Step
|
|
49
49
|
end
|
50
50
|
|
51
51
|
begin
|
52
|
-
@info_cache = Misc.insist(2,
|
53
|
-
Misc.insist(2,
|
54
|
-
Misc.insist(3, 0.
|
52
|
+
@info_cache = Misc.insist(2, 3, info_file) do
|
53
|
+
Misc.insist(2, 1, info_file) do
|
54
|
+
Misc.insist(3, 0.2, info_file) do
|
55
55
|
Open.open(info_file) do |file|
|
56
56
|
INFO_SERIALIAZER.load(file) || {}
|
57
57
|
end
|
@@ -2,6 +2,47 @@ class Step
|
|
2
2
|
|
3
3
|
attr_reader :stream
|
4
4
|
|
5
|
+
STREAM_CACHE = {}
|
6
|
+
STREAM_CACHE_MUTEX = Mutex.new
|
7
|
+
def self.dup_stream(stream)
|
8
|
+
case stream
|
9
|
+
when IO, File
|
10
|
+
return stream if stream.closed?
|
11
|
+
STREAM_CACHE_MUTEX.synchronize do
|
12
|
+
if STREAM_CACHE[stream].nil?
|
13
|
+
STREAM_CACHE[stream] = stream
|
14
|
+
else
|
15
|
+
Misc.dup_stream(STREAM_CACHE[stream])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
when TSV::Dumper, TSV::Parser
|
19
|
+
stream = stream.stream
|
20
|
+
return stream if stream.closed?
|
21
|
+
|
22
|
+
STREAM_CACHE_MUTEX.synchronize do
|
23
|
+
if STREAM_CACHE[stream].nil?
|
24
|
+
STREAM_CACHE[stream] = stream
|
25
|
+
else
|
26
|
+
Misc.dup_stream(STREAM_CACHE[stream])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
else
|
30
|
+
stream
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.purge_stream_cache
|
35
|
+
return
|
36
|
+
STREAM_CACHE_MUTEX.synchronize do
|
37
|
+
STREAM_CACHE.collect{|k,s|
|
38
|
+
Thread.new do
|
39
|
+
Misc.consume_stream s
|
40
|
+
end
|
41
|
+
}
|
42
|
+
STREAM_CACHE.clear
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
5
46
|
def get_stream
|
6
47
|
@mutex.synchronize do
|
7
48
|
@stream = begin
|
@@ -12,9 +53,16 @@ class Step
|
|
12
53
|
end
|
13
54
|
end
|
14
55
|
|
56
|
+
def dup_inputs
|
57
|
+
@inputs.collect do |input|
|
58
|
+
Step.dup_stream input
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
15
62
|
def _exec
|
16
63
|
@exec = true if @exec.nil?
|
17
|
-
|
64
|
+
#@task.exec_in((bindings ? bindings : self), *@inputs)
|
65
|
+
@task.exec_in((bindings ? bindings : self), *dup_inputs)
|
18
66
|
end
|
19
67
|
|
20
68
|
def exec(no_load=false)
|
@@ -299,26 +347,32 @@ class Step
|
|
299
347
|
|
300
348
|
join_stream
|
301
349
|
|
302
|
-
return if not Open.exists? info_file
|
350
|
+
return self if not Open.exists? info_file
|
351
|
+
|
352
|
+
return self if info[:joined]
|
303
353
|
pid = @pid
|
304
354
|
|
305
355
|
Misc.insist [0.1, 0.2, 0.5, 1] do
|
306
356
|
pid ||= info[:pid]
|
307
357
|
end
|
308
358
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
359
|
+
begin
|
360
|
+
if pid.nil?
|
361
|
+
dependencies.each{|dep| dep.join }
|
362
|
+
self
|
363
|
+
else
|
364
|
+
begin
|
365
|
+
Log.debug{"Waiting for pid: #{pid}"}
|
366
|
+
Process.waitpid pid
|
367
|
+
rescue Errno::ECHILD
|
368
|
+
Log.debug{"Process #{ pid } already finished: #{ path }"}
|
369
|
+
end if Misc.pid_exists? pid
|
370
|
+
pid = nil
|
371
|
+
dependencies.each{|dep| dep.join }
|
372
|
+
self
|
373
|
+
end
|
374
|
+
ensure
|
375
|
+
set_info :joined, true
|
322
376
|
end
|
323
377
|
self
|
324
378
|
end
|
data/lib/rbbt/workflow/task.rb
CHANGED
@@ -29,15 +29,13 @@ module Task
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
def param_options
|
33
|
-
end
|
34
|
-
|
35
32
|
def take_input_values(input_values)
|
36
33
|
return [] if @inputs.nil?
|
37
34
|
values = []
|
35
|
+
defaults = IndiferentHash.setup(@input_defaults || {})
|
38
36
|
@inputs.each do |input|
|
39
37
|
value = input_values[input]
|
40
|
-
value =
|
38
|
+
value = defaults[input] if value.nil?
|
41
39
|
values << value
|
42
40
|
end
|
43
41
|
values
|
@@ -46,7 +44,11 @@ module Task
|
|
46
44
|
def exec(*args)
|
47
45
|
case
|
48
46
|
when (args.length == 1 and not inputs.nil? and inputs.length > 1 and Hash === args.first)
|
49
|
-
|
47
|
+
begin
|
48
|
+
self.call *take_input_values(IndiferentHash.setup(args.first))
|
49
|
+
ensure
|
50
|
+
purge_stream_cache
|
51
|
+
end
|
50
52
|
else
|
51
53
|
self.call *args
|
52
54
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), '../..', 'test_helper.rb')
|
2
|
+
require 'rbbt/tsv'
|
3
|
+
require 'rbbt/tsv/stream'
|
4
|
+
require 'rbbt'
|
5
|
+
|
6
|
+
class TestStream < Test::Unit::TestCase
|
7
|
+
def test_collapse_stream
|
8
|
+
text=<<-EOF
|
9
|
+
#: :sep=" "
|
10
|
+
#Row LabelA LabelB LabelC
|
11
|
+
row1 A B C
|
12
|
+
row1 a b c
|
13
|
+
row2 AA BB CC
|
14
|
+
row2 aa bb cc
|
15
|
+
EOF
|
16
|
+
|
17
|
+
s = StringIO.new text
|
18
|
+
tsv = TSV.open TSV.collapse_stream(s)
|
19
|
+
assert_equal ["A", "a"], tsv["row1"][0]
|
20
|
+
assert_equal ["BB", "bb"], tsv["row2"][1]
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_paste_stream
|
24
|
+
text1=<<-EOF
|
25
|
+
#: :sep=" "
|
26
|
+
#Row LabelA LabelB LabelC
|
27
|
+
row1 A B C
|
28
|
+
row2 AA BB CC
|
29
|
+
row3 AAA BBB CCC
|
30
|
+
EOF
|
31
|
+
|
32
|
+
text2=<<-EOF
|
33
|
+
#: :sep=" "
|
34
|
+
#Row Labela Labelb
|
35
|
+
row1 a b
|
36
|
+
row2 aa bb
|
37
|
+
row3 aaa bbb
|
38
|
+
EOF
|
39
|
+
|
40
|
+
text3=<<-EOF
|
41
|
+
#: :sep=" "
|
42
|
+
#Row LabelC
|
43
|
+
row1 c
|
44
|
+
row2 cc
|
45
|
+
row3 ccc
|
46
|
+
EOF
|
47
|
+
|
48
|
+
s1 = StringIO.new text1
|
49
|
+
s2 = StringIO.new text2
|
50
|
+
s3 = StringIO.new text3
|
51
|
+
tsv = TSV.open TSV.paste_streams([s1,s2,s3], :sep => " ", :type => :list)
|
52
|
+
assert_equal ["A", "B", "C", "a", "b", "c"], tsv["row1"]
|
53
|
+
assert_equal ["AA", "BB", "CC", "aa", "bb", "cc"], tsv["row2"]
|
54
|
+
assert_equal ["AAA", "BBB", "CCC", "aaa", "bbb", "ccc"], tsv["row3"]
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_paste_stream_sort
|
58
|
+
text1=<<-EOF
|
59
|
+
#: :sep=" "
|
60
|
+
#Row LabelA LabelB LabelC
|
61
|
+
row2 AA BB CC
|
62
|
+
row1 A B C
|
63
|
+
row3 AAA BBB CCC
|
64
|
+
EOF
|
65
|
+
|
66
|
+
text2=<<-EOF
|
67
|
+
#: :sep=" "
|
68
|
+
#Row Labela Labelb
|
69
|
+
row1 a b
|
70
|
+
row3 aaa bbb
|
71
|
+
row2 aa bb
|
72
|
+
EOF
|
73
|
+
|
74
|
+
text3=<<-EOF
|
75
|
+
#: :sep=" "
|
76
|
+
#Row Labelc
|
77
|
+
row3 ccc
|
78
|
+
row1 c
|
79
|
+
row2 cc
|
80
|
+
EOF
|
81
|
+
|
82
|
+
s1 = StringIO.new text1
|
83
|
+
s2 = StringIO.new text2
|
84
|
+
s3 = StringIO.new text3
|
85
|
+
tsv = TSV.open TSV.paste_streams([s1,s2,s3], :sep => " ", :type => :list, :sort => true)
|
86
|
+
assert_equal "Row", tsv.key_field
|
87
|
+
assert_equal %w(LabelA LabelB LabelC Labela Labelb Labelc), tsv.fields
|
88
|
+
assert_equal ["A", "B", "C", "a", "b", "c"], tsv["row1"]
|
89
|
+
assert_equal ["AA", "BB", "CC", "aa", "bb", "cc"], tsv["row2"]
|
90
|
+
assert_equal ["AAA", "BBB", "CCC", "aaa", "bbb", "ccc"], tsv["row3"]
|
91
|
+
end
|
92
|
+
end
|
data/test/rbbt/tsv/test_util.rb
CHANGED
@@ -18,12 +18,10 @@ row2 A B Id3
|
|
18
18
|
|
19
19
|
assert_equal 2, TSV.field_match_counts(tsv, ["a","A","a","b","Id3"])["ValueA"]
|
20
20
|
assert_equal nil, TSV.field_match_counts(tsv, ["ValueA"])["ValueA"]
|
21
|
-
|
22
21
|
end
|
23
|
-
|
24
22
|
end
|
25
23
|
|
26
|
-
def
|
24
|
+
def _test_marshal
|
27
25
|
content =<<-EOF
|
28
26
|
#Id ValueA ValueB OtherID
|
29
27
|
row1 a|aa|aaa b Id1|Id2
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../../test_helper')
|
2
|
+
require 'test/unit'
|
3
|
+
require 'rbbt/tsv'
|
4
|
+
require 'rbbt/util/misc'
|
5
|
+
|
6
|
+
class TestMiscPipes < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def test_collapse_stream
|
9
|
+
text=<<-EOF
|
10
|
+
row1 A B C
|
11
|
+
row1 a b c
|
12
|
+
row2 AA BB CC
|
13
|
+
row2 aa bb cc
|
14
|
+
EOF
|
15
|
+
|
16
|
+
s = StringIO.new text
|
17
|
+
tsv = TSV.open Misc.collapse_stream(s,nil, " "), :sep => " "
|
18
|
+
assert_equal ["A", "a"], tsv["row1"][0]
|
19
|
+
assert_equal ["BB", "bb"], tsv["row2"][1]
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_paste_stream
|
23
|
+
text1=<<-EOF
|
24
|
+
row1 A B C
|
25
|
+
row2 AA BB CC
|
26
|
+
row3 AAA BBB CCC
|
27
|
+
EOF
|
28
|
+
|
29
|
+
text2=<<-EOF
|
30
|
+
row1 a b
|
31
|
+
row2 aa bb
|
32
|
+
EOF
|
33
|
+
|
34
|
+
text3=<<-EOF
|
35
|
+
row1 c
|
36
|
+
row2 cc
|
37
|
+
row3 ccc
|
38
|
+
EOF
|
39
|
+
|
40
|
+
s1 = StringIO.new text1
|
41
|
+
s2 = StringIO.new text2
|
42
|
+
s3 = StringIO.new text3
|
43
|
+
tsv = TSV.open Misc.paste_streams([s1,s2,s3],nil, " "), :sep => " ", :type => :list
|
44
|
+
assert_equal ["A", "B", "C", "a", "b", "c"], tsv["row1"]
|
45
|
+
assert_equal ["AA", "BB", "CC", "aa", "bb", "cc"], tsv["row2"]
|
46
|
+
assert_equal ["AAA", "BBB", "CCC", "", "", "ccc"], tsv["row3"]
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_sort_stream
|
50
|
+
text =<<-EOF
|
51
|
+
#: :sep=" "
|
52
|
+
#Row LabelA LabelB LabelC
|
53
|
+
row2 AA BB CC
|
54
|
+
row3 AAA BBB CCC
|
55
|
+
row1 A B C
|
56
|
+
EOF
|
57
|
+
s = StringIO.new text
|
58
|
+
sorted = Misc.sort_stream(s)
|
59
|
+
assert_equal %w(#: #Row row2 row3 row1), text.split("\n").collect{|l| l.split(" ").first}
|
60
|
+
assert_equal %w(#: #Row row1 row2 row3), sorted.read.split("\n").collect{|l| l.split(" ").first}
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_dup_stream
|
64
|
+
text =<<-EOF
|
65
|
+
#: :sep=" "
|
66
|
+
#Row LabelA LabelB LabelC
|
67
|
+
row2 AA BB CC
|
68
|
+
row3 AAA BBB CCC
|
69
|
+
row1 A B C
|
70
|
+
EOF
|
71
|
+
|
72
|
+
TmpFile.with_file(text) do |tmp|
|
73
|
+
io = Open.open(tmp)
|
74
|
+
dup = Misc.dup_stream(io)
|
75
|
+
assert_equal text, dup.read
|
76
|
+
assert_equal text, io.read
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|