miga-base 1.1.3.6 → 1.2.1.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/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/ls.rb +35 -16
- data/lib/miga/cli/action/run.rb +21 -9
- data/lib/miga/cli/action/tax_dist.rb +0 -1
- data/lib/miga/cli/base.rb +3 -4
- data/lib/miga/cli/opt_helper.rb +11 -6
- data/lib/miga/common/errors.rb +12 -0
- data/lib/miga/common/format.rb +5 -4
- data/lib/miga/common/system_call.rb +93 -0
- data/lib/miga/common.rb +14 -5
- 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/format_test.rb +21 -0
- data/test/system_call_test.rb +50 -0
- data/utils/distance/base.rb +1 -1
- data/utils/distance/commands.rb +1 -2
- 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: afb7c816474f73c547c7f54982293fe72c24d7829184801ab51fc848adf3d9e3
         | 
| 4 | 
            +
              data.tar.gz: 06d51ebc47e96c28072c8415321014535ea7576d9e6f1c381e3ca62dc880df15
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: a4f5279fdba54ad1f8bcbce86cb84a7643b473b7742686e8e9992f8c4af7c982d5776a5a06775b10df67b61de90c4a32f915b51a17a9b11a223474574e7f8159
         | 
| 7 | 
            +
              data.tar.gz: bcd547a1dc5337fbf036ba8e2df6de6db4c4fb34979afeb30ce6c1a692e76166b5412457fb3cc778e03cb601a192af0c8d33709b2e5d7233508dfdbd1c5156ed
         | 
| @@ -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/ls.rb
    CHANGED
    
    | @@ -1,5 +1,4 @@ | |
| 1 | 
            -
            #  | 
| 2 | 
            -
            # @license Artistic-2.0
         | 
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 3 2 |  | 
| 4 3 | 
             
            require 'miga/cli/action'
         | 
| 5 4 |  | 
| @@ -42,33 +41,53 @@ class MiGA::Cli::Action::Ls < MiGA::Cli::Action | |
| 42 41 | 
             
                    '-s', '--silent',
         | 
| 43 42 | 
             
                    'No output and exit with non-zero status if the dataset list is empty'
         | 
| 44 43 | 
             
                  ) { |v| cli[:silent] = v }
         | 
| 44 | 
            +
                  opt.on(
         | 
| 45 | 
            +
                    '--exec CMD',
         | 
| 46 | 
            +
                    'Command to execute per dataset, with the following token variables:',
         | 
| 47 | 
            +
                    '~ {{dataset}}: Name of the dataset',
         | 
| 48 | 
            +
                    '~ {{project}}: Path to the project'
         | 
| 49 | 
            +
                  ) { |v| cli[:exec] = v }
         | 
| 45 50 | 
             
                end
         | 
| 46 51 | 
             
              end
         | 
| 47 52 |  | 
| 48 53 | 
             
              def perform
         | 
| 49 54 | 
             
                ds = cli.load_and_filter_datasets(cli[:silent])
         | 
| 55 | 
            +
                p  = cli.load_project
         | 
| 50 56 | 
             
                exit(ds.empty? ? 1 : 0) if cli[:silent]
         | 
| 51 | 
            -
             | 
| 57 | 
            +
             | 
| 58 | 
            +
                head = nil
         | 
| 59 | 
            +
                fun  = nil
         | 
| 60 | 
            +
                if cli[:datum]
         | 
| 52 61 | 
             
                  cli[:tabular] = true
         | 
| 53 | 
            -
                   | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
                   | 
| 62 | 
            +
                  head = [nil, nil]
         | 
| 63 | 
            +
                  fun  = proc { |d| [d.name, d.metadata[cli[:datum]]] }
         | 
| 64 | 
            +
                elsif cli[:fields]
         | 
| 65 | 
            +
                  head = [:name] + cli[:fields]
         | 
| 66 | 
            +
                  fun  = proc { |d| [d.name] + cli[:fields].map { |f| d.metadata[f] } }
         | 
| 58 67 | 
             
                elsif cli[:info]
         | 
| 59 | 
            -
                   | 
| 68 | 
            +
                  head = Dataset.INFO_FIELDS
         | 
| 69 | 
            +
                  fun  = proc(&:info)
         | 
| 60 70 | 
             
                elsif cli[:processing]
         | 
| 61 | 
            -
                   | 
| 62 | 
            -
                   | 
