miga-base 1.1.4.0 → 1.2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bb03f8cf2e7a3ebd138b0a4b4fcb393093ee18317a89d168f27c1e2f4ac687cd
4
- data.tar.gz: ca50166c33ae2a93e32e5f44f570e1d3b3cacd0ce7361d4e58b9ba9cefbc0dfa
3
+ metadata.gz: 5dd4ba6aa9570bedd4454451caf47fee3fe4d73a7e951bcf599af38ab59e1342
4
+ data.tar.gz: a39c566d1d00000ae288bd2fd08017236af5537cbde7f2d39e91168aa7561748
5
5
  SHA512:
6
- metadata.gz: f95b279c12c9e4735a7507795698fed578c28b904cb867caadebcd9f3ea0ba4592ef7d8763425cf0d6d1806f6afc1801ffa2b0db8341498c5e4c8d1ca2689214
7
- data.tar.gz: f54a2e738c2ae885bda629d216f45d9b139bd64d68e99b95f02ea328a1f0c26138314a621ef63a836391559be703b24b78d2f83dadf496c94bc5f61a78e1abe7
6
+ metadata.gz: da9bc73396a64deef4913947cd0beb2044d27488cddc63f452f9815f9e02ae71d8dce7f8537901a3a10c8d42fae2a595bf8ffa2d6236c6f415411008f420b7c0
7
+ data.tar.gz: 315d4662e61457980273fc62f4761d0d16baaf927ed85eeb9af4e647045159cdb7b4534ee30b059e53ad6d5e2fa77fc6a91c8c5bbb5a97f11af72c9f3705aa93
@@ -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')
@@ -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.expand_path('genomospecies.tsv', cli[:outdir]), 'w') do |fh|
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.expand_path('representatives', cli[:outdir])
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.expand_path('representatives.txt', cli[:outdir])
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.expand_path('utils/representatives.rb', MiGA::MiGA.root_path)
99
- `ruby '#{src}' '#{p.path}' | cut -f 2 > '#{f}'`
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
- cmdo = `gzip -9 '#{file}'`.chomp
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
- cmdo = `cd '#{dir}' && tar -zcf proteins.tar.gz *.faa && rm *.faa`.chomp
271
- warn(cmdo) unless cmdo.empty?
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
- cmdo = `cd '#{dir}/..' \
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'`.chomp
298
- warn(cmdo) unless cmdo.empty?
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
- `cd "#{cli[:local]}" && tar -zxf "#{file}" && rm "#{file}"`
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
- `cd '#{miga_db}' && tar zxf '#{arch}' && rm '#{arch}'`
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
@@ -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
- `. "#{cli[:config]}" && #{cmd}`
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 2>&1"
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, "which #{exec.shellescape}"))
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
- case language
212
- when :r
213
- run_r_cmd(cli, paths, "library('#{pkg}')")
214
- when :ruby
215
- x = "#{paths['ruby'].shellescape} -r #{pkg.shellescape} -e '' 2>/dev/null"
216
- run_cmd(cli, x)
217
- when :python
218
- x = "#{paths['python3'].shellescape} -c 'import #{pkg}' 2>/dev/null"
219
- run_cmd(cli, x)
220
- else
221
- raise "Unrecognized language: #{language}"
222
- end
223
- $?.success?
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
- gem_cmd = "Gem::GemRunner.new.run %w(install --user #{pkg})"
236
- x = "#{paths['ruby'].shellescape} -r rubygems -r rubygems/gem_runner \
237
- -e #{gem_cmd.shellescape} 2>&1"
238
- run_cmd(cli, x)
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 = "#{paths['python3'].shellescape} \
241
- -m pip install --user #{pkg.shellescape} 2>&1"
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
@@ -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
- cmd = ["PROJECT=#{p.path.shellescape}",
58
- "RUNTYPE=#{cli[:remote] ? 'ssh' : 'bash'}",
59
- "MIGA=#{miga.shellescape}", "CORES=#{cli[:thr]}"]
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 = ['ssh', '-t', '-t', cli[:remote].shellescape,
71
- cmd.join(' ').shellescape]
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
- pid = spawn cmd.join(' ')
77
- Process.wait pid
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
@@ -3,7 +3,6 @@
3
3
 
4
4
  require 'miga/cli/action'
5
5
  require 'miga/tax_index'
6
- require 'zlib'
7
6
  require 'tmpdir'
8
7
 
9
8
  class MiGA::Cli::Action::TaxDist < MiGA::Cli::Action
@@ -26,6 +26,10 @@ module MiGA::Cli::OptHelper
26
26
  'Accept all defaults as answers'
27
27
  ) { |v| self[:auto] = v }
28
28
  end
