miga-base 1.1.3.5 → 1.2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/miga/cli/action/browse.rb +1 -1
- data/lib/miga/cli/action/daemon.rb +7 -3
- data/lib/miga/cli/action/derep_wf.rb +5 -5
- data/lib/miga/cli/action/doctor.rb +16 -7
- data/lib/miga/cli/action/get_db.rb +5 -1
- data/lib/miga/cli/action/init/files_helper.rb +6 -1
- data/lib/miga/cli/action/init.rb +30 -26
- data/lib/miga/cli/action/run.rb +21 -9
- data/lib/miga/cli/action/tax_dist.rb +0 -1
- data/lib/miga/cli/opt_helper.rb +11 -6
- data/lib/miga/common/errors.rb +12 -0
- data/lib/miga/common/format.rb +0 -1
- data/lib/miga/common/system_call.rb +93 -0
- data/lib/miga/common.rb +13 -3
- data/lib/miga/daemon.rb +4 -2
- data/lib/miga/result/stats.rb +5 -6
- data/lib/miga/tax_dist.rb +0 -1
- data/lib/miga/version.rb +2 -2
- data/test/system_call_test.rb +50 -0
- data/utils/distance/base.rb +1 -1
- data/utils/distance/commands.rb +2 -3
- data/utils/distance/pipeline.rb +3 -3
- data/utils/find-medoid.R +1 -2
- data/utils/subclade/base.rb +6 -1
- data/utils/subclade/pipeline.rb +18 -7
- data/utils/subclade/runner.rb +2 -6
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27068ded9d2ff63c3575a5aafd3fa68374f4bcf8aef924354e0c9cbde7dc1f6d
|
4
|
+
data.tar.gz: ef438e828180d304a9e3449d49551ace933a5e5a46128970b3c8bc385c836d58
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 894cbeca2aa4f5e29c6bd6e1c23c9c358b9f3b497960998116169fa62d7122da78417e357789dc9b9b7bfdfad824f835b3daa035d1320cb948e5cdc4b1d74bb3
|
7
|
+
data.tar.gz: 8bea4585b36855195f3a2d76005a6ff664133c1df639a677402907c88fd8f6b0a25fb34cc4bd0e9e38bc7666dbe3a382644137dcf5cddd4005c93256d2c75c05
|
@@ -179,7 +179,7 @@ class MiGA::Cli::Action::Browse < MiGA::Cli::Action
|
|
179
179
|
str
|
180
180
|
.to_s.unmiga_name
|
181
181
|
.sub(/^./, &:upcase)
|
182
|
-
.gsub(/(Aai|Ani|Ogs|Cds|Ssu| db$| ssu )/, &:upcase)
|
182
|
+
.gsub(/(Aai|Ani|Ogs|Cds|Ssu|Rds|ani95|aai90| db$| ssu )/, &:upcase)
|
183
183
|
.sub(/Haai/, 'hAAI')
|
184
184
|
.sub(/Mytaxa/, 'MyTaxa')
|
185
185
|
.sub(/ pvalue$/, ' p-value')
|
@@ -38,9 +38,13 @@ class MiGA::Cli::Action::Daemon < MiGA::Cli::Action
|
|
38
38
|
'Path to the list of execution hostnames'
|
39
39
|
) { |v| cli[:nodelist] = v }
|
40
40
|
opt.on(
|
41
|
-
'--ppn INT',
|
41
|
+
'--ppn INT', Integer,
|
42
42
|
'Maximum number of cores to use in a single job'
|
43
|
-
) { |v| cli[:ppn] = v
|
43
|
+
) { |v| cli[:ppn] = v }
|
44
|
+
opt.on(
|
45
|
+
'--ppn-project INT', Integer,
|
46
|
+
'Maximum number of cores to use in project-wide tasks'
|
47
|
+
) { |v| cli[:ppn_project] = v }
|
44
48
|
opt.on(
|
45
49
|
'--json PATH',
|
46
50
|
'Path to a custom daemon definition in json format'
|
@@ -81,7 +85,7 @@ class MiGA::Cli::Action::Daemon < MiGA::Cli::Action
|
|
81
85
|
# Configure and run daemon
|
82
86
|
p = cli.load_project
|
83
87
|
d = MiGA::Daemon.new(p, cli[:json])
|
84
|
-
dopts = %i[latency maxjobs nodelist ppn shutdown_when_done]
|
88
|
+
dopts = %i[latency maxjobs nodelist ppn ppn_project shutdown_when_done]
|
85
89
|
dopts.each { |k| d.runopts(k, cli[k]) }
|
86
90
|
d.show_log! if cli[:show_log]
|
87
91
|
d.daemon(cli.operation, cli[:daemon_opts])
|
@@ -73,14 +73,14 @@ class MiGA::Cli::Action::DerepWf < MiGA::Cli::Action
|
|
73
73
|
c_f = r.file_path(:clades_gsp) or raise 'Result incomplete: run failed'
|
74
74
|
clades = File.readlines(c_f).map { |i| i.chomp.split("\t") }
|
75
75
|
rep = representatives(p)
|
76
|
-
File.open(File.
|
76
|
+
File.open(File.join(cli[:outdir], 'genomospecies.tsv'), 'w') do |fh|
|
77
77
|
fh.puts "Clade\tRepresentative\tMembers"
|
78
78
|
clades.each_with_index do |i, k|
|
79
79
|
fh.puts ["gsp_#{k + 1}", rep[k], i.join(',')].join("\t")
|
80
80
|
end
|
81
81
|
end
|
82
82
|
if cli[:collection]
|
83
|
-
dir = File.
|
83
|
+
dir = File.join(cli[:outdir], 'representatives')
|
84
84
|
FileUtils.mkdir_p(dir)
|
85
85
|
rep.each do |i|
|
86
86
|
f = p.dataset(i).result(:assembly).file_path(:largecontigs)
|
@@ -91,12 +91,12 @@ class MiGA::Cli::Action::DerepWf < MiGA::Cli::Action
|
|
91
91
|
|
92
92
|
def representatives(p)
|
93
93
|
cli.say 'Identifying representatives'
|
94
|
-
f = File.
|
94
|
+
f = File.join(cli[:outdir], 'representatives.txt')
|
95
95
|
if cli[:criterion] == :medoids
|
96
96
|
FileUtils.cp(p.result(:clade_finding).file_path(:medoids_gsp), f)
|
97
97
|
else
|
98
|
-
src = File.
|
99
|
-
|
98
|
+
src = File.join(MiGA::MiGA.root_path, 'utils/representatives.rb')
|
99
|
+
MiGA::MiGA.run_cmd("ruby '#{src}' '#{p.path}' | cut -f 2", stdout: f)
|
100
100
|
end
|
101
101
|
File.readlines(f).map(&:chomp)
|
102
102
|
end
|
@@ -236,8 +236,7 @@ class MiGA::Cli::Action::Doctor < MiGA::Cli::Action
|
|
236
236
|
file = res.file_path(f) or next
|
237
237
|
if file !~ /\.gz/
|
238
238
|
cli.say " > Gzipping #{d.name} #{f} "
|
239
|
-
|
240
|
-
warn(cmdo) unless cmdo.empty?
|
239
|
+
run_cmd(['gzip', '-9', file])
|
241
240
|
changed = true
|
242
241
|
end
|
243
242
|
end
|
@@ -267,8 +266,9 @@ class MiGA::Cli::Action::Doctor < MiGA::Cli::Action
|
|
267
266
|
next if Dir["#{dir}/*.faa"].empty?
|
268
267
|
|
269
268
|
cli.say " > Fixing #{d.name}"
|
270
|
-
|
271
|
-
|
269
|
+
run_cmd <<~CMD
|
270
|
+
cd #{dir.shellescape} && tar -zcf proteins.tar.gz *.faa && rm *.faa
|
271
|
+
CMD
|
272
272
|
end
|
273
273
|
end
|
274
274
|
|
@@ -292,10 +292,11 @@ class MiGA::Cli::Action::Doctor < MiGA::Cli::Action
|
|
292
292
|
fix = false
|
293
293
|
unless dir.nil?
|
294
294
|
if Dir.exist? dir
|
295
|
-
|
295
|
+
run_cmd <<~CMD
|
296
|
+
cd #{dir.shellescape}/.. \
|
296
297
|
&& tar -zcf '#{d.name}.reg.tar.gz' '#{d.name}.reg' \
|
297
|
-
&& rm -r '#{d.name}.reg'
|
298
|
-
|
298
|
+
&& rm -r '#{d.name}.reg'
|
299
|
+
CMD
|
299
300
|
end
|
300
301
|
fix = true
|
301
302
|
end
|
@@ -335,4 +336,12 @@ class MiGA::Cli::Action::Doctor < MiGA::Cli::Action
|
|
335
336
|
# TODO: Find different 95%ANI clusters with genomes from the same species
|
336
337
|
# TODO: Find AAI values too high or too low for each LCA rank
|
337
338
|
end
|
339
|
+
|
340
|
+
##
|
341
|
+
# Run command +cmd+ with options +opts+
|
342
|
+
def run_cmd(cmd, opts = {})
|
343
|
+
opts = { return: :output, err2out: true, raise: false }.merge(opts)
|
344
|
+
cmdo = MiGA::MiGA.run_cmd(cmd, opts).chomp
|
345
|
+
warn(cmdo) unless cmdo.empty?
|
346
|
+
end
|
338
347
|
end
|
@@ -190,7 +190,11 @@ class MiGA::Cli::Action::GetDb < MiGA::Cli::Action
|
|
190
190
|
|
191
191
|
def unarchive(file)
|
192
192
|
cli.say "Unarchiving #{file}"
|
193
|
-
|
193
|
+
MiGA::MiGA.run_cmd <<~CMD
|
194
|
+
cd #{cli[:local].shellescape} \
|
195
|
+
&& tar -zxf #{file.shellescape} \
|
196
|
+
&& rm #{file.shellescape}
|
197
|
+
CMD
|
194
198
|
end
|
195
199
|
|
196
200
|
def register_database(manif, db, ver)
|
@@ -107,7 +107,12 @@ module MiGA::Cli::Action::Init::FilesHelper
|
|
107
107
|
MiGA::MiGA.download_file_ftp(
|
108
108
|
:miga_dist, arch, File.join(miga_db, arch)
|
109
109
|
) { |n, size| cli.advance("#{arch}:", n, size) }
|
110
|
-
|
110
|
+
cmd = <<~CMD
|
111
|
+
cd #{miga_db.shellescape} \
|
112
|
+
&& tar zxf #{arch.shellescape} \
|
113
|
+
&& rm #{arch.shellescape}
|
114
|
+
CMD
|
115
|
+
run_cmd(cmd, source: nil)
|
111
116
|
cli.puts
|
112
117
|
end
|
113
118
|
end
|
data/lib/miga/cli/action/init.rb
CHANGED
@@ -83,14 +83,16 @@ class MiGA::Cli::Action::Init < MiGA::Cli::Action
|
|
83
83
|
def empty_action
|
84
84
|
end
|
85
85
|
|
86
|
-
def run_cmd(cli, cmd)
|
87
|
-
|
86
|
+
def run_cmd(cli, cmd, opts = {})
|
87
|
+
opts = { return: :output, source: cli[:config] }.merge(opts)
|
88
|
+
MiGA::MiGA.run_cmd(cmd, opts)
|
88
89
|
end
|
89
90
|
|
90
|
-
def run_r_cmd(cli, paths, cmd)
|
91
|
+
def run_r_cmd(cli, paths, cmd, opts = {})
|
91
92
|
run_cmd(
|
92
93
|
cli,
|
93
|
-
"echo #{cmd.shellescape} | #{paths['R'].shellescape} --vanilla -q
|
94
|
+
"echo #{cmd.shellescape} | #{paths['R'].shellescape} --vanilla -q",
|
95
|
+
{ err2out: true, stdout: '/dev/null' }.merge(opts)
|
94
96
|
)
|
95
97
|
end
|
96
98
|
|
@@ -159,7 +161,7 @@ class MiGA::Cli::Action::Init < MiGA::Cli::Action
|
|
159
161
|
def find_software(exec)
|
160
162
|
path = nil
|
161
163
|
loop do
|
162
|
-
d_path = File.dirname(run_cmd(cli,
|
164
|
+
d_path = File.dirname(run_cmd(cli, ['which', exec], raise: false))
|
163
165
|
if cli[:ask] || d_path == '.'
|
164
166
|
path = cli.ask_user('Where can I find it?', d_path, nil, true)
|
165
167
|
else
|
@@ -172,7 +174,7 @@ class MiGA::Cli::Action::Init < MiGA::Cli::Action
|
|
172
174
|
end
|
173
175
|
break
|
174
176
|
end
|
175
|
-
cli.print "I cannot find #{exec} "
|
177
|
+
cli.print "I cannot find #{exec}. "
|
176
178
|
end
|
177
179
|
path
|
178
180
|
end
|
@@ -208,19 +210,21 @@ class MiGA::Cli::Action::Init < MiGA::Cli::Action
|
|
208
210
|
end
|
209
211
|
|
210
212
|
def test_library(cli, paths, language, pkg)
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
213
|
+
opts = { raise: false, return: :status, stderr: '/dev/null' }
|
214
|
+
status =
|
215
|
+
case language
|
216
|
+
when :r
|
217
|
+
run_r_cmd(cli, paths, "library('#{pkg}')", opts)
|
218
|
+
when :ruby
|
219
|
+
x = [paths['ruby'], '-r', pkg, '-e', '']
|
220
|
+
run_cmd(cli, x, opts)
|
221
|
+
when :python
|
222
|
+
x = [paths['python3'], '-c', "import #{pkg}"]
|
223
|
+
run_cmd(cli, x, opts)
|
224
|
+
else
|
225
|
+
raise "Unrecognized language: #{language}"
|
226
|
+
end
|
227
|
+
status.success?
|
224
228
|
end
|
225
229
|
|
226
230
|
def install_library(cli, paths, language, pkg)
|
@@ -232,14 +236,14 @@ class MiGA::Cli::Action::Init < MiGA::Cli::Action
|
|
232
236
|
# This hackey mess is meant to ensure the test and installation are done
|
233
237
|
# on the configuration Ruby, not on the Ruby currently executing the
|
234
238
|
# init action
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
+
x = [
|
240
|
+
paths['ruby'], '-r', 'rubygems', '-r', 'rubygems/gem_runner',
|
241
|
+
'-e', "Gem::GemRunner.new.run %w(install --user #{pkg})"
|
242
|
+
]
|
243
|
+
run_cmd(cli, x, err2out: true)
|
239
244
|
when :python
|
240
|
-
x =
|
241
|
-
|
242
|
-
run_cmd(cli, x)
|
245
|
+
x = [paths['python3'], '-m', 'pip', 'install', '--user', pkg]
|
246
|
+
run_cmd(cli, x, err2out: true)
|
243
247
|
else
|
244
248
|
raise "Unrecognized language: #{language}"
|
245
249
|
end
|
data/lib/miga/cli/action/run.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
# @license Artistic-2.0
|
3
3
|
|
4
4
|
require 'miga/cli/action'
|
5
|
-
require 'shellwords'
|
6
5
|
|
7
6
|
class MiGA::Cli::Action::Run < MiGA::Cli::Action
|
8
7
|
def parse_cli
|
@@ -54,9 +53,13 @@ class MiGA::Cli::Action::Run < MiGA::Cli::Action
|
|
54
53
|
|
55
54
|
# Prepare command
|
56
55
|
miga = MiGA.root_path
|
57
|
-
|
58
|
-
|
59
|
-
|
56
|
+
opts = {}
|
57
|
+
cmd = [
|
58
|
+
"PROJECT=#{p.path.shellescape}",
|
59
|
+
"RUNTYPE=#{cli[:remote] ? 'ssh' : 'bash'}",
|
60
|
+
"MIGA=#{miga.shellescape}",
|
61
|
+
"CORES=#{cli[:thr]}"
|
62
|
+
]
|
60
63
|
obj = cli.load_project_or_dataset
|
61
64
|
klass = obj.class
|
62
65
|
virtual_task = %i[p d maintenance].include?(cli[:result])
|
@@ -67,13 +70,22 @@ class MiGA::Cli::Action::Run < MiGA::Cli::Action
|
|
67
70
|
|
68
71
|
cmd << MiGA.script_path(cli[:result], miga: miga, project: p).shellescape
|
69
72
|
if cli[:remote]
|
70
|
-
cmd = [
|
71
|
-
|
73
|
+
cmd = [
|
74
|
+
'ssh', '-t', '-t',
|
75
|
+
cli[:remote].shellescape,
|
76
|
+
cmd.join(' ').shellescape
|
77
|
+
]
|
78
|
+
end
|
79
|
+
|
80
|
+
if cli[:log]
|
81
|
+
opts[:stdout] = cli[:log]
|
82
|
+
opts[:err2out] = true
|
72
83
|
end
|
73
|
-
cmd << ['>', cli[:log].shellescape, '2>&1'] if cli[:log]
|
74
84
|
|
75
85
|
# Launch
|
76
|
-
|
77
|
-
|
86
|
+
# note that all elements were carefully escaped in advace, so this has to be
|
87
|
+
# passed as String to avoid double-escaping or unintentionally escaping
|
88
|
+
# characters such as `=` and `>`
|
89
|
+
MiGA::MiGA.run_cmd(cmd.join(' '), opts)
|
78
90
|
end
|
79
91
|
end
|
data/lib/miga/cli/opt_helper.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
#
|
2
|
-
# @license Artistic-2.0
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
3
|
+
##
|
4
|
+
# Helper module including functions for CLI options
|
4
5
|
module MiGA::Cli::OptHelper
|
5
6
|
##
|
6
7
|
# Send MiGA's banner to OptionParser +opt+
|
@@ -26,6 +27,10 @@ module MiGA::Cli::OptHelper
|
|
26
27
|
'Accept all defaults as answers'
|
27
28
|
) { |v| self[:auto] = v }
|
28
29
|
end
|
30
|
+
opt.on(
|
31
|
+
'--rand-seed INT', Integer,
|
32
|
+
'Set this seed to initialize pseudo-randomness'
|
33
|
+
) { |v| srand(v) }
|
29
34
|
opt.on(
|
30
35
|
'-v', '--verbose',
|
31
36
|
'Print additional information to STDERR'
|
@@ -61,7 +66,7 @@ module MiGA::Cli::OptHelper
|
|
61
66
|
# - :result_project To require a type of project result
|
62
67
|
# The options :result, :result_opt, :result_dataset, and :result_project
|
63
68
|
# are mutually exclusive
|
64
|
-
def opt_object(opt, what = [
|
69
|
+
def opt_object(opt, what = %i[project dataset])
|
65
70
|
what.each do |w|
|
66
71
|
case w
|
67
72
|
when :project
|
@@ -86,7 +91,7 @@ module MiGA::Cli::OptHelper
|
|
86
91
|
when :result, :result_opt
|
87
92
|
opt.on(
|
88
93
|
'-r', '--result STRING',
|
89
|
-
"#{
|
94
|
+
"#{'(Mandatory) ' if w == :result}Name of the result",
|
90
95
|
'Recognized names for dataset-specific results include:',
|
91
96
|
*MiGA::Dataset.RESULT_DIRS.keys.map { |n| " ~ #{n}" },
|
92
97
|
'Recognized names for project-wide results include:',
|
@@ -118,7 +123,7 @@ module MiGA::Cli::OptHelper
|
|
118
123
|
# - :active To filter by active (--active) or inactive (--no-active)
|
119
124
|
# - :taxonomy To filter by taxonomy (--taxonomy)
|
120
125
|
# The "k-th" filter (--dataset-k) is always included
|
121
|
-
def opt_filter_datasets(opt, what = [
|
126
|
+
def opt_filter_datasets(opt, what = %i[ref multi active taxonomy])
|
122
127
|
what.each do |w|
|
123
128
|
case w
|
124
129
|
when :ref
|
@@ -161,6 +166,6 @@ module MiGA::Cli::OptHelper
|
|
161
166
|
# If +sym+ is nil, +flag+ is used as Symbol
|
162
167
|
def opt_flag(opt, flag, description, sym = nil)
|
163
168
|
sym = flag.to_sym if sym.nil?
|
164
|
-
opt.on("--#{flag.to_s.
|
169
|
+
opt.on("--#{flag.to_s.tr('_', '-')}", description) { |v| self[sym] = v }
|
165
170
|
end
|
166
171
|
end
|
data/lib/miga/common/format.rb
CHANGED
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
3
|
+
##
|
4
|
+
# General functions for process (system call) execution
|
5
|
+
module MiGA::Common::SystemCall
|
6
|
+
##
|
7
|
+
# Execute the command +cmd+ with options +opts+ determined by #run_cmd_opts
|
8
|
+
#
|
9
|
+
# The command +cmd+ can be:
|
10
|
+
# - String: The command is processed as is, without changes
|
11
|
+
# - Array: The command is built with +shelljoin+ so each value is escaped
|
12
|
+
def run_cmd(cmd, opts = {})
|
13
|
+
opts = run_cmd_opts(opts)
|
14
|
+
cmd = cmd.shelljoin if cmd.is_a?(Array)
|
15
|
+
spawn_opts = {}
|
16
|
+
spawn_opts[:out] = opts[:stdout] if opts[:stdout]
|
17
|
+
spawn_opts[:err] = opts[:stderr] if opts[:stderr]
|
18
|
+
out_io, spawn_opts[:out] = IO.pipe if opts[:return] == :output
|
19
|
+
spawn_opts[:err] = [:child, :out] if opts[:err2out] && spawn_opts[:out]
|
20
|
+
opts[:source] = MiGA::MiGA.rc_path if opts[:source] == :miga
|
21
|
+
if opts[:source] && File.exist?(opts[:source])
|
22
|
+
cmd = ". #{opts[:source].shellescape} && #{cmd}"
|
23
|
+
end
|
24
|
+
|
25
|
+
DEBUG "CMD: #{cmd}"
|
26
|
+
puts "CMD: #{cmd}" if opts[:show_cmd]
|
27
|
+
return if opts[:dry]
|
28
|
+
|
29
|
+
pid = nil
|
30
|
+
error = nil
|
31
|
+
begin
|
32
|
+
pid = spawn(opts[:env], cmd, spawn_opts)
|
33
|
+
Process.wait(pid)
|
34
|
+
rescue => e
|
35
|
+
error = e
|
36
|
+
end
|
37
|
+
status = $?
|
38
|
+
|
39
|
+
if opts[:raise] && !status&.success?
|
40
|
+
raise MiGA::SystemCallError.new(
|
41
|
+
"Command failed with status " \
|
42
|
+
"#{status&.exitstatus}#{' (core dump)' if status&.coredump?}:\n" \
|
43
|
+
"#{error&.class}: #{error&.message}\n" \
|
44
|
+
"OPT: #{opts}\n" \
|
45
|
+
"CMD: #{cmd}"
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
case opts[:return]
|
50
|
+
when :status ; status
|
51
|
+
when :pid ; pid
|
52
|
+
when :error ; error
|
53
|
+
when :output
|
54
|
+
spawn_opts[:out].close
|
55
|
+
output = out_io.read
|
56
|
+
out_io.close
|
57
|
+
output
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# Options for #run_cmd using a Hash +opts+ to modify defaults
|
63
|
+
#
|
64
|
+
# Supported keys (as Symbol) include:
|
65
|
+
# - stdout: Redirect STDOUT to this file
|
66
|
+
# - stderr: Redirect STDOUT to this file
|
67
|
+
# - dry: Don't run, just send the command to debug (default: false)
|
68
|
+
# - return: What should the function return, supported values are
|
69
|
+
# +:status+ (Process::Status, default), +:pid+ (Integer, process ID),
|
70
|
+
# +:error+ (Error if failed, nil otherwise), +:output+ (String,
|
71
|
+
# contents sent to STDOUT)
|
72
|
+
# - raise: Raise an exception (MiGA::SystemCallError) in case of failure
|
73
|
+
# (default: true)
|
74
|
+
# - show_cmd: Print command to the STDOUT (prefixed with CMD: ) to ease
|
75
|
+
# debugging (default: false)
|
76
|
+
# - err2out: Redirect STDERR to STDOUT
|
77
|
+
# - env: Environmental variables as a Hash, keys and values must be strings
|
78
|
+
# - source: A file to be sourced before running, or the Symbol +:miga+ to
|
79
|
+
# source the MiGA configuration file
|
80
|
+
def run_cmd_opts(opts = {})
|
81
|
+
{
|
82
|
+
stdout: nil,
|
83
|
+
stderr: nil,
|
84
|
+
dry: false,
|
85
|
+
return: :status,
|
86
|
+
raise: true,
|
87
|
+
show_cmd: false,
|
88
|
+
err2out: false,
|
89
|
+
env: {},
|
90
|
+
source: nil
|
91
|
+
}.merge(opts)
|
92
|
+
end
|
93
|
+
end
|
data/lib/miga/common.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
# @package MiGA
|
2
2
|
# @license Artistic-2.0
|
3
3
|
|
4
|
+
require 'zlib'
|
5
|
+
require 'stringio'
|
4
6
|
require 'miga/version'
|
5
7
|
require 'miga/json'
|
6
8
|
require 'miga/parallel'
|
7
9
|
require 'miga/common/base'
|
10
|
+
require 'miga/common/errors'
|
8
11
|
require 'miga/common/path'
|
9
12
|
require 'miga/common/format'
|
10
13
|
require 'miga/common/net'
|
11
|
-
require '
|
14
|
+
require 'miga/common/system_call'
|
12
15
|
|
13
16
|
##
|
14
17
|
# Generic class used to handle system-wide information and methods, and parent
|
@@ -19,14 +22,21 @@ class MiGA::MiGA
|
|
19
22
|
extend MiGA::Common::Path
|
20
23
|
extend MiGA::Common::Format
|
21
24
|
extend MiGA::Common::Net
|
25
|
+
extend MiGA::Common::SystemCall
|
22
26
|
|
23
27
|
ENV['MIGA_HOME'] ||= ENV['HOME']
|
24
28
|
|
29
|
+
##
|
30
|
+
# Path to the +.miga_rc+ file
|
31
|
+
def self.rc_path
|
32
|
+
File.join(ENV['MIGA_HOME'], '.miga_rc')
|
33
|
+
end
|
34
|
+
|
25
35
|
##
|
26
36
|
# Has MiGA been initialized?
|
27
37
|
def self.initialized?
|
28
|
-
File.exist?(
|
29
|
-
File.exist?(File.
|
38
|
+
File.exist?(rc_path) &&
|
39
|
+
File.exist?(File.join(ENV['MIGA_HOME'], '.miga_daemon.json'))
|
30
40
|
end
|
31
41
|
|
32
42
|
##
|
data/lib/miga/daemon.rb
CHANGED
@@ -321,7 +321,9 @@ class MiGA::Daemon < MiGA::MiGA
|
|
321
321
|
def purge!
|
322
322
|
say 'Probing running jobs'
|
323
323
|
@jobs_running.select! do |job|
|
324
|
-
|
324
|
+
MiGA::MiGA.run_cmd(
|
325
|
+
runopts(:alive).miga_variables(pid: job[:pid]), return: :output
|
326
|
+
).chomp.to_i == 1
|
325
327
|
end
|
326
328
|
end
|
327
329
|
|
@@ -346,7 +348,7 @@ class MiGA::Daemon < MiGA::MiGA
|
|
346
348
|
Process.detach(job[:pid]) unless [nil, '', 0].include?(job[:pid])
|
347
349
|
else
|
348
350
|
# Schedule cluster job (qsub, msub, slurm)
|
349
|
-
job[:pid] =
|
351
|
+
job[:pid] = MiGA::MiGA.run_cmd(job[:cmd], return: :output).chomp
|
350
352
|
end
|
351
353
|
|
352
354
|
# Check if registered
|
data/lib/miga/result/stats.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'zlib'
|
2
1
|
require 'miga/result/base'
|
3
2
|
|
4
3
|
##
|
@@ -198,12 +197,12 @@ module MiGA::Result::Stats
|
|
198
197
|
file_path(:raw_report)
|
199
198
|
|
200
199
|
MiGA::MiGA.DEBUG "Fixing essential genes by domain"
|
201
|
-
scr =
|
200
|
+
scr = File.join(MiGA::MiGA.root_path, 'utils', 'domain-ess-genes.rb')
|
202
201
|
rep = file_path(:report)
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
202
|
+
$stderr.print MiGA::MiGA.run_cmd(
|
203
|
+
['ruby', scr, rep, "#{rep}.domain", tax[:d][0]],
|
204
|
+
return: :output, err2out: true, source: :miga
|
205
|
+
)
|
207
206
|
add_file(:raw_report, "#{source.name}.ess/log")
|
208
207
|
add_file(:report, "#{source.name}.ess/log.domain")
|
209
208
|
end
|
data/lib/miga/tax_dist.rb
CHANGED
data/lib/miga/version.rb
CHANGED
@@ -12,7 +12,7 @@ module MiGA
|
|
12
12
|
# - String indicating release status:
|
13
13
|
# - rc* release candidate, not released as gem
|
14
14
|
# - [0-9]+ stable release, released as gem
|
15
|
-
VERSION = [1.
|
15
|
+
VERSION = [1.2, 0, 1].freeze
|
16
16
|
|
17
17
|
##
|
18
18
|
# Nickname for the current major.minor version.
|
@@ -20,7 +20,7 @@ module MiGA
|
|
20
20
|
|
21
21
|
##
|
22
22
|
# Date of the current gem relese.
|
23
|
-
VERSION_DATE = Date.new(2021,
|
23
|
+
VERSION_DATE = Date.new(2021, 12, 11)
|
24
24
|
|
25
25
|
##
|
26
26
|
# References of MiGA
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class SystemCallTest < Test::Unit::TestCase
|
4
|
+
include TestHelper
|
5
|
+
|
6
|
+
def test_run_cmd_opts
|
7
|
+
assert_equal(true, MiGA::MiGA.run_cmd_opts[:raise])
|
8
|
+
assert_equal(:status, MiGA::MiGA.run_cmd_opts[:return])
|
9
|
+
assert_equal(:pid, MiGA::MiGA.run_cmd_opts(return: :pid)[:return])
|
10
|
+
assert_nil(MiGA::MiGA.run_cmd_opts[:stdout])
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_run_cmd_redirection
|
14
|
+
f1 = tmpfile('f1')
|
15
|
+
MiGA::MiGA.run_cmd('echo 1', stdout: f1)
|
16
|
+
assert_equal("1\n", File.read(f1))
|
17
|
+
|
18
|
+
MiGA::MiGA.run_cmd('echo 2 >&2', stderr: f1)
|
19
|
+
assert_equal("2\n", File.read(f1))
|
20
|
+
|
21
|
+
f2 = tmpfile('with spaces')
|
22
|
+
MiGA::MiGA.run_cmd('echo 3', stdout: f2)
|
23
|
+
assert_equal("3\n", File.read(f2))
|
24
|
+
|
25
|
+
MiGA::MiGA.run_cmd(['echo', 4], stdout: f2)
|
26
|
+
assert_equal("4\n", File.read(f2))
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_run_cmd_return
|
30
|
+
o = MiGA::MiGA.run_cmd('echo 1', stdout: '/dev/null')
|
31
|
+
assert(o.is_a? Process::Status)
|
32
|
+
assert(o.success?)
|
33
|
+
|
34
|
+
o = MiGA::MiGA.run_cmd('echo 1', stdout: '/dev/null', return: :pid)
|
35
|
+
assert(o.is_a? Integer)
|
36
|
+
|
37
|
+
o = MiGA::MiGA.run_cmd('echo 1', stdout: '/dev/null', return: :error)
|
38
|
+
assert_nil(o)
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_run_cmd_raise
|
42
|
+
assert_raise(MiGA::SystemCallError) { MiGA::MiGA.run_cmd('echoes!!!') }
|
43
|
+
|
44
|
+
o = MiGA::MiGA.run_cmd('echoes!!!', raise: false, return: :status)
|
45
|
+
assert_not(o.success?)
|
46
|
+
|
47
|
+
o = MiGA::MiGA.run_cmd('echoes!!!', raise: false, return: :error)
|
48
|
+
assert(o.is_a? Errno::ENOENT)
|
49
|
+
end
|
50
|
+
end
|
data/utils/distance/base.rb
CHANGED
data/utils/distance/commands.rb
CHANGED
@@ -155,7 +155,7 @@ module MiGA::DistanceRunner::Commands
|
|
155
155
|
# Build target database
|
156
156
|
f1 = tmp_file
|
157
157
|
if donors.size == 1
|
158
|
-
|
158
|
+
FileUtils.cp(donors.first, f1)
|
159
159
|
else
|
160
160
|
File.open(f0 = tmp_file, 'w') { |fh| donors.each { |i| fh.puts i } }
|
161
161
|
run_cmd(
|
@@ -227,7 +227,6 @@ module MiGA::DistanceRunner::Commands
|
|
227
227
|
end
|
228
228
|
|
229
229
|
def run_cmd(cmd)
|
230
|
-
|
231
|
-
puts `#{cmd} 2>&1`
|
230
|
+
MiGA::MiGA.run_cmd(cmd, show_cmd: true, err2out: true)
|
232
231
|
end
|
233
232
|
end
|
data/utils/distance/pipeline.rb
CHANGED
@@ -58,9 +58,9 @@ module MiGA::DistanceRunner::Pipeline
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
ds_matrix_fh.close
|
61
|
-
ref_tree = File.
|
62
|
-
|
63
|
-
File.unlink
|
61
|
+
ref_tree = File.join(MiGA::MiGA.root_path, 'utils', 'ref-tree.R')
|
62
|
+
MiGA::MiGA.run_cmd([ref_tree, ds_matrix, out_base, dataset.name])
|
63
|
+
File.unlink(ds_matrix)
|
64
64
|
end
|
65
65
|
|
66
66
|
# Tests taxonomy
|
data/utils/find-medoid.R
CHANGED
@@ -26,7 +26,6 @@ find_medoids <- function (ani.df, out, clades) {
|
|
26
26
|
medoids <- c()
|
27
27
|
for(i in cl){
|
28
28
|
lab <- strsplit(i, ",")[[1]]
|
29
|
-
cat("Clade of:", lab[1], "\n")
|
30
29
|
if(length(lab) == 1) {
|
31
30
|
lab.s <- lab
|
32
31
|
} else {
|
@@ -44,7 +43,7 @@ find_medoids <- function (ani.df, out, clades) {
|
|
44
43
|
}
|
45
44
|
|
46
45
|
#= Main
|
47
|
-
cat("Finding Medoids")
|
46
|
+
cat("Finding Medoids\n")
|
48
47
|
ani <- readRDS(argv[1])
|
49
48
|
find_medoids(ani.df = ani, out = argv[2], clades = argv[3])
|
50
49
|
|
data/utils/subclade/base.rb
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
require 'zlib'
|
2
2
|
require 'miga'
|
3
3
|
|
4
|
-
class MiGA::SubcladeRunner
|
4
|
+
class MiGA::SubcladeRunner < MiGA::MiGA
|
5
|
+
require_relative 'temporal.rb'
|
6
|
+
require_relative 'pipeline.rb'
|
7
|
+
|
8
|
+
include MiGA::SubcladeRunner::Temporal
|
9
|
+
include MiGA::SubcladeRunner::Pipeline
|
5
10
|
end
|
data/utils/subclade/pipeline.rb
CHANGED
@@ -29,7 +29,10 @@ module MiGA::SubcladeRunner::Pipeline
|
|
29
29
|
ofh.close
|
30
30
|
# Cluster genomes
|
31
31
|
if File.size? abc_path
|
32
|
-
|
32
|
+
run_cmd([
|
33
|
+
'ogs.mcl.rb',
|
34
|
+
'-o', "#{ogs_file}.tmp", '--abc', abc_path, '-t', opts[:thr]
|
35
|
+
])
|
33
36
|
File.open(ogs_file, 'w') do |fh|
|
34
37
|
File.foreach("#{ogs_file}.tmp").with_index do |ln, lno|
|
35
38
|
fh.puts(ln) if lno > 0
|
@@ -45,8 +48,10 @@ module MiGA::SubcladeRunner::Pipeline
|
|
45
48
|
# Find genomospecies medoids
|
46
49
|
src = File.expand_path('utils/find-medoid.R', MiGA::MiGA.root_path)
|
47
50
|
dir = opts[:gsp_metric] == 'aai' ? '02.aai' : '03.ani'
|
48
|
-
|
49
|
-
|
51
|
+
run_cmd([
|
52
|
+
'Rscript', src, "../../09.distances/#{dir}/miga-project.rds",
|
53
|
+
'miga-project.gsp-medoids', 'miga-project.gsp-clades'
|
54
|
+
])
|
50
55
|
if File.exist? 'miga-project.gsp-clades.sorted'
|
51
56
|
File.rename 'miga-project.gsp-clades.sorted', 'miga-project.gsp-clades'
|
52
57
|
end
|
@@ -62,13 +67,15 @@ module MiGA::SubcladeRunner::Pipeline
|
|
62
67
|
ofh.close
|
63
68
|
end
|
64
69
|
|
65
|
-
def subclades
|
70
|
+
def subclades(metric)
|
66
71
|
src = File.expand_path('utils/subclades.R', MiGA::MiGA.root_path)
|
67
72
|
step = :"#{metric}_distances"
|
68
73
|
metric_res = project.result(step) or raise "Incomplete step #{step}"
|
69
74
|
matrix = metric_res.file_path(:matrix)
|
70
|
-
|
71
|
-
miga-project
|
75
|
+
run_cmd([
|
76
|
+
'Rscript', src, matrix, 'miga-project', opts[:thr],
|
77
|
+
'miga-project.gsp-medoids', opts[:run_clades] ? 'cluster' : 'empty'
|
78
|
+
])
|
72
79
|
if File.exist? 'miga-project.nwk'
|
73
80
|
File.rename('miga-project.nwk', "miga-project.#{metric}.nwk")
|
74
81
|
end
|
@@ -76,6 +83,10 @@ module MiGA::SubcladeRunner::Pipeline
|
|
76
83
|
|
77
84
|
def compile
|
78
85
|
src = File.expand_path('utils/subclades-compile.rb', MiGA::MiGA.root_path)
|
79
|
-
|
86
|
+
run_cmd(['ruby', src, '.', 'miga-project.class'])
|
87
|
+
end
|
88
|
+
|
89
|
+
def run_cmd(cmd)
|
90
|
+
MiGA::MiGA.run_cmd(cmd, show_cmd: true, err2out: true)
|
80
91
|
end
|
81
92
|
end
|
data/utils/subclade/runner.rb
CHANGED
@@ -1,12 +1,8 @@
|
|
1
|
+
|
1
2
|
require_relative 'base.rb'
|
2
|
-
require_relative 'temporal.rb'
|
3
|
-
require_relative 'pipeline.rb'
|
4
3
|
|
5
4
|
class MiGA::SubcladeRunner
|
6
|
-
|
7
|
-
include MiGA::SubcladeRunner::Pipeline
|
8
|
-
|
9
|
-
attr_reader :project, :step, :opts, :home, :tmp
|
5
|
+
attr_reader(:project, :step, :opts, :home, :tmp)
|
10
6
|
|
11
7
|
def initialize(project_path, step, opts_hash = {})
|
12
8
|
@opts = opts_hash
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: miga-base
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luis M. Rodriguez-R
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-11
|
11
|
+
date: 2021-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: daemons
|
@@ -176,10 +176,12 @@ files:
|
|
176
176
|
- lib/miga/cli/opt_helper.rb
|
177
177
|
- lib/miga/common.rb
|
178
178
|
- lib/miga/common/base.rb
|
179
|
+
- lib/miga/common/errors.rb
|
179
180
|
- lib/miga/common/format.rb
|
180
181
|
- lib/miga/common/hooks.rb
|
181
182
|
- lib/miga/common/net.rb
|
182
183
|
- lib/miga/common/path.rb
|
184
|
+
- lib/miga/common/system_call.rb
|
183
185
|
- lib/miga/common/with_daemon.rb
|
184
186
|
- lib/miga/common/with_daemon_class.rb
|
185
187
|
- lib/miga/common/with_option.rb
|
@@ -253,6 +255,7 @@ files:
|
|
253
255
|
- test/remote_dataset_test.rb
|
254
256
|
- test/result_stats_test.rb
|
255
257
|
- test/result_test.rb
|
258
|
+
- test/system_call_test.rb
|
256
259
|
- test/tax_dist_test.rb
|
257
260
|
- test/tax_index_test.rb
|
258
261
|
- test/taxonomy_test.rb
|