| 63 | 
            -
                    [d.name] + d.profile_advance.map { |i|  | 
| 71 | 
            +
                  head = [:name] + MiGA::Dataset.PREPROCESSING_TASKS
         | 
| 72 | 
            +
                  fun  = proc do |d|
         | 
| 73 | 
            +
                    [d.name] + d.profile_advance.map { |i| %w[- done queued][i] }
         | 
| 64 74 | 
             
                  end
         | 
| 65 75 | 
             
                elsif cli[:taskstatus]
         | 
| 66 | 
            -
                   | 
| 67 | 
            -
             | 
| 68 | 
            -
                  end
         | 
| 76 | 
            +
                  head = [:name] + MiGA::Dataset.PREPROCESSING_TASKS
         | 
| 77 | 
            +
                  fun  = proc { |d| [d.name] + d.results_status.values }
         | 
| 69 78 | 
             
                else
         | 
| 70 79 | 
             
                  cli[:tabular] = true
         | 
| 71 | 
            -
                   | 
| 80 | 
            +
                  head = [nil]
         | 
| 81 | 
            +
                  fun  = proc { |d| [d.name] }
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                format_table(ds, head) do |d|
         | 
| 85 | 
            +
                  if cli[:exec]
         | 
| 86 | 
            +
                    MiGA::MiGA.run_cmd(
         | 
| 87 | 
            +
                      cli[:exec].miga_variables(dataset: d.name, project: p.path)
         | 
| 88 | 
            +
                    )
         | 
| 89 | 
            +
                  end
         | 
| 90 | 
            +
                  fun[d]
         | 
| 72 91 | 
             
                end
         | 
| 73 92 | 
             
              end
         | 
| 74 93 |  | 
    
        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/base.rb
    CHANGED
    
    | @@ -1,5 +1,4 @@ | |
| 1 | 
            -
            #  | 
| 2 | 
            -
            # @license Artistic-2.0
         | 
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 3 2 |  | 
| 4 3 | 
             
            module MiGA::Cli::Base
         | 
| 5 4 | 
             
              @@TASK_DESC = {
         | 
| @@ -20,10 +19,10 @@ module MiGA::Cli::Base | |
| 20 19 | 
             
                add: 'Create a dataset in a MiGA project',
         | 
| 21 20 | 
             
                get: 'Download a dataset from public databases into a MiGA project',
         | 
| 22 21 | 
             
                ncbi_get: 'Download all genomes in a taxon from NCBI into a MiGA project',
         | 
| 23 | 
            -
                rm: 'Remove a dataset from  | 
| 22 | 
            +
                rm: 'Remove a dataset from a MiGA project',
         | 
| 24 23 | 
             
                find: 'Find unregistered datasets based on result files',
         | 
| 25 24 | 
             
                ln: 'Link datasets (including results) from one project to another',
         | 
| 26 | 
            -
                ls: 'List all registered datasets in  | 
| 25 | 
            +
                ls: 'List all registered datasets in a MiGA project',
         | 
| 27 26 | 
             
                archive: 'Generate a tar-ball with all files from select datasets',
         | 
| 28 27 | 
             
                # Results
         | 
| 29 28 | 
             
                add_result: 'Register a result',
         | 
    
        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
    
    | @@ -1,5 +1,6 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            require 'tempfile'
         | 
| 2 | 
            -
            require 'zlib'
         | 
| 3 4 |  | 
| 4 5 | 
             
            ##
         | 
| 5 6 | 
             
            # General formatting functions shared throughout MiGA.
         | 
| @@ -38,13 +39,13 @@ module MiGA::Common::Format | |
| 38 39 | 
             
                    tmp_path = tmp_fh.path
         | 
| 39 40 | 
             
                    fh = File.open(file, 'r')
         | 
| 40 41 | 
             
                  end
         | 
| 41 | 
            -
                  buffer = ''
         | 
| 42 | 
            +
                  buffer = ''.dup
         | 
| 42 43 | 
             
                  fh.each_line do |ln|
         | 
| 43 44 | 
             
                    ln.chomp!
         | 
| 44 45 | 
             
                    if ln =~ /^>\s*(\S+)(.*)/
         | 
| 45 46 | 
             
                      id, df = $1, $2
         | 
| 46 47 | 
             
                      tmp_fh.print buffer.wrap_width(80)
         | 
| 47 | 
            -
                      buffer = ''
         | 
| 48 | 
            +
                      buffer = ''.dup
         | 
| 48 49 | 
             
                      tmp_fh.puts ">#{id.gsub(/[^A-Za-z0-9_\|\.]/, '_')}#{df}"
         | 
| 49 50 | 
             
                    else
         | 
| 50 51 | 
             
                      buffer << ln.gsub(/[^A-Za-z\.\-]/, '')
         | 
| @@ -166,7 +167,7 @@ class String | |
| 166 167 | 
             
              ##
         | 
| 167 168 | 
             
              # Replace {{variables}} using the +vars+ hash
         | 
| 168 169 | 
             
              def miga_variables(vars)
         | 
| 169 | 
            -
                o =  | 
| 170 | 
            +
                o = self.dup
         | 
| 170 171 | 
             
                vars.each { |k, v| o.gsub!("{{#{k}}}", v.to_s) }
         | 
| 171 172 | 
             
                o
         | 
| 172 173 | 
             
              end
         | 
| @@ -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,16 @@ | |
| 1 | 
            -
            #  | 
| 2 | 
            -
            # @license Artistic-2.0
         | 
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 3 2 |  | 
| 3 | 
            +
            require 'zlib'
         | 
| 4 | 
            +
            require 'stringio'
         | 
| 4 5 | 
             
            require 'miga/version'
         | 
| 5 6 | 
             
            require 'miga/json'
         | 
| 6 7 | 
             
            require 'miga/parallel'
         | 
| 7 8 | 
             
            require 'miga/common/base'
         | 
| 9 | 
            +
            require 'miga/common/errors'
         | 
| 8 10 | 
             
            require 'miga/common/path'
         | 
| 9 11 | 
             
            require 'miga/common/format'
         | 
| 10 12 | 
             
            require 'miga/common/net'
         | 
| 11 | 
            -
            require ' | 
| 13 | 
            +
            require 'miga/common/system_call'
         | 
| 12 14 |  | 
| 13 15 | 
             
            ##
         | 
| 14 16 | 
             
            # Generic class used to handle system-wide information and methods, and parent
         | 
| @@ -19,14 +21,21 @@ class MiGA::MiGA | |
| 19 21 | 
             
              extend MiGA::Common::Path
         | 
| 20 22 | 
             
              extend MiGA::Common::Format
         | 
| 21 23 | 
             
              extend MiGA::Common::Net
         | 
| 24 | 
            +
              extend MiGA::Common::SystemCall
         | 
| 22 25 |  | 
| 23 26 | 
             
              ENV['MIGA_HOME'] ||= ENV['HOME']
         | 
| 24 27 |  | 
| 28 | 
            +
              ##
         | 
| 29 | 
            +
              # Path to the +.miga_rc+ file
         | 
| 30 | 
            +
              def self.rc_path
         | 
| 31 | 
            +
                File.join(ENV['MIGA_HOME'], '.miga_rc')
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 25 34 | 
             
              ##
         | 
| 26 35 | 
             
              # Has MiGA been initialized?
         | 
| 27 36 | 
             
              def self.initialized?
         | 
| 28 | 
            -
                File.exist?( | 
| 29 | 
            -
                  File.exist?(File. | 
| 37 | 
            +
                File.exist?(rc_path) &&
         | 
| 38 | 
            +
                  File.exist?(File.join(ENV['MIGA_HOME'], '.miga_daemon.json'))
         | 
| 30 39 | 
             
              end
         | 
| 31 40 |  | 
| 32 41 | 
             
              ##
         | 
    
        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, 1, 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,  | 
| 23 | 
            +
              VERSION_DATE = Date.new(2021, 12, 12)
         | 
| 24 24 |  | 
| 25 25 | 
             
              ##
         | 
| 26 26 | 
             
              # References of MiGA
         | 
    
        data/test/format_test.rb
    CHANGED
    
    | @@ -58,6 +58,9 @@ class FormatTest < Test::Unit::TestCase | |
| 58 58 | 
             
                assert_equal(50.0, o[:gc])
         | 
| 59 59 | 
             
                assert_equal(5, o[:n50])
         | 
| 60 60 | 
             
                assert_equal(4.0, o[:med])
         | 
| 61 | 
            +
                o = MiGA::MiGA.seqs_length(f, :fasta, skew: true)
         | 
| 62 | 
            +
                assert_equal(-50.0, o[:at_skew])
         | 
| 63 | 
            +
                assert_equal(-25.0, o[:gc_skew])
         | 
| 61 64 | 
             
              end
         | 
| 62 65 |  | 
| 63 66 | 
             
              def test_seqs_length_fastq
         | 
| @@ -77,4 +80,22 @@ class FormatTest < Test::Unit::TestCase | |
| 77 80 | 
             
                assert_equal('123  45', tab[2])
         | 
| 78 81 | 
             
                assert_equal('678  90', tab[3])
         | 
| 79 82 | 
             
              end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
              def test_miga_name
         | 
| 85 | 
            +
                assert_not('a-bad-name'.miga_name?)
         | 
| 86 | 
            +
                assert('a_good_one'.miga_name?)
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                assert('After_it_s_fixed_', 'After it\'s fixed!'.miga_name)
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                assert('A sp.', 'A_sp_'.unmiga_name)
         | 
| 91 | 
            +
                assert('B str. C', 'B_sp_C'.unmiga_name)
         | 
| 92 | 
            +
                assert('The X content', 'The_x_content'.unmiga_name)
         | 
| 93 | 
            +
              end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
              def test_miga_variables
         | 
| 96 | 
            +
                assert_equal(
         | 
| 97 | 
            +
                  '1 a box!',
         | 
| 98 | 
            +
                  '{{n}} {{my}} {{secret}}!'.miga_variables(my: 'a', secret: :box, n: 1)
         | 
| 99 | 
            +
                )
         | 
| 100 | 
            +
              end
         | 
| 80 101 | 
             
            end
         | 
| @@ -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
    
    
    
        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.1. | 
| 4 | 
            +
              version: 1.2.1.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- | 
| 11 | 
            +
            date: 2021-12-12 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
         |