rbbt-util 5.2.3 → 5.2.4
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 +15 -0
- data/bin/rbbt +27 -1
- data/bin/rbbt_monitor.rb +6 -2
- data/lib/rbbt/persist.rb +4 -4
- data/lib/rbbt/persist/tsv.rb +1 -1
- data/lib/rbbt/tsv/attach.rb +8 -2
- data/lib/rbbt/tsv/attach/util.rb +1 -1
- data/lib/rbbt/util/log.rb +1 -1
- data/lib/rbbt/util/misc.rb +32 -0
- data/lib/rbbt/util/simpleopt.rb +168 -7
- data/lib/rbbt/workflow.rb +7 -6
- data/lib/rbbt/workflow/step.rb +15 -8
- data/lib/rbbt/workflow/usage.rb +4 -36
- data/share/rbbt_commands/app/start +2 -1
- data/share/rbbt_commands/workflow/task +36 -17
- data/test/rbbt/test_tsv.rb +16 -0
- data/test/rbbt/util/test_misc.rb +4 -0
- metadata +5 -27
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZjIwN2RhYmRjNDg2MjMzMWNmYWU4NGQ5ZDUyYjcyNGU4MmExMzJhYw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NzAyMmUyMjg3ZWRmY2I1N2EwNDk1OGVlNTBmNWUyNmIyNTUxN2QwNg==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
M2M0OTlkODVmMjY1ZWNjZWIzYjhjMTE2M2MyOGNiNWY5YjZiYjNiNDdkMTQx
|
10
|
+
MjkyNTk0MWRkZGM4ZjU3OTVjOTQ3ODg3YmNhNjVmZjljZDlmZGU3YTI4YWIw
|
11
|
+
MmFkZjcwMTE5OGFlNmI3MjRkZWI0NTQwZDBlZTg3ZTUwMWJhYjY=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZTIxNTBhZGQyZjg0ZjNiYjhlZjU3MTQ4M2YzMzgyNWNlZWE4MWMxNDg2OWUw
|
14
|
+
MzRlMzQyMzkyZWJiNDM1NjQ3ODljNmUwYjg1ZjJhYzYxOWE3MTZjZjc1ZDM3
|
15
|
+
OTI1ZjMzMTNmZDE4Mzc4OTQ3NDJmY2UyYTQzNWRjZDg0MjhlOWI=
|
data/bin/rbbt
CHANGED
@@ -1,8 +1,30 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'rbbt'
|
4
|
+
require 'rbbt/util/simpleopt'
|
4
5
|
|
5
|
-
|
6
|
+
options = SOPT.get("--log* Log level from 0 (debug) 7 (errors):--command_dir* Directory from where to load commands")
|
7
|
+
|
8
|
+
if options[:log]
|
9
|
+
Log.severity = options[:log].to_i
|
10
|
+
end
|
11
|
+
|
12
|
+
if options[:command_dir]
|
13
|
+
$rbbt_command_dir = Path.setup(options[:command_dir])
|
14
|
+
else
|
15
|
+
$rbbt_command_dir = Rbbt.share.rbbt_commands
|
16
|
+
end
|
17
|
+
|
18
|
+
SOPT.synopsys = "rbbt <command> <subcommand> ... -a --arg1 --arg2='value'"
|
19
|
+
SOPT.summary = "Ruby bioinformatics toolkit"
|
20
|
+
SOPT.description = <<-EOF
|
21
|
+
This command controls many aspects of the Rbbt framework, from configuration tasks to running applications.
|
22
|
+
|
23
|
+
Commands are implemented in separate files under the Rbbt path#{
|
24
|
+
} '#{$rbbt_command_dir}'. Known locations are: #{
|
25
|
+
([$rbbt_command_dir] + $rbbt_command_dir.find_all) * ", "
|
26
|
+
}. You can place your own commads at #{$rbbt_command_dir.find(:user)}.
|
27
|
+
EOF
|
6
28
|
|
7
29
|
def commands(prev)
|
8
30
|
rbbt_command_dir = $rbbt_command_dir
|
@@ -35,6 +57,10 @@ while ARGV.any?
|
|
35
57
|
end
|
36
58
|
end
|
37
59
|
|
60
|
+
puts SOPT.doc
|
61
|
+
|
62
|
+
puts "## COMMANDS"
|
63
|
+
puts
|
38
64
|
puts "Command:"
|
39
65
|
puts
|
40
66
|
puts " #{File.basename($0)} #{prev * " "}"
|
data/bin/rbbt_monitor.rb
CHANGED
@@ -50,6 +50,8 @@ def list_jobs(options)
|
|
50
50
|
end
|
51
51
|
|
52
52
|
color = case
|
53
|
+
when (not info)
|
54
|
+
Log::SEVERITY_COLOR[3]
|
53
55
|
when info[:status] == :error
|
54
56
|
Log::SEVERITY_COLOR[3]
|
55
57
|
when (info[:pid] and not running? info)
|
@@ -57,6 +59,8 @@ def list_jobs(options)
|
|
57
59
|
end
|
58
60
|
|
59
61
|
case
|
62
|
+
when (not info)
|
63
|
+
print_job file, info, color
|
60
64
|
when (not omit_ok)
|
61
65
|
print_job file, info, color
|
62
66
|
when options[:zombies]
|
@@ -89,9 +93,9 @@ def clean_jobs(options)
|
|
89
93
|
case
|
90
94
|
when options[:all]
|
91
95
|
remove_job file
|
92
|
-
when (options[:
|
96
|
+
when (options[:errors] and (not info or info[:status] == :error))
|
93
97
|
remove_job file
|
94
|
-
when (options[:
|
98
|
+
when (options[:zombies] and info[:pid] and not running? info)
|
95
99
|
remove_job file
|
96
100
|
end
|
97
101
|
|
data/lib/rbbt/persist.rb
CHANGED
@@ -249,11 +249,11 @@ module Persist
|
|
249
249
|
|
250
250
|
else
|
251
251
|
if is_persisted?(path, persist_options)
|
252
|
-
Log.
|
252
|
+
Log.low "Persist up-to-date: #{ path } - #{persist_options.inspect[0..100]}"
|
253
253
|
return nil if persist_options[:no_load]
|
254
254
|
return load_file(path, type)
|
255
255
|
else
|
256
|
-
Log.
|
256
|
+
Log.medium "Persist create: #{ path } - #{persist_options.inspect[0..100]}"
|
257
257
|
end
|
258
258
|
begin
|
259
259
|
res = yield
|
@@ -262,8 +262,8 @@ module Persist
|
|
262
262
|
end
|
263
263
|
res
|
264
264
|
rescue
|
265
|
-
Log.high "Error in persist. Erasing '#{ path }'"
|
266
|
-
FileUtils.rm path if File.exists? path
|
265
|
+
Log.high "Error in persist. #{File.exists?(path) ? "Erasing '#{ path }'" : ""}"
|
266
|
+
FileUtils.rm path if File.exists? path
|
267
267
|
raise $!
|
268
268
|
end
|
269
269
|
end
|
data/lib/rbbt/persist/tsv.rb
CHANGED
@@ -158,7 +158,7 @@ module Persist
|
|
158
158
|
lock_filename = Persist.persistence_path(path, {:dir => Rbbt.tmp.tsv_open_locks.find})
|
159
159
|
return Misc.lock(lock_filename) do open_tokyocabinet(path, false); end
|
160
160
|
else
|
161
|
-
Log.
|
161
|
+
Log.medium "TSV persistence creating: #{ path }"
|
162
162
|
end
|
163
163
|
|
164
164
|
FileUtils.rm path if File.exists? path
|
data/lib/rbbt/tsv/attach.rb
CHANGED
@@ -48,13 +48,16 @@ module TSV
|
|
48
48
|
end
|
49
49
|
|
50
50
|
# Merge two files with the same keys and different fields
|
51
|
-
def self.merge_different_fields(file1, file2, output, sep = "\t")
|
51
|
+
def self.merge_different_fields(file1, file2, output, sep = "\t", monitor = false)
|
52
52
|
case
|
53
53
|
when (String === file1 and not file1 =~ /\n/ and file1.length < 250 and File.exists?(file1))
|
54
|
+
size = CMD.cmd("wc -l '#{file1}'").read.to_f if monitor
|
54
55
|
file1 = CMD.cmd("sort -k1,1 -t'#{sep}' #{ file1 } | grep -v '^#{sep}' ", :pipe => true)
|
55
56
|
when (String === file1 or StringIO === file1)
|
57
|
+
size = file1.length if monitor
|
56
58
|
file1 = CMD.cmd("sort -k1,1 -t'#{sep}' | grep -v '^#{sep}'", :in => file1, :pipe => true)
|
57
59
|
when TSV === file1
|
60
|
+
size = file1.size if monitor
|
58
61
|
file1 = CMD.cmd("sort -k1,1 -t'#{sep}' | grep -v '^#{sep}'", :in => file1.to_s(:sort, true), :pipe => true)
|
59
62
|
end
|
60
63
|
|
@@ -88,6 +91,8 @@ module TSV
|
|
88
91
|
cols2 = parts2.length
|
89
92
|
end
|
90
93
|
|
94
|
+
progress_monitor = Progress::Bar.new(size, 0, 100, "Merging fields") if monitor
|
95
|
+
|
91
96
|
key = key1 < key2 ? key1 : key2
|
92
97
|
parts = [""] * (cols1 + cols2)
|
93
98
|
while not (done1 and done2)
|
@@ -99,6 +104,7 @@ module TSV
|
|
99
104
|
while key1.nil? and not done1
|
100
105
|
if file1.eof?; done1 = true; else key1, *parts1 = file1.gets.sub("\n",'').split(sep, -1) end
|
101
106
|
end
|
107
|
+
progress_monitor.tick if monitor
|
102
108
|
end
|
103
109
|
while (not done2 and key2 == key)
|
104
110
|
parts2.each_with_index do |part, i|
|
@@ -151,7 +157,7 @@ module TSV
|
|
151
157
|
end
|
152
158
|
|
153
159
|
other_filename = other.respond_to?(:filename) ? other.filename : other.inspect
|
154
|
-
Log.
|
160
|
+
Log.low("Attaching fields:#{fields.inspect} from #{other_filename}.")
|
155
161
|
|
156
162
|
case
|
157
163
|
when key_field == other.key_field
|
data/lib/rbbt/tsv/attach/util.rb
CHANGED
@@ -229,7 +229,7 @@ module TSV
|
|
229
229
|
|
230
230
|
traversal_ids = path.collect{|p| p.first}
|
231
231
|
|
232
|
-
Log.
|
232
|
+
Log.debug "Found Traversal: #{traversal_ids * " => "}"
|
233
233
|
|
234
234
|
data_key, data_file = path.shift
|
235
235
|
data_index = if data_key == data_file.key_field
|
data/lib/rbbt/util/log.rb
CHANGED
@@ -25,7 +25,7 @@ module Log
|
|
25
25
|
# @severity
|
26
26
|
#end
|
27
27
|
|
28
|
-
SEVERITY_COLOR = ["0;37m", "0;32m", "0;33m", "0;31m", "
|
28
|
+
SEVERITY_COLOR = ["0;37m", "0;32m", "0;33m", "0;31m","0;37m", "0;32m", "0;33m"].collect{|e| "\033[#{e}"}
|
29
29
|
|
30
30
|
def self.log(message, severity = MEDIUM)
|
31
31
|
message ||= ""
|
data/lib/rbbt/util/misc.rb
CHANGED
@@ -19,6 +19,38 @@ end
|
|
19
19
|
module Misc
|
20
20
|
class FieldNotFoundError < StandardError;end
|
21
21
|
|
22
|
+
def self.correct_icgc_mutation(pos, ref, mut_str)
|
23
|
+
mut = mut_str
|
24
|
+
mut = '-' * (mut_str.length - 1) if mut =~/^-[ACGT]/
|
25
|
+
[pos, [mut]]
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.correct_vcf_mutation(pos, ref, mut_str)
|
29
|
+
muts = mut_str.nil? ? [] : mut_str.split(',')
|
30
|
+
|
31
|
+
while ref.length >= 1 and muts.reject{|m| m[0] == ref[0]}.empty?
|
32
|
+
ref = ref[1..-1]
|
33
|
+
pos = pos + 1
|
34
|
+
muts = muts.collect{|m| m[1..-1]}
|
35
|
+
end
|
36
|
+
|
37
|
+
muts = muts.collect do |m|
|
38
|
+
case
|
39
|
+
when ref.empty?
|
40
|
+
"+" << m
|
41
|
+
when (m.length < ref.length and (m.empty? or ref.index(m)))
|
42
|
+
"-" * (ref.length - m.length)
|
43
|
+
when (ref.length == 1 and m.length == 1)
|
44
|
+
m
|
45
|
+
else
|
46
|
+
Log.debug "Cannot understand: #{[ref, m]} (#{ muts })"
|
47
|
+
'-' * ref.length + m
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
[pos, muts]
|
52
|
+
end
|
53
|
+
|
22
54
|
def self.pid_exists?(pid)
|
23
55
|
return false if pid.nil?
|
24
56
|
begin
|
data/lib/rbbt/util/simpleopt.rb
CHANGED
@@ -1,17 +1,178 @@
|
|
1
1
|
module SOPT
|
2
|
+
class << self
|
3
|
+
attr_accessor :command, :summary, :synopsys, :description
|
4
|
+
attr_accessor :inputs, :input_shortcuts, :input_types, :input_descriptions, :input_defaults
|
5
|
+
|
6
|
+
def command
|
7
|
+
@command ||= File.basename($0)
|
8
|
+
end
|
9
|
+
|
10
|
+
def summary
|
11
|
+
@summary ||= ""
|
12
|
+
end
|
13
|
+
|
14
|
+
def synopsys
|
15
|
+
@synopsys ||= begin
|
16
|
+
"#{command} " <<
|
17
|
+
inputs.collect{|name|
|
18
|
+
"[" << input_format(name, input_types[name] || :string, input_defaults[name], input_shortcuts[name]).sub(/:$/,'') << "]"
|
19
|
+
} * " "
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def description
|
24
|
+
@description ||= "Missing"
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def shortcuts
|
29
|
+
@shortcuts ||= []
|
30
|
+
end
|
31
|
+
|
32
|
+
def all
|
33
|
+
@all ||= {}
|
34
|
+
end
|
35
|
+
|
36
|
+
def inputs
|
37
|
+
@inputs ||= []
|
38
|
+
end
|
39
|
+
|
40
|
+
def input_shortcuts
|
41
|
+
@input_shortcuts ||= {}
|
42
|
+
end
|
43
|
+
|
44
|
+
def input_types
|
45
|
+
@input_types ||= {}
|
46
|
+
end
|
47
|
+
|
48
|
+
def input_descriptions
|
49
|
+
@input_descriptions ||= {}
|
50
|
+
end
|
51
|
+
|
52
|
+
def input_defaults
|
53
|
+
@input_defaults ||= {}
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def reset
|
58
|
+
@shortcuts = []
|
59
|
+
@all = {}
|
60
|
+
end
|
61
|
+
|
62
|
+
def record(info)
|
63
|
+
input = info[:long].sub("--", '')
|
64
|
+
inputs << input
|
65
|
+
input_types[input] = info[:arg] ? :string : :boolean
|
66
|
+
input_descriptions[input] = info[:description]
|
67
|
+
input_defaults[input] = info[:default]
|
68
|
+
input_shortcuts[input] = info[:short]? info[:short].sub("-",'') : nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
def self.short_for(name)
|
74
|
+
short = []
|
75
|
+
chars = name.to_s.chars.to_a
|
76
|
+
|
77
|
+
short << chars.shift
|
78
|
+
shortcuts = input_shortcuts.values.compact.flatten
|
79
|
+
while shortcuts.include? short * "" and chars.any?
|
80
|
+
short << chars.shift
|
81
|
+
end
|
82
|
+
return nil if chars.empty?
|
83
|
+
|
84
|
+
short * ""
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.input_format(name, type = nil, default = nil, short = "")
|
88
|
+
short = short_for(name) if not short.nil? and short.empty?
|
89
|
+
|
90
|
+
input_str = short.nil? ? "--#{name}" : "-#{short}, --#{name}"
|
91
|
+
input_str << case type
|
92
|
+
when nil
|
93
|
+
"#{default != nil ? " (default '#{default}')" : ""}:"
|
94
|
+
when :boolean
|
95
|
+
"[=false]#{default != nil ? " (default '#{default}')" : ""}:"
|
96
|
+
when :tsv, :text
|
97
|
+
"=<filename.#{type}|->#{default != nil ? " (default '#{default}')" : ""}; Use '-' for STDIN:"
|
98
|
+
when :array
|
99
|
+
"=<string[,string]*|filename.list|->#{default != nil ? " (default '#{default}')" : ""}; Use '-' for STDIN:"
|
100
|
+
else
|
101
|
+
"=<#{ type }>#{default != nil ? " (default '#{default}')" : ""}:"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.input_doc(inputs, input_types = nil, input_descriptions = nil, input_defaults = nil, input_shortcuts = nil)
|
106
|
+
type = description = default = nil
|
107
|
+
shortcut = ""
|
108
|
+
inputs.collect do |name|
|
109
|
+
|
110
|
+
type = input_types[name] unless input_types.nil?
|
111
|
+
description = input_descriptions[name] unless input_descriptions.nil?
|
112
|
+
default = input_defaults[name] unless input_defaults.nil?
|
113
|
+
shortcut = input_shortcuts[name] unless input_shortcuts.nil?
|
114
|
+
|
115
|
+
type = :string if type.nil?
|
116
|
+
|
117
|
+
str = " * " << SOPT.input_format(name, type.to_sym, default, shortcut) << "\n"
|
118
|
+
str << " " << description << "\n" if description and not description.empty?
|
119
|
+
str
|
120
|
+
end * "\n"
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.doc
|
124
|
+
doc = <<-EOF
|
125
|
+
#{command}(1) -- #{summary}
|
126
|
+
#{"=" * (command.length + summary.length + 7)}
|
127
|
+
|
128
|
+
## SYNOPSYS
|
129
|
+
|
130
|
+
#{synopsys}
|
131
|
+
|
132
|
+
## DESCRIPTION
|
133
|
+
|
134
|
+
#{description}
|
135
|
+
|
136
|
+
## OPTIONS
|
137
|
+
|
138
|
+
#{input_doc(inputs, input_types, input_descriptions, input_defaults, input_shortcuts)}
|
139
|
+
EOF
|
140
|
+
end
|
141
|
+
|
2
142
|
def self.name(info)
|
3
143
|
(info[:long] || info[:short]).sub(/^-*/,'')
|
4
144
|
end
|
5
145
|
|
6
146
|
def self.parse(opts)
|
7
147
|
info = {}
|
148
|
+
|
8
149
|
opts.split(/:/).each do |opt|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
150
|
+
next if opt.strip.empty?
|
151
|
+
|
152
|
+
short, long = opt.strip.sub(/(^[^\s]*)\*/,'\1').split('--').values_at(0,1)
|
153
|
+
long, short = short, nil if long.nil?
|
154
|
+
|
155
|
+
if long.index(" ")
|
156
|
+
long, description = long.match(/^([^\s]+)\s+(.*)/).values_at 1, 2
|
157
|
+
else
|
158
|
+
description = nil
|
159
|
+
end
|
160
|
+
|
161
|
+
i= { :arg => !!opt.match(/^[^\s]*\*/) }
|
162
|
+
|
163
|
+
i[:short] = short unless short.nil? || short.empty?
|
164
|
+
i[:long] = '--' + long unless long.nil? || long.empty?
|
165
|
+
i[:description] = description unless description.nil? || description.empty?
|
166
|
+
|
167
|
+
if shortcuts.include? short
|
168
|
+
i[:short] = short_for(i[:long])
|
169
|
+
Log.debug("Short for #{ long } is taken. Changed to #{i[:short]}")
|
170
|
+
else
|
171
|
+
shortcuts << i[:short] if short
|
172
|
+
end
|
173
|
+
|
174
|
+
record(i)
|
175
|
+
|
15
176
|
info[name(i)] = i
|
16
177
|
end
|
17
178
|
|
@@ -51,7 +212,7 @@ module SOPT
|
|
51
212
|
end
|
52
213
|
options[name.to_sym] = value
|
53
214
|
else
|
54
|
-
options[name.to_sym] = true
|
215
|
+
options[name.to_sym] = value == "false" ? false : true
|
55
216
|
end
|
56
217
|
else
|
57
218
|
rest << orig_arg
|
data/lib/rbbt/workflow.rb
CHANGED
@@ -41,14 +41,14 @@ module Workflow
|
|
41
41
|
when ((File.exists?(wf_name.find) and not File.directory?(wf_name.find)) or File.exists?(wf_name.find + '.rb'))
|
42
42
|
$LOAD_PATH.unshift(File.join(File.expand_path(File.dirname(wf_name.find)), 'lib'))
|
43
43
|
require wf_name.find
|
44
|
-
Log.
|
44
|
+
Log.medium "Workflow loaded from file: #{ wf_name }"
|
45
45
|
return true
|
46
46
|
|
47
47
|
# Points to workflow dir
|
48
48
|
when (File.exists?(wf_name.find) and File.directory?(wf_name.find) and File.exists?(File.join(wf_name.find, 'workflow.rb')))
|
49
49
|
$LOAD_PATH.unshift(File.join(File.expand_path(wf_name.find), 'lib'))
|
50
50
|
require File.join(wf_name.find, 'workflow.rb')
|
51
|
-
Log.
|
51
|
+
Log.medium "Workflow loaded from directory: #{ wf_name }"
|
52
52
|
return true
|
53
53
|
|
54
54
|
else
|
@@ -61,7 +61,7 @@ module Workflow
|
|
61
61
|
when ((File.exists?(wf_name) and not File.directory?(wf_name)) or File.exists?(wf_name + '.rb'))
|
62
62
|
$LOAD_PATH.unshift(File.join(File.expand_path(File.dirname(wf_name)), 'lib'))
|
63
63
|
require wf_name
|
64
|
-
Log.
|
64
|
+
Log.medium "Workflow loaded from file: #{ wf_name }"
|
65
65
|
return true
|
66
66
|
|
67
67
|
when (defined?(Rbbt) and Rbbt.etc.workflow_dir.exists?)
|
@@ -69,21 +69,21 @@ module Workflow
|
|
69
69
|
dir = File.join(dir, wf_name)
|
70
70
|
$LOAD_PATH.unshift(File.join(File.expand_path(dir), 'lib'))
|
71
71
|
require File.join(dir, 'workflow.rb')
|
72
|
-
Log.
|
72
|
+
Log.medium "Workflow #{wf_name} loaded from workflow_dir: #{ dir }"
|
73
73
|
return true
|
74
74
|
|
75
75
|
when defined?(Rbbt)
|
76
76
|
path = Rbbt.workflows[wf_name].find
|
77
77
|
$LOAD_PATH.unshift(File.join(File.expand_path(path), 'lib'))
|
78
78
|
require File.join(path, 'workflow.rb')
|
79
|
-
Log.
|
79
|
+
Log.medium "Workflow #{wf_name} loaded from Rbbt.workflows: #{ path }"
|
80
80
|
return true
|
81
81
|
|
82
82
|
else
|
83
83
|
path = File.join(ENV['HOME'], '.workflows', wf_name)
|
84
84
|
$LOAD_PATH.unshift(File.join(File.expand_path(path), 'lib'))
|
85
85
|
require File.join(path, 'workflow.rb')
|
86
|
-
Log.
|
86
|
+
Log.medium "Workflow #{wf_name} loaded from .workflows: #{ path }"
|
87
87
|
return true
|
88
88
|
end
|
89
89
|
end
|
@@ -211,6 +211,7 @@ module Workflow
|
|
211
211
|
path = File.join(workdir, id)
|
212
212
|
task = task_for path
|
213
213
|
step = Step.new path, tasks[task.to_sym]
|
214
|
+
step.info
|
214
215
|
if step.info.include? :dependencies
|
215
216
|
step.dependencies = step.info[:dependencies].collect do |task, job|
|
216
217
|
load_id(File.join(task.to_s, job))
|
data/lib/rbbt/workflow/step.rb
CHANGED
@@ -68,16 +68,14 @@ class Step
|
|
68
68
|
|
69
69
|
def join
|
70
70
|
if @pid.nil?
|
71
|
-
|
72
|
-
sleep 5
|
73
|
-
end
|
71
|
+
self
|
74
72
|
else
|
75
|
-
Log.debug "Waiting for pid: #{@pid}"
|
76
73
|
begin
|
77
|
-
|
74
|
+
Log.debug "Waiting for pid: #{@pid}"
|
75
|
+
Process.waitpid @pid
|
78
76
|
rescue Errno::ECHILD
|
79
77
|
Log.debug "Process #{ @pid } already finished: #{ path }"
|
80
|
-
end
|
78
|
+
end if Misc.pid_exists? @pid
|
81
79
|
@pid = nil
|
82
80
|
end
|
83
81
|
self
|
@@ -108,7 +106,8 @@ class Step
|
|
108
106
|
end
|
109
107
|
}
|
110
108
|
|
111
|
-
|
109
|
+
Log.medium("Starting task #{task.name || ""} [#{Process.pid}]: #{ path }")
|
110
|
+
set_info :status, :started
|
112
111
|
|
113
112
|
set_info :started, Time.now
|
114
113
|
|
@@ -147,6 +146,8 @@ class Step
|
|
147
146
|
end
|
148
147
|
|
149
148
|
set_info :status, :done
|
149
|
+
set_info :done, Time.now
|
150
|
+
Log.medium("Completed task #{task.name || ""} [#{Process.pid}]: #{ path }")
|
150
151
|
res
|
151
152
|
end
|
152
153
|
|
@@ -164,6 +165,12 @@ class Step
|
|
164
165
|
FileUtils.mkdir_p File.dirname(path) unless File.exists? File.dirname(path)
|
165
166
|
begin
|
166
167
|
run
|
168
|
+
rescue Exception
|
169
|
+
Log.debug("Exception caught on forked process: #{$!.message}")
|
170
|
+
exit -1
|
171
|
+
end
|
172
|
+
|
173
|
+
begin
|
167
174
|
children_pids = info[:children_pids]
|
168
175
|
if children_pids
|
169
176
|
children_pids.each do |pid|
|
@@ -177,7 +184,7 @@ class Step
|
|
177
184
|
end
|
178
185
|
end
|
179
186
|
rescue Exception
|
180
|
-
Log.debug("Exception
|
187
|
+
Log.debug("Exception waiting for children: #{$!.message}")
|
181
188
|
exit -1
|
182
189
|
end
|
183
190
|
set_info :pid, nil
|
data/lib/rbbt/workflow/usage.rb
CHANGED
@@ -1,28 +1,11 @@
|
|
1
|
+
require 'rbbt/util/simpleopt'
|
1
2
|
|
2
3
|
module Task
|
3
4
|
def doc(deps = nil)
|
4
|
-
|
5
5
|
puts "## #{ name }:"
|
6
6
|
puts "\n" << description if description and not description.empty?
|
7
|
-
puts
|
8
|
-
|
9
|
-
inputs.each do |name|
|
10
|
-
short = name.to_s.chars.first
|
11
|
-
|
12
|
-
description = input_descriptions[name]
|
13
|
-
default = input_defaults[name]
|
14
|
-
type = input_types[name]
|
15
|
-
|
16
|
-
|
17
|
-
if type.to_sym == :boolean
|
18
|
-
puts " * -#{short}, --#{name}[=<true|false>]#{default != nil ? " (default: #{default})" : ""}:"
|
19
|
-
else
|
20
|
-
puts " * -#{short}, --#{name}=<#{ type }>#{default != nil ? " (default: #{default})" : ""}:"
|
21
|
-
end
|
22
|
-
|
23
|
-
puts " " << description if description and not description.empty?
|
24
|
-
puts
|
25
|
-
end
|
7
|
+
puts
|
8
|
+
puts SOPT.input_doc(inputs, input_types, input_descriptions, input_defaults)
|
26
9
|
|
27
10
|
if deps and deps.any?
|
28
11
|
puts
|
@@ -31,22 +14,7 @@ module Task
|
|
31
14
|
deps.each do |dep|
|
32
15
|
puts " #{dep.name}:"
|
33
16
|
puts
|
34
|
-
dep.inputs.
|
35
|
-
short = name.to_s.chars.first
|
36
|
-
|
37
|
-
description = dep.input_descriptions[name]
|
38
|
-
default = dep.input_defaults[name]
|
39
|
-
type = dep.input_types[name]
|
40
|
-
|
41
|
-
if type.to_sym == :boolean
|
42
|
-
puts " * -#{short}, --#{name}[=<true|false>]#{default != nil ? " (default: #{default})" : ""}:"
|
43
|
-
else
|
44
|
-
puts " * -#{short}, --#{name}=<#{ type }>#{default != nil ? " (default: #{default})" : ""}:"
|
45
|
-
end
|
46
|
-
|
47
|
-
puts " " << description if description and not description.empty?
|
48
|
-
puts
|
49
|
-
end
|
17
|
+
puts SOPT.input_doc(dep.inputs, dep.input_types, dep.input_descriptions, dep.input_defaults)
|
50
18
|
end
|
51
19
|
end
|
52
20
|
end
|
@@ -14,5 +14,6 @@ app_dir = app_dir[app]
|
|
14
14
|
server = options[:server] || 'thin'
|
15
15
|
|
16
16
|
Misc.in_dir(app_dir) do
|
17
|
-
|
17
|
+
`env RBBT_LOG=#{Log.severity} #{options.include?(:environment)? "env RACK_ENV=#{options[:environment]}" : ""} \
|
18
|
+
#{server} start -p #{options[:port]} #{ARGV.collect{|a| "'#{a}'"} * " "}`
|
18
19
|
end
|
@@ -5,6 +5,9 @@ require 'rbbt/workflow'
|
|
5
5
|
require 'rbbt/workflow/usage'
|
6
6
|
|
7
7
|
def usage(workflow = nil, task = nil)
|
8
|
+
puts SOPT.doc
|
9
|
+
puts "## WORKFLOW"
|
10
|
+
puts
|
8
11
|
if workflow.nil?
|
9
12
|
puts "No workflow specified"
|
10
13
|
exit -1
|
@@ -14,6 +17,9 @@ def usage(workflow = nil, task = nil)
|
|
14
17
|
workflow.load_tasks if workflow.respond_to? :load_tasks
|
15
18
|
workflow.doc
|
16
19
|
else
|
20
|
+
puts workflow.to_s
|
21
|
+
puts "=" * workflow.to_s.length
|
22
|
+
puts
|
17
23
|
workflow.doc(task)
|
18
24
|
end
|
19
25
|
|
@@ -94,7 +100,14 @@ def fix_options(workflow, task, job_options)
|
|
94
100
|
job_options_cleaned
|
95
101
|
end
|
96
102
|
|
97
|
-
options = SOPT.get
|
103
|
+
options = SOPT.get <<EOF
|
104
|
+
-h--help Show this help:
|
105
|
+
-as--array_separator* Change the character that separates elements of Arrays, ',', '|', or '\\n' by default:
|
106
|
+
-cl--clean Clean the last step of the job so that it gets recomputed:
|
107
|
+
-rcl--recursive_clean Clean the last step and its dependencies to recompute the job completely:
|
108
|
+
-n--name* Job name to use. The name 'Default' is used by default:
|
109
|
+
-pn--printname Print the name of the job and exit without starting it:
|
110
|
+
EOF
|
98
111
|
|
99
112
|
workflow = ARGV.shift
|
100
113
|
usage if workflow.nil?
|
@@ -103,9 +116,9 @@ task = ARGV.shift
|
|
103
116
|
|
104
117
|
|
105
118
|
# Set log, fork, clean, recursive_clean and help
|
106
|
-
Log.severity = options[:log].to_i if options.include? :log
|
107
119
|
help = !!options.delete(:help)
|
108
120
|
do_fork = !!options.delete(:fork)
|
121
|
+
do_exec = !!options.delete(:exec)
|
109
122
|
clean = !!options.delete(:clean)
|
110
123
|
recursive_clean = !!options.delete(:recursive_clean)
|
111
124
|
$array_separator = options.delete(:array_separator)
|
@@ -155,7 +168,7 @@ job_options = fix_options(workflow, task, job_options)
|
|
155
168
|
job = workflow.job(task.name, name, job_options)
|
156
169
|
|
157
170
|
# clean job
|
158
|
-
if clean and job.done?
|
171
|
+
if clean and job.done? != false
|
159
172
|
job.clean
|
160
173
|
sleep 1
|
161
174
|
job = workflow.job(task.name, name, job_options)
|
@@ -168,6 +181,21 @@ if recursive_clean and job.done?
|
|
168
181
|
end
|
169
182
|
|
170
183
|
# run
|
184
|
+
if do_exec
|
185
|
+
res = job.exec
|
186
|
+
case
|
187
|
+
when Array === res
|
188
|
+
puts res * "\n"
|
189
|
+
when TSV === res
|
190
|
+
puts res
|
191
|
+
when Hash === res
|
192
|
+
puts res.to_yaml
|
193
|
+
else
|
194
|
+
puts res
|
195
|
+
end
|
196
|
+
exit 0
|
197
|
+
end
|
198
|
+
|
171
199
|
if do_fork
|
172
200
|
job.fork
|
173
201
|
while not job.done?
|
@@ -175,30 +203,21 @@ if do_fork
|
|
175
203
|
sleep 2
|
176
204
|
end
|
177
205
|
raise job.messages.last if job.error?
|
178
|
-
if $array_separator
|
179
|
-
res = job.load(:sep2 => $array_separator)
|
180
|
-
else
|
181
|
-
res = job.load
|
182
|
-
end
|
183
206
|
else
|
184
|
-
res = job.run
|
207
|
+
res = job.run(true)
|
185
208
|
end
|
186
209
|
|
187
210
|
if options.delete(:printname)
|
188
211
|
puts job.name
|
189
|
-
exit
|
212
|
+
exit 0
|
190
213
|
else
|
191
214
|
Log.low "Job name: #{job.name}"
|
192
215
|
end
|
193
216
|
|
194
|
-
|
195
|
-
|
196
|
-
puts res * "\n"
|
197
|
-
when TSV === res
|
198
|
-
puts res
|
199
|
-
when Hash === res
|
200
|
-
puts res.to_yaml
|
217
|
+
if Step === res
|
218
|
+
puts Open.read(res.path)
|
201
219
|
else
|
202
220
|
puts res
|
203
221
|
end
|
204
222
|
|
223
|
+
exit 0
|
data/test/rbbt/test_tsv.rb
CHANGED
@@ -420,6 +420,22 @@ row2 b bbb bbbb bb
|
|
420
420
|
end
|
421
421
|
end
|
422
422
|
|
423
|
+
def test_flat_key
|
424
|
+
content =<<-EOF
|
425
|
+
#Id ValueA
|
426
|
+
row1 a aa aaa
|
427
|
+
row2 b bbb bbbb bb aa
|
428
|
+
EOF
|
429
|
+
|
430
|
+
TmpFile.with_file(content) do |filename|
|
431
|
+
tsv = TSV.open(filename, :sep => /\s+/, :merge => true, :type => :flat, :key_field => "ValueA")
|
432
|
+
assert_equal ["row1"], tsv["a"]
|
433
|
+
assert_equal ["row1", "row2"], tsv["aa"]
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
|
438
|
+
|
423
439
|
def test_zipped
|
424
440
|
content =<<-EOF
|
425
441
|
#Id ValueA ValueB
|
data/test/rbbt/util/test_misc.rb
CHANGED
@@ -220,4 +220,8 @@ class TestMisc < Test::Unit::TestCase
|
|
220
220
|
assert_equal "ACRONIM_test", Misc.snake_case(str1)
|
221
221
|
assert_equal "ACRONIM_test", Misc.snake_case(str2)
|
222
222
|
end
|
223
|
+
|
224
|
+
def test_correct_vcf_mutations
|
225
|
+
assert_equal [737407, ["-----", "-----G", "-----GTTAAT"]], Misc.correct_vcf_mutation(737406, "GTTAAT", "G,GG,GGTTAAT")
|
226
|
+
end
|
223
227
|
end
|
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbbt-util
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.2.
|
5
|
-
prerelease:
|
4
|
+
version: 5.2.4
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Miguel Vazquez
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-05-
|
11
|
+
date: 2013-05-27 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rake
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ! '>='
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ! '>='
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,7 +27,6 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: spreadsheet
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ! '>='
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ! '>='
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -46,7 +41,6 @@ dependencies:
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: ruby-prof
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - ! '>='
|
52
46
|
- !ruby/object:Gem::Version
|
@@ -54,7 +48,6 @@ dependencies:
|
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
52
|
- - ! '>='
|
60
53
|
- !ruby/object:Gem::Version
|
@@ -62,7 +55,6 @@ dependencies:
|
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: tokyocabinet
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
59
|
- - ! '>='
|
68
60
|
- !ruby/object:Gem::Version
|
@@ -70,7 +62,6 @@ dependencies:
|
|
70
62
|
type: :runtime
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
66
|
- - ! '>='
|
76
67
|
- !ruby/object:Gem::Version
|
@@ -78,7 +69,6 @@ dependencies:
|
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: progress-monitor
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
73
|
- - ! '>='
|
84
74
|
- !ruby/object:Gem::Version
|
@@ -86,7 +76,6 @@ dependencies:
|
|
86
76
|
type: :runtime
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
80
|
- - ! '>='
|
92
81
|
- !ruby/object:Gem::Version
|
@@ -94,7 +83,6 @@ dependencies:
|
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
84
|
name: lockfile
|
96
85
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
86
|
requirements:
|
99
87
|
- - ! '>='
|
100
88
|
- !ruby/object:Gem::Version
|
@@ -102,7 +90,6 @@ dependencies:
|
|
102
90
|
type: :runtime
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
93
|
requirements:
|
107
94
|
- - ! '>='
|
108
95
|
- !ruby/object:Gem::Version
|
@@ -110,7 +97,6 @@ dependencies:
|
|
110
97
|
- !ruby/object:Gem::Dependency
|
111
98
|
name: RubyInline
|
112
99
|
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
100
|
requirements:
|
115
101
|
- - ! '>='
|
116
102
|
- !ruby/object:Gem::Version
|
@@ -118,7 +104,6 @@ dependencies:
|
|
118
104
|
type: :runtime
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
107
|
requirements:
|
123
108
|
- - ! '>='
|
124
109
|
- !ruby/object:Gem::Version
|
@@ -126,7 +111,6 @@ dependencies:
|
|
126
111
|
- !ruby/object:Gem::Dependency
|
127
112
|
name: narray
|
128
113
|
requirement: !ruby/object:Gem::Requirement
|
129
|
-
none: false
|
130
114
|
requirements:
|
131
115
|
- - ! '>='
|
132
116
|
- !ruby/object:Gem::Version
|
@@ -134,7 +118,6 @@ dependencies:
|
|
134
118
|
type: :runtime
|
135
119
|
prerelease: false
|
136
120
|
version_requirements: !ruby/object:Gem::Requirement
|
137
|
-
none: false
|
138
121
|
requirements:
|
139
122
|
- - ! '>='
|
140
123
|
- !ruby/object:Gem::Version
|
@@ -142,7 +125,6 @@ dependencies:
|
|
142
125
|
- !ruby/object:Gem::Dependency
|
143
126
|
name: simplews
|
144
127
|
requirement: !ruby/object:Gem::Requirement
|
145
|
-
none: false
|
146
128
|
requirements:
|
147
129
|
- - ! '>='
|
148
130
|
- !ruby/object:Gem::Version
|
@@ -150,7 +132,6 @@ dependencies:
|
|
150
132
|
type: :runtime
|
151
133
|
prerelease: false
|
152
134
|
version_requirements: !ruby/object:Gem::Requirement
|
153
|
-
none: false
|
154
135
|
requirements:
|
155
136
|
- - ! '>='
|
156
137
|
- !ruby/object:Gem::Version
|
@@ -158,7 +139,6 @@ dependencies:
|
|
158
139
|
- !ruby/object:Gem::Dependency
|
159
140
|
name: highline
|
160
141
|
requirement: !ruby/object:Gem::Requirement
|
161
|
-
none: false
|
162
142
|
requirements:
|
163
143
|
- - ! '>='
|
164
144
|
- !ruby/object:Gem::Version
|
@@ -166,7 +146,6 @@ dependencies:
|
|
166
146
|
type: :runtime
|
167
147
|
prerelease: false
|
168
148
|
version_requirements: !ruby/object:Gem::Requirement
|
169
|
-
none: false
|
170
149
|
requirements:
|
171
150
|
- - ! '>='
|
172
151
|
- !ruby/object:Gem::Version
|
@@ -286,27 +265,26 @@ files:
|
|
286
265
|
- bin/rbbt_dangling_locks.rb
|
287
266
|
homepage: http://github.com/mikisvaz/rbbt-util
|
288
267
|
licenses: []
|
268
|
+
metadata: {}
|
289
269
|
post_install_message:
|
290
270
|
rdoc_options: []
|
291
271
|
require_paths:
|
292
272
|
- lib
|
293
273
|
required_ruby_version: !ruby/object:Gem::Requirement
|
294
|
-
none: false
|
295
274
|
requirements:
|
296
275
|
- - ! '>='
|
297
276
|
- !ruby/object:Gem::Version
|
298
277
|
version: '0'
|
299
278
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
300
|
-
none: false
|
301
279
|
requirements:
|
302
280
|
- - ! '>='
|
303
281
|
- !ruby/object:Gem::Version
|
304
282
|
version: '0'
|
305
283
|
requirements: []
|
306
284
|
rubyforge_project:
|
307
|
-
rubygems_version:
|
285
|
+
rubygems_version: 2.0.3
|
308
286
|
signing_key:
|
309
|
-
specification_version:
|
287
|
+
specification_version: 4
|
310
288
|
summary: Utilities for the Ruby Bioinformatics Toolkit (rbbt)
|
311
289
|
test_files:
|
312
290
|
- test/rbbt/tsv/test_accessor.rb
|