29
+ opt.on(
30
+ '--rand-seed INT', Integer,
31
+ 'Set this seed to initialize pseudo-randomness'
32
+ ) { |v| srand(v) }
29
33
  opt.on(
30
34
  '-v', '--verbose',
31
35
  'Print additional information to STDERR'
@@ -0,0 +1,12 @@
1
+
2
+ module MiGA
3
+ ##
4
+ # A generic MiGA error
5
+ class Error < RuntimeError
6
+ end
7
+
8
+ ##
9
+ # An error with a system call
10
+ class SystemCallError < Error
11
+ end
12
+ end
@@ -1,5 +1,4 @@
1
1
  require 'tempfile'
2
- require 'zlib'
3
2
 
4
3
  ##
5
4
  # General formatting functions shared throughout MiGA.
@@ -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 'stringio'
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?(File.expand_path('.miga_rc', ENV['MIGA_HOME'])) &&
29
- File.exist?(File.expand_path('.miga_daemon.json', ENV['MIGA_HOME']))
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
- `#{runopts(:alive).miga_variables(pid: job[:pid])}`.chomp.to_i == 1
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] = `#{job[:cmd]}`.chomp
351
+ job[:pid] = MiGA::MiGA.run_cmd(job[:cmd], return: :output).chomp
350
352
  end
351
353
 
352
354
  # Check if registered
@@ -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 = "#{MiGA::MiGA.root_path}/utils/domain-ess-genes.rb"
200
+ scr = File.join(MiGA::MiGA.root_path, 'utils', 'domain-ess-genes.rb')
202
201
  rep = file_path(:report)
203
- rc_p = File.expand_path('.miga_rc', ENV['HOME'])
204
- rc = File.exist?(rc_p) ? ". '#{rc_p}' && " : ''
205
- $stderr.print `#{rc} ruby '#{scr}' \
206
- '#{rep}' '#{rep}.domain' '#{tax[:d][0]}'`
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
@@ -3,7 +3,6 @@
3
3
 
4
4
  require 'miga/common'
5
5
  require 'miga/taxonomy'
6
- require 'zlib'
7
6
 
8
7
  ##
9
8
  # Methods for taxonomy identification based on AAI/ANI values.
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.1, 4, 0].freeze
15
+ VERSION = [1.2, 0, 0].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, 12, 7)
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
@@ -1,7 +1,7 @@
1
1
  require 'miga'
2
2
  require 'miga/tax_dist'
3
3
 
4
- class MiGA::DistanceRunner
4
+ class MiGA::DistanceRunner < MiGA::MiGA
5
5
  require_relative 'temporal.rb'
6
6
  require_relative 'database.rb'
7
7
  require_relative 'commands.rb'
@@ -227,7 +227,6 @@ module MiGA::DistanceRunner::Commands
227
227
  end
228
228
 
229
229
  def run_cmd(cmd)
230
- puts "CMD: #{cmd}"
231
- puts `#{cmd} 2>&1`
230
+ MiGA::MiGA.run_cmd(cmd, show_cmd: true, err2out: true)
232
231
  end
233
232
  end
@@ -58,9 +58,9 @@ module MiGA::DistanceRunner::Pipeline
58
58
  end
59
59
  end
60
60
  ds_matrix_fh.close
61
- ref_tree = File.expand_path('utils/ref-tree.R', MiGA::MiGA.root_path)
62
- `"#{ref_tree}" "#{ds_matrix}" "#{out_base}" "#{dataset.name}"`
63
- File.unlink ds_matrix
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
@@ -44,7 +44,7 @@ find_medoids <- function (ani.df, out, clades) {
44
44
  }
45
45
 
46
46
  #= Main
47
- cat("Finding Medoids")
47
+ cat("Finding Medoids\n")
48
48
  ani <- readRDS(argv[1])
49
49
  find_medoids(ani.df = ani, out = argv[2], clades = argv[3])
50
50
 
@@ -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
@@ -29,7 +29,10 @@ module MiGA::SubcladeRunner::Pipeline
29
29
  ofh.close
30
30
  # Cluster genomes
31
31
  if File.size? abc_path
32
- `ogs.mcl.rb -o '#{ogs_file}.tmp' --abc '#{abc_path}' -t '#{opts[:thr]}'`
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
- `Rscript '#{src}' '../../09.distances/#{dir}/miga-project.rds' \
49
- miga-project.gsp-medoids miga-project.gsp-clades`
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 metric
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
- `Rscript '#{src}' '#{matrix}' miga-project '#{opts[:thr]}' \
71
- miga-project.gsp-medoids '#{opts[:run_clades] ? 'cluster' : 'empty'}'`
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
- `ruby '#{src}' '.' 'miga-project.class'`
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
@@ -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
- include MiGA::SubcladeRunner::Temporal
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.1.4.0
4
+ version: 1.2.0.0
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-12-07 00:00:00.000000000 Z
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