miga-base 0.6.1.0 → 0.6.2.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/daemon.rb +2 -3
- data/lib/miga/daemon.rb +68 -77
- data/lib/miga/dataset/result.rb +253 -212
- data/lib/miga/project/dataset.rb +1 -1
- data/lib/miga/version.rb +2 -2
- data/test/common_test.rb +0 -8
- data/test/daemon_test.rb +199 -17
- data/test/format_test.rb +88 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c317237c4cd2f049b56af6021272208c206f1810052dde4b1b5b41394f37139
|
4
|
+
data.tar.gz: '066558242d9bcc1a96f166349815398296cdb976190853a18ca52bdafe84c263'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50b395740f68543e7aa79bf0e3631cb86248fffbcd9aac942e2d30681579a42e528d552638701f153605f68ea9da389762b6d068455e9b67cbfd9b66cde879c0
|
7
|
+
data.tar.gz: d20fd84e71bd4d7a8ebf5ff1060e12096d78477b662098e013b88ea9a19e54b4665a71bbfa0e49fd57df47a61b3a0780ed469fcb004b1384dd4e4f2304320666
|
@@ -74,9 +74,8 @@ class MiGA::Cli::Action::Daemon < MiGA::Cli::Action
|
|
74
74
|
def perform
|
75
75
|
p = cli.load_project
|
76
76
|
d = MiGA::Daemon.new(p, cli[:json])
|
77
|
-
[
|
78
|
-
|
79
|
-
end
|
77
|
+
dopts = %i[latency maxjobs nodelist ppn shutdown_when_done]
|
78
|
+
dopts.each { |k| d.runopts(k, cli[k]) }
|
80
79
|
d.daemon(cli.operation, cli[:daemon_opts])
|
81
80
|
end
|
82
81
|
end
|
data/lib/miga/daemon.rb
CHANGED
@@ -22,15 +22,15 @@ class MiGA::Daemon < MiGA::MiGA
|
|
22
22
|
# Array of all spawned daemons.
|
23
23
|
$_MIGA_DAEMON_LAIR = []
|
24
24
|
|
25
|
-
# MiGA::Project in which the daemon is running
|
25
|
+
# MiGA::Project in which the daemon is running
|
26
26
|
attr_reader :project
|
27
|
-
# Options used to setup the daemon
|
27
|
+
# Options used to setup the daemon
|
28
28
|
attr_reader :options
|
29
|
-
# Array of jobs next to be executed
|
29
|
+
# Array of jobs next to be executed
|
30
30
|
attr_reader :jobs_to_run
|
31
|
-
# Array of jobs currently running
|
31
|
+
# Array of jobs currently running
|
32
32
|
attr_reader :jobs_running
|
33
|
-
# Integer indicating the current iteration
|
33
|
+
# Integer indicating the current iteration
|
34
34
|
attr_reader :loop_i
|
35
35
|
|
36
36
|
##
|
@@ -47,7 +47,7 @@ class MiGA::Daemon < MiGA::MiGA
|
|
47
47
|
MiGA::Json.parse(
|
48
48
|
json, default: File.expand_path('.miga_daemon.json', ENV['MIGA_HOME'])
|
49
49
|
).each { |k,v| runopts(k, v) }
|
50
|
-
update_format_0
|
50
|
+
update_format_0
|
51
51
|
@jobs_to_run = []
|
52
52
|
@jobs_running = []
|
53
53
|
@loop_i = -1
|
@@ -68,21 +68,22 @@ class MiGA::Daemon < MiGA::MiGA
|
|
68
68
|
end
|
69
69
|
|
70
70
|
##
|
71
|
-
# Launches the +task+ with options +opts+ (as command-line arguments)
|
72
|
-
#
|
73
|
-
|
71
|
+
# Launches the +task+ with options +opts+ (as command-line arguments) and
|
72
|
+
# returns the process ID as an Integer. If +wait+ it waits for the process to
|
73
|
+
# complete, immediately returns otherwise.
|
74
|
+
# Supported tasks: start, stop, restart, status.
|
75
|
+
def daemon(task, opts = [], wait = true)
|
74
76
|
MiGA.DEBUG "Daemon.daemon #{task} #{opts}"
|
75
77
|
options = default_options
|
76
|
-
opts.unshift(task)
|
78
|
+
opts.unshift(task.to_s)
|
77
79
|
options[:ARGV] = opts
|
78
80
|
# This additional degree of separation below was introduced so the Daemons
|
79
81
|
# package doesn't kill the parent process in workflows.
|
80
82
|
pid = fork do
|
81
|
-
Daemons.run_proc("MiGA:#{project.name}", options)
|
82
|
-
loop { break unless in_loop }
|
83
|
-
end
|
83
|
+
Daemons.run_proc("MiGA:#{project.name}", options) { while in_loop; end }
|
84
84
|
end
|
85
|
-
Process.wait
|
85
|
+
Process.wait(pid) if wait
|
86
|
+
pid
|
86
87
|
end
|
87
88
|
|
88
89
|
##
|
@@ -130,13 +131,8 @@ class MiGA::Daemon < MiGA::MiGA
|
|
130
131
|
# Traverse datasets
|
131
132
|
def check_datasets
|
132
133
|
project.each_dataset do |n, ds|
|
133
|
-
|
134
|
-
|
135
|
-
project.load
|
136
|
-
else
|
137
|
-
to_run = ds.next_preprocessing(false)
|
138
|
-
queue_job(:d, ds) unless to_run.nil?
|
139
|
-
end
|
134
|
+
to_run = ds.next_preprocessing(false)
|
135
|
+
queue_job(:d, ds) unless to_run.nil?
|
140
136
|
end
|
141
137
|
end
|
142
138
|
|
@@ -202,9 +198,9 @@ class MiGA::Daemon < MiGA::MiGA
|
|
202
198
|
@jobs_running.select! do |job|
|
203
199
|
ongoing = case job[:job].to_s
|
204
200
|
when 'd'
|
205
|
-
|
201
|
+
!job[:ds].next_preprocessing(false).nil?
|
206
202
|
when 'p'
|
207
|
-
|
203
|
+
!project.next_task(nil, false).nil?
|
208
204
|
else
|
209
205
|
(job[:ds].nil? ? project : job[:ds]).add_result(job[:job], false).nil?
|
210
206
|
end
|
@@ -221,16 +217,13 @@ class MiGA::Daemon < MiGA::MiGA
|
|
221
217
|
end
|
222
218
|
|
223
219
|
##
|
224
|
-
#
|
225
|
-
#
|
220
|
+
# In SSH daemons, retrieve the host index of an available node, nil if none.
|
221
|
+
# In any other daemons, returns true as long as #maxjobs is not reached
|
226
222
|
def next_host
|
227
|
-
if
|
228
|
-
return jobs_running.size < maxjobs
|
229
|
-
end
|
223
|
+
return jobs_running.size < maxjobs if runopts(:type) != 'ssh'
|
230
224
|
allk = (0 .. nodelist.size-1).to_a
|
231
225
|
busyk = jobs_running.map { |k| k[:hostk] }
|
232
|
-
|
233
|
-
availk.empty? ? nil : availk.first
|
226
|
+
(allk - busyk).first
|
234
227
|
end
|
235
228
|
|
236
229
|
##
|
@@ -248,7 +241,7 @@ class MiGA::Daemon < MiGA::MiGA
|
|
248
241
|
project.load
|
249
242
|
if loop_i == -1
|
250
243
|
say '-----------------------------------'
|
251
|
-
say 'MiGA:%s launched
|
244
|
+
say 'MiGA:%s launched' % project.name
|
252
245
|
say '-----------------------------------'
|
253
246
|
load_status
|
254
247
|
@loop_i = 0
|
@@ -286,54 +279,52 @@ class MiGA::Daemon < MiGA::MiGA
|
|
286
279
|
File.unlink(f) if File.exist? f
|
287
280
|
end
|
288
281
|
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
282
|
+
##
|
283
|
+
# Launch the job described by Hash +job+ to +hostk+-th host
|
284
|
+
def launch_job(job, hostk = nil)
|
285
|
+
# Execute job
|
286
|
+
case runopts(:type)
|
287
|
+
when 'ssh'
|
288
|
+
# Remote job
|
289
|
+
job[:hostk] = hostk
|
290
|
+
job[:cmd] = job[:cmd].miga_variables(host: nodelist[hostk])
|
291
|
+
job[:pid] = spawn job[:cmd]
|
292
|
+
Process.detach job[:pid] unless [nil, '', 0].include?(job[:pid])
|
293
|
+
when 'bash'
|
294
|
+
# Local job
|
295
|
+
job[:pid] = spawn job[:cmd]
|
296
|
+
Process.detach job[:pid] unless [nil, '', 0].include?(job[:pid])
|
297
|
+
else
|
298
|
+
# Schedule cluster job (qsub, msub, slurm)
|
299
|
+
job[:pid] = `#{job[:cmd]}`.chomp
|
300
|
+
end
|
308
301
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
end
|
302
|
+
# Check if registered
|
303
|
+
if [nil, '', 0].include? job[:pid]
|
304
|
+
job[:pid] = nil
|
305
|
+
@jobs_to_run << job
|
306
|
+
say "Unsuccessful #{job[:task_name]}, rescheduling"
|
307
|
+
else
|
308
|
+
@jobs_running << job
|
309
|
+
say "Spawned pid:#{job[:pid]}#{
|
310
|
+
" to #{job[:hostk]}:#{nodelist[job[:hostk]]}" if job[:hostk]
|
311
|
+
} for #{job[:task_name]}"
|
320
312
|
end
|
313
|
+
end
|
321
314
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
)
|
335
|
-
) unless runopts(k).nil?
|
336
|
-
end
|
337
|
-
runopts(:format_version, 1)
|
315
|
+
##
|
316
|
+
# Update from daemon JSON format 0 to the latest version
|
317
|
+
def update_format_0
|
318
|
+
{
|
319
|
+
cmd: %w[script vars cpus log task_name],
|
320
|
+
var: %w[key value],
|
321
|
+
alive: %w[pid],
|
322
|
+
kill: %w[pid]
|
323
|
+
}.each do |k,v|
|
324
|
+
runopts(
|
325
|
+
k, runopts(k).gsub(/%(\d+\$)?d/, '%\\1s') % v.map{ |i| "{{#{i}}}" }
|
326
|
+
) if !runopts(k).nil? && runopts(k) =~ /%(\d+\$)?[ds]/
|
338
327
|
end
|
328
|
+
runopts(:format_version, 1)
|
329
|
+
end
|
339
330
|
end
|
data/lib/miga/dataset/result.rb
CHANGED
@@ -4,13 +4,12 @@ require 'miga/result'
|
|
4
4
|
require 'miga/dataset/base'
|
5
5
|
|
6
6
|
##
|
7
|
-
# Helper module including specific functions to add dataset results
|
7
|
+
# Helper module including specific functions to add dataset results
|
8
8
|
module MiGA::Dataset::Result
|
9
|
-
|
10
9
|
include MiGA::Dataset::Base
|
11
10
|
|
12
11
|
##
|
13
|
-
# Get the result MiGA::Result in this dataset identified by the symbol +k
|
12
|
+
# Get the result MiGA::Result in this dataset identified by the symbol +k+
|
14
13
|
def result(k)
|
15
14
|
return nil if @@RESULT_DIRS[k.to_sym].nil?
|
16
15
|
MiGA::Result.load(
|
@@ -19,11 +18,13 @@ module MiGA::Dataset::Result
|
|
19
18
|
end
|
20
19
|
|
21
20
|
##
|
22
|
-
# Get all the results (Array of MiGA::Result) in this dataset
|
23
|
-
def results
|
21
|
+
# Get all the results (Array of MiGA::Result) in this dataset
|
22
|
+
def results
|
23
|
+
@@RESULT_DIRS.keys.map { |k| result k }.compact
|
24
|
+
end
|
24
25
|
|
25
26
|
##
|
26
|
-
# For each result executes the 2-ary +blk+ block: key symbol and MiGA::Result
|
27
|
+
# For each result executes the 2-ary +blk+ block: key symbol and MiGA::Result
|
27
28
|
def each_result(&blk)
|
28
29
|
@@RESULT_DIRS.keys.each do |k|
|
29
30
|
blk.call(k, result(k)) unless result(k).nil?
|
@@ -49,8 +50,9 @@ module MiGA::Dataset::Result
|
|
49
50
|
r_pre = MiGA::Result.load("#{base}.json")
|
50
51
|
return r_pre if (r_pre.nil? && !save) || !r_pre.nil?
|
51
52
|
end
|
52
|
-
r = File.exist?("#{base}.done")
|
53
|
-
|
53
|
+
r = if File.exist?("#{base}.done")
|
54
|
+
self.send("add_result_#{result_type}", base, opts)
|
55
|
+
end
|
54
56
|
unless r.nil?
|
55
57
|
r.save
|
56
58
|
pull_hook(:on_result_ready, result_type)
|
@@ -69,7 +71,7 @@ module MiGA::Dataset::Result
|
|
69
71
|
# initial input. Passes +save+ to #add_result.
|
70
72
|
def first_preprocessing(save = false)
|
71
73
|
@first_processing ||= @@PREPROCESSING_TASKS.find do |t|
|
72
|
-
|
74
|
+
!ignore_task?(t) && !add_result(t, save).nil?
|
73
75
|
end
|
74
76
|
end
|
75
77
|
|
@@ -82,22 +84,22 @@ module MiGA::Dataset::Result
|
|
82
84
|
return nil if first.nil?
|
83
85
|
@@PREPROCESSING_TASKS.each do |t|
|
84
86
|
next if ignore_task? t
|
85
|
-
if after_first
|
87
|
+
if after_first && add_result(t, save).nil?
|
86
88
|
if (metadata["_try_#{t}"] || 0) > (project.metadata[:max_try] || 10)
|
87
89
|
inactivate!
|
88
90
|
return nil
|
89
91
|
end
|
90
92
|
return t
|
91
93
|
end
|
92
|
-
after_first = (after_first
|
94
|
+
after_first = (after_first || (t == first))
|
93
95
|
end
|
94
96
|
nil
|
95
97
|
end
|
96
98
|
|
97
99
|
##
|
98
|
-
# Are all the dataset-specific tasks done? Passes +save+ to #add_result
|
100
|
+
# Are all the dataset-specific tasks done? Passes +save+ to #add_result
|
99
101
|
def done_preprocessing?(save = false)
|
100
|
-
!first_preprocessing(save).nil?
|
102
|
+
!first_preprocessing(save).nil? && next_preprocessing(save).nil?
|
101
103
|
end
|
102
104
|
|
103
105
|
##
|
@@ -114,8 +116,8 @@ module MiGA::Dataset::Result
|
|
114
116
|
state = 0
|
115
117
|
next_task = next_preprocessing(save)
|
116
118
|
@@PREPROCESSING_TASKS.each do |task|
|
117
|
-
state = 1 if first_task==task
|
118
|
-
state = 2 if !next_task.nil?
|
119
|
+
state = 1 if first_task == task
|
120
|
+
state = 2 if !next_task.nil? && next_task == task
|
119
121
|
adv << state
|
120
122
|
end
|
121
123
|
adv
|
@@ -144,23 +146,23 @@ module MiGA::Dataset::Result
|
|
144
146
|
def result_status(task)
|
145
147
|
if first_preprocessing.nil?
|
146
148
|
:ignore_empty
|
147
|
-
elsif
|
149
|
+
elsif !get_result(task).nil?
|
148
150
|
:complete
|
149
151
|
elsif @@PREPROCESSING_TASKS.index(task) <
|
150
|
-
|
152
|
+
@@PREPROCESSING_TASKS.index(first_preprocessing)
|
151
153
|
:-
|
152
154
|
elsif ignore_task?(task)
|
153
|
-
if
|
155
|
+
if !is_active?
|
154
156
|
:ignore_inactive
|
155
157
|
elsif metadata["run_#{task}"]
|
156
158
|
:ignore_force
|
157
|
-
elsif task == :taxonomy
|
159
|
+
elsif task == :taxonomy && project.metadata[:ref_project].nil?
|
158
160
|
:ignore_project
|
159
|
-
elsif @@_EXCLUDE_NOREF_TASKS_H[task] && !
|
161
|
+
elsif @@_EXCLUDE_NOREF_TASKS_H[task] && !is_ref?
|
160
162
|
:ignore_noref
|
161
|
-
elsif @@_ONLY_MULTI_TASKS_H[task] && !
|
163
|
+
elsif @@_ONLY_MULTI_TASKS_H[task] && !is_multi?
|
162
164
|
:ignore_multi
|
163
|
-
elsif @@_ONLY_NONMULTI_TASKS_H[task] && !
|
165
|
+
elsif @@_ONLY_NONMULTI_TASKS_H[task] && !is_nonmulti?
|
164
166
|
:ignore_nonmulti
|
165
167
|
else
|
166
168
|
:ignore
|
@@ -169,7 +171,7 @@ module MiGA::Dataset::Result
|
|
169
171
|
:pending
|
170
172
|
end
|
171
173
|
end
|
172
|
-
|
174
|
+
|
173
175
|
##
|
174
176
|
# Clean-up all the stored distances, removing values for datasets no longer in
|
175
177
|
# the project as reference datasets.
|
@@ -179,7 +181,7 @@ module MiGA::Dataset::Result
|
|
179
181
|
return if r.nil?
|
180
182
|
[:haai_db, :aai_db, :ani_db].each do |db_type|
|
181
183
|
db = r.file_path(db_type)
|
182
|
-
next if db.nil?
|
184
|
+
next if db.nil? || !File.size?(db)
|
183
185
|
sqlite_db = SQLite3::Database.new db
|
184
186
|
table = db_type[-6..-4]
|
185
187
|
val = sqlite_db.execute "select seq2 from #{table}"
|
@@ -192,220 +194,259 @@ module MiGA::Dataset::Result
|
|
192
194
|
|
193
195
|
private
|
194
196
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
end
|
205
|
-
|
206
|
-
##
|
207
|
-
# Add result type +:trimmed_reads+ at +base+ (no +_opts+ supported).
|
208
|
-
def add_result_trimmed_reads(base, _opts)
|
209
|
-
return nil unless result_files_exist?(base, ".1.clipped.fastq")
|
210
|
-
r = MiGA::Result.new("#{base}.json")
|
211
|
-
if result_files_exist?(base, ".2.clipped.fastq")
|
212
|
-
r = add_files_to_ds_result(r, name,
|
213
|
-
pair1: ".1.clipped.fastq", pair2: ".2.clipped.fastq",
|
214
|
-
single: ".1.clipped.single.fastq")
|
197
|
+
##
|
198
|
+
# Add result type +:raw_reads+ at +base+ (no +_opts+ supported)
|
199
|
+
def add_result_raw_reads(base, _opts)
|
200
|
+
return nil unless result_files_exist?(base, '.1.fastq')
|
201
|
+
r = MiGA::Result.new("#{base}.json")
|
202
|
+
add_files_to_ds_result(
|
203
|
+
r, name,
|
204
|
+
if result_files_exist?(base, '.2.fastq')
|
205
|
+
{ pair1: '.1.fastq', pair2: '.2.fastq' }
|
215
206
|
else
|
216
|
-
|
207
|
+
{ single: '.1.fastq' }
|
217
208
|
end
|
218
|
-
|
219
|
-
|
220
|
-
end
|
209
|
+
)
|
210
|
+
end
|
221
211
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
212
|
+
##
|
213
|
+
# Add result type +:trimmed_reads+ at +base+ (no +_opts+ supported)
|
214
|
+
def add_result_trimmed_reads(base, _opts)
|
215
|
+
return nil unless result_files_exist?(base, '.1.clipped.fastq')
|
216
|
+
r = MiGA::Result.new("#{base}.json")
|
217
|
+
if result_files_exist?(base, '.2.clipped.fastq')
|
218
|
+
r = add_files_to_ds_result(r, name,
|
219
|
+
pair1: '.1.clipped.fastq',
|
220
|
+
pair2: '.2.clipped.fastq',
|
221
|
+
single: '.1.clipped.single.fastq')
|
222
|
+
else
|
223
|
+
r = add_files_to_ds_result(r, name, single: '.1.clipped.fastq')
|
229
224
|
end
|
225
|
+
r.add_file(:trimming_sumary, "#{name}.1.fastq.trimmed.summary.txt")
|
226
|
+
r
|
227
|
+
end
|
230
228
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
r = MiGA::Result.new("#{base}.json")
|
239
|
-
add_files_to_ds_result(r, name, coupled: ".CoupledReads.fa",
|
240
|
-
single: ".SingleReads.fa", pair1: ".1.fasta", pair2: ".2.fasta")
|
241
|
-
end
|
229
|
+
##
|
230
|
+
# Add result type +:read_quality+ at +base+ (no +_opts+ supported)
|
231
|
+
def add_result_read_quality(base, _opts)
|
232
|
+
return nil unless result_files_exist?(base, %w[.solexaqa .fastqc])
|
233
|
+
r = MiGA::Result.new("#{base}.json")
|
234
|
+
add_files_to_ds_result(r, name, solexaqa: '.solexaqa', fastqc: '.fastqc')
|
235
|
+
end
|
242
236
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
r
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
end
|
237
|
+
##
|
238
|
+
# Add result type +:trimmed_fasta+ at +base+ (no +_opts+ supported)
|
239
|
+
def add_result_trimmed_fasta(base, _opts)
|
240
|
+
return nil unless
|
241
|
+
result_files_exist?(base, '.CoupledReads.fa') ||
|
242
|
+
result_files_exist?(base, '.SingleReads.fa') ||
|
243
|
+
result_files_exist?(base, %w[.1.fasta .2.fasta])
|
244
|
+
r = MiGA::Result.new("#{base}.json")
|
245
|
+
add_files_to_ds_result(
|
246
|
+
r, name,
|
247
|
+
coupled: '.CoupledReads.fa',
|
248
|
+
single: '.SingleReads.fa',
|
249
|
+
pair1: '.1.fasta',
|
250
|
+
pair2: '.2.fasta')
|
251
|
+
end
|
259
252
|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
r
|
253
|
+
##
|
254
|
+
# Add result type +:assembly+ at +base+. Hash +opts+ supports
|
255
|
+
# +is_clean: Boolean+.
|
256
|
+
def add_result_assembly(base, opts)
|
257
|
+
return nil unless result_files_exist?(base, '.LargeContigs.fna')
|
258
|
+
r = MiGA::Result.new("#{base}.json")
|
259
|
+
r = add_files_to_ds_result(
|
260
|
+
r, name,
|
261
|
+
largecontigs: '.LargeContigs.fna',
|
262
|
+
allcontigs: '.AllContigs.fna',
|
263
|
+
assembly_data: '')
|
264
|
+
opts[:is_clean] ||= false
|
265
|
+
r.clean! if opts[:is_clean]
|
266
|
+
unless r.clean?
|
267
|
+
MiGA::MiGA.clean_fasta_file(r.file_path(:largecontigs))
|
268
|
+
r.clean!
|
275
269
|
end
|
270
|
+
r
|
271
|
+
end
|
276
272
|
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
273
|
+
##
|
274
|
+
# Add result type +:cds+ at +base+. Hash +opts+ supports +is_clean: Boolean+
|
275
|
+
def add_result_cds(base, opts)
|
276
|
+
return nil unless result_files_exist?(base, %w[.faa])
|
277
|
+
r = MiGA::Result.new("#{base}.json")
|
278
|
+
r = add_files_to_ds_result(
|
279
|
+
r, name,
|
280
|
+
proteins: '.faa',
|
281
|
+
genes: '.fna',
|
282
|
+
gff2: '.gff2',
|
283
|
+
gff3: '.gff3',
|
284
|
+
tab: '.tab')
|
285
|
+
opts[:is_clean] ||= false
|
286
|
+
r.clean! if opts[:is_clean]
|
287
|
+
unless r.clean?
|
288
|
+
MiGA::MiGA.clean_fasta_file(r.file_path(:proteins))
|
289
|
+
MiGA::MiGA.clean_fasta_file(r.file_path(:genes)) if r.file_path(:genes)
|
290
|
+
r.clean!
|
284
291
|
end
|
292
|
+
r
|
293
|
+
end
|
285
294
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
r
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
295
|
+
##
|
296
|
+
# Add result type +:essential_genes+ at +base+ (no +_opts+ supported).
|
297
|
+
def add_result_essential_genes(base, _opts)
|
298
|
+
return nil unless result_files_exist?(base, %w[.ess.faa .ess .ess/log])
|
299
|
+
r = MiGA::Result.new("#{base}.json")
|
300
|
+
add_files_to_ds_result(
|
301
|
+
r, name,
|
302
|
+
ess_genes: '.ess.faa',
|
303
|
+
collection: '.ess',
|
304
|
+
report: '.ess/log',
|
305
|
+
alignments: '.ess/proteins.aln')
|
306
|
+
end
|
307
|
+
|
308
|
+
##
|
309
|
+
# Add result type +:ssu+ at +base+. Hash +opts+ supports +is_clean: Boolean+
|
310
|
+
def add_result_ssu(base, opts)
|
311
|
+
return MiGA::Result.new("#{base}.json") if result(:assembly).nil?
|
312
|
+
return nil unless result_files_exist?(base, '.ssu.fa')
|
313
|
+
r = MiGA::Result.new("#{base}.json")
|
314
|
+
r = add_files_to_ds_result(
|
315
|
+
r, name,
|
316
|
+
longest_ssu_gene: '.ssu.fa',
|
317
|
+
gff: '.ssu.gff',
|
318
|
+
all_ssu_genes: '.ssu.all.fa')
|
319
|
+
opts[:is_clean] ||= false
|
320
|
+
r.clean! if opts[:is_clean]
|
321
|
+
unless r.clean?
|
322
|
+
MiGA::MiGA.clean_fasta_file(r.file_path(:longest_ssu_gene))
|
323
|
+
r.clean!
|
301
324
|
end
|
325
|
+
r
|
326
|
+
end
|
302
327
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
328
|
+
##
|
329
|
+
# Add result type +:mytaxa+ at +base+ (no +_opts+ supported)
|
330
|
+
def add_result_mytaxa(base, _opts)
|
331
|
+
if is_multi?
|
332
|
+
return nil unless
|
333
|
+
result_files_exist?(base, '.mytaxa') ||
|
334
|
+
result_files_exist?(base, '.nomytaxa.txt')
|
335
|
+
r = MiGA::Result.new("#{base}.json")
|
336
|
+
add_files_to_ds_result(
|
337
|
+
r, name,
|
338
|
+
mytaxa: '.mytaxa',
|
339
|
+
blast: '.blast',
|
340
|
+
mytaxain: '.mytaxain',
|
341
|
+
nomytaxa: '.nomytaxa.txt',
|
342
|
+
species: '.mytaxa.Species.txt',
|
343
|
+
genus: '.mytaxa.Genus.txt',
|
344
|
+
phylum: '.mytaxa.Phylum.txt',
|
345
|
+
innominate: '.mytaxa.innominate',
|
346
|
+
kronain: '.mytaxa.krona',
|
347
|
+
krona: '.html')
|
348
|
+
else
|
349
|
+
MiGA::Result.new("#{base}.json")
|
321
350
|
end
|
351
|
+
end
|
322
352
|
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
353
|
+
##
|
354
|
+
# Add result type +:mytaxa_scan+ at +base+ (no +_opts+ supported)
|
355
|
+
def add_result_mytaxa_scan(base, _opts)
|
356
|
+
if is_nonmulti?
|
357
|
+
return nil unless
|
358
|
+
result_files_exist?(base, %w[.pdf .mytaxa]) ||
|
359
|
+
result_files_exist?(base, '.nomytaxa.txt')
|
360
|
+
r = MiGA::Result.new("#{base}.json")
|
361
|
+
add_files_to_ds_result(
|
362
|
+
r, name,
|
363
|
+
nomytaxa: '.nomytaxa.txt',
|
364
|
+
mytaxa: '.mytaxa',
|
365
|
+
report: '.pdf',
|
366
|
+
regions_archive: '.reg.tar',
|
367
|
+
# Intermediate / Deprecated:
|
368
|
+
blast: '.blast',
|
369
|
+
mytaxain: '.mytaxain',
|
370
|
+
wintax: '.wintax',
|
371
|
+
gene_ids: '.wintax.genes',
|
372
|
+
region_ids: '.wintax.regions',
|
373
|
+
regions: '.reg')
|
374
|
+
else
|
375
|
+
MiGA::Result.new("#{base}.json")
|
340
376
|
end
|
377
|
+
end
|
341
378
|
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
else
|
349
|
-
add_result_distances_nonref(base)
|
350
|
-
end
|
379
|
+
##
|
380
|
+
# Add result type +:distances+ at +base+ (no +_opts+ supported)
|
381
|
+
def add_result_distances(base, _opts)
|
382
|
+
if is_nonmulti?
|
383
|
+
if is_ref?
|
384
|
+
add_result_distances_ref(base)
|
351
385
|
else
|
352
|
-
|
386
|
+
add_result_distances_nonref(base)
|
353
387
|
end
|
388
|
+
else
|
389
|
+
add_result_distances_multi(base)
|
354
390
|
end
|
391
|
+
end
|
355
392
|
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
##
|
363
|
-
# Add result type +:stats+ at +base+ (no +_opts+ supported).
|
364
|
-
def add_result_stats(base, _opts)
|
365
|
-
MiGA::Result.new("#{base}.json")
|
366
|
-
end
|
393
|
+
##
|
394
|
+
# Add result type +:taxonomy+ at +base+ (no +_opts+ supported)
|
395
|
+
def add_result_taxonomy(base, _opts)
|
396
|
+
add_result_distances_nonref(base)
|
397
|
+
end
|
367
398
|
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
399
|
+
##
|
400
|
+
# Add result type +:stats+ at +base+ (no +_opts+ supported)
|
401
|
+
def add_result_stats(base, _opts)
|
402
|
+
MiGA::Result.new("#{base}.json")
|
403
|
+
end
|
373
404
|
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
File.exist?("#{pref}/01.haai/#{name}.db")
|
380
|
-
r = MiGA::Result.new("#{base}.json")
|
381
|
-
r.add_files(haai_db: "01.haai/#{name}.db", aai_db: "02.aai/#{name}.db",
|
382
|
-
ani_db: "03.ani/#{name}.db")
|
383
|
-
r
|
384
|
-
end
|
405
|
+
##
|
406
|
+
# Add result type +:distances+ for _multi_ datasets at +base+
|
407
|
+
def add_result_distances_multi(base)
|
408
|
+
MiGA::Result.new("#{base}.json")
|
409
|
+
end
|
385
410
|
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
r
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
haai_db: '.haai.db', aai_db: '.aai.db', ani_medoids: '.ani-medoids.tsv',
|
397
|
-
ani_db: '.ani.db', ref_tree: '.nwk', ref_tree_pdf: '.nwk.pdf',
|
398
|
-
intax_test: '.intax.txt'
|
411
|
+
##
|
412
|
+
# Add result type +:distances+ for _nonmulti_ reference datasets at +base+
|
413
|
+
def add_result_distances_ref(base)
|
414
|
+
pref = File.dirname(base)
|
415
|
+
return nil unless File.exist?("#{pref}/01.haai/#{name}.db")
|
416
|
+
MiGA::Result.new("#{base}.json").tap do |r|
|
417
|
+
r.add_files(
|
418
|
+
haai_db: "01.haai/#{name}.db",
|
419
|
+
aai_db: "02.aai/#{name}.db",
|
420
|
+
ani_db: "03.ani/#{name}.db"
|
399
421
|
)
|
400
422
|
end
|
423
|
+
end
|
401
424
|
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
425
|
+
##
|
426
|
+
# Add result type +:distances+ for _nonmulti_ query datasets at +base+
|
427
|
+
def add_result_distances_nonref(base)
|
428
|
+
return nil unless
|
429
|
+
result_files_exist?(base, %w[.aai-medoids.tsv .aai.db]) ||
|
430
|
+
result_files_exist?(base, %w[.ani-medoids.tsv .ani.db])
|
431
|
+
r = MiGA::Result.new("#{base}.json")
|
432
|
+
add_files_to_ds_result(
|
433
|
+
r, name,
|
434
|
+
aai_medoids: '.aai-medoids.tsv',
|
435
|
+
haai_db: '.haai.db',
|
436
|
+
aai_db: '.aai.db',
|
437
|
+
ani_medoids: '.ani-medoids.tsv',
|
438
|
+
ani_db: '.ani.db',
|
439
|
+
ref_tree: '.nwk',
|
440
|
+
ref_tree_pdf: '.nwk.pdf',
|
441
|
+
intax_test: '.intax.txt')
|
442
|
+
end
|
410
443
|
|
444
|
+
##
|
445
|
+
# Add files in +rel_files+ Hash to the result +r+ with dataset name +name+
|
446
|
+
def add_files_to_ds_result(r, name, rel_files)
|
447
|
+
files = {}
|
448
|
+
rel_files.each { |k, v| files[k] = name + v }
|
449
|
+
r.add_files(files)
|
450
|
+
r
|
451
|
+
end
|
411
452
|
end
|
data/lib/miga/project/dataset.rb
CHANGED
data/lib/miga/version.rb
CHANGED
@@ -10,7 +10,7 @@ module MiGA
|
|
10
10
|
# - Float representing the major.minor version.
|
11
11
|
# - Integer representing gem releases of the current version.
|
12
12
|
# - Integer representing minor changes that require new version number.
|
13
|
-
VERSION = [0.6,
|
13
|
+
VERSION = [0.6, 2, 0]
|
14
14
|
|
15
15
|
##
|
16
16
|
# Nickname for the current major.minor version.
|
@@ -18,7 +18,7 @@ module MiGA
|
|
18
18
|
|
19
19
|
##
|
20
20
|
# Date of the current gem release.
|
21
|
-
VERSION_DATE = Date.new(2020, 3,
|
21
|
+
VERSION_DATE = Date.new(2020, 3, 11)
|
22
22
|
|
23
23
|
##
|
24
24
|
# Reference of MiGA.
|
data/test/common_test.rb
CHANGED
@@ -71,14 +71,6 @@ class CommonTest < Test::Unit::TestCase
|
|
71
71
|
FileUtils.rm_rf $tmp
|
72
72
|
end
|
73
73
|
|
74
|
-
def test_tabulate
|
75
|
-
tab = MiGA::MiGA.tabulate(%w[a b], [%w[123 45], %w[678 90]])
|
76
|
-
assert_equal(' a b ', tab[0])
|
77
|
-
assert_equal(' - - ', tab[1])
|
78
|
-
assert_equal('123 45', tab[2])
|
79
|
-
assert_equal('678 90', tab[3])
|
80
|
-
end
|
81
|
-
|
82
74
|
def test_miga_name
|
83
75
|
assert_equal('Xa sp. C', 'Xa_sp__C'.unmiga_name)
|
84
76
|
assert_equal('X_______', 'X^*.!{}!'.miga_name)
|
data/test/daemon_test.rb
CHANGED
@@ -11,7 +11,7 @@ class DaemonTest < Test::Unit::TestCase
|
|
11
11
|
daemon_json = File.expand_path('.miga_daemon.json', ENV['MIGA_HOME'])
|
12
12
|
File.open(daemon_json, 'w') do |fh|
|
13
13
|
fh.puts '{"maxjobs":1,"ppn":1,"latency":2,"varsep":" ",
|
14
|
-
"var":"{{key}}={{value}}","cmd":"{{task_name}}",
|
14
|
+
"var":"{{key}}={{value}}","cmd":"echo {{task_name}} >/dev/null",
|
15
15
|
"alive":"echo 1 # {{pid}}","type":"bash","format_version":1}'
|
16
16
|
end
|
17
17
|
$p1 = MiGA::Project.new(File.expand_path('project1', $tmp))
|
@@ -23,7 +23,30 @@ class DaemonTest < Test::Unit::TestCase
|
|
23
23
|
ENV['MIGA_HOME'] = nil
|
24
24
|
end
|
25
25
|
|
26
|
+
def helper_datasets_with_results(n = 1)
|
27
|
+
p1 = $p1
|
28
|
+
Array.new(n) do |i|
|
29
|
+
d = "d#{i}"
|
30
|
+
FileUtils.touch(File.expand_path(
|
31
|
+
"data/02.trimmed_reads/#{d}.1.clipped.fastq", p1.path
|
32
|
+
))
|
33
|
+
FileUtils.touch(File.expand_path(
|
34
|
+
"data/02.trimmed_reads/#{d}.done", p1.path
|
35
|
+
))
|
36
|
+
p1.add_dataset(MiGA::Dataset.new(p1, d, true).name).tap do |ds|
|
37
|
+
ds.first_preprocessing(true)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
26
42
|
def test_check_project
|
43
|
+
d1 = $d1
|
44
|
+
helper_datasets_with_results.first.inactivate!
|
45
|
+
out = capture_stdout { d1.check_project }
|
46
|
+
assert(out.string =~ /Queueing miga-project:p/)
|
47
|
+
assert_equal(1, d1.jobs_to_run.size)
|
48
|
+
assert_equal(:p, d1.jobs_to_run.first[:job])
|
49
|
+
assert_equal('project1:p:miga-project', d1.get_job(:p)[:task_name])
|
27
50
|
end
|
28
51
|
|
29
52
|
def test_check_datasets
|
@@ -48,7 +71,7 @@ class DaemonTest < Test::Unit::TestCase
|
|
48
71
|
end
|
49
72
|
assert(out.string =~ /Queueing #{ds.name}:d/)
|
50
73
|
assert_equal(1, d.jobs_to_run.size)
|
51
|
-
assert_equal('project1:d:ds1', d.jobs_to_run.first[:cmd])
|
74
|
+
assert_equal('echo project1:d:ds1 >/dev/null', d.jobs_to_run.first[:cmd])
|
52
75
|
assert_equal(d.jobs_to_run.first, d.get_job(:d, ds))
|
53
76
|
end
|
54
77
|
|
@@ -74,11 +97,16 @@ class DaemonTest < Test::Unit::TestCase
|
|
74
97
|
d.runopts(:latency, 0, true)
|
75
98
|
assert_equal(0, d.latency)
|
76
99
|
omit_if($jruby_tests, 'JRuby doesn\'t implement fork.')
|
77
|
-
|
100
|
+
child = $child = d.daemon(:start, ['--shush'])
|
101
|
+
assert(child.is_a? Integer)
|
102
|
+
assert(child != 0, 'The daemond process should have non-zero PID')
|
103
|
+
assert_equal(0, `ps -p "#{child}" -o ppid=`.strip.to_i,
|
104
|
+
'The daemon process should be detached')
|
78
105
|
sleep(3)
|
79
|
-
dpath = File.
|
106
|
+
dpath = File.join(p.path, 'daemon', "MiGA:#{p.name}")
|
80
107
|
assert(File.exist?("#{dpath}.pid"))
|
81
108
|
out = capture_stdout { d.stop }
|
109
|
+
assert_raise(Errno::ESRCH) { Process.kill(0, child) }
|
82
110
|
assert_equal('', out.string)
|
83
111
|
assert(!File.exist?("#{dpath}.pid"))
|
84
112
|
assert(File.exist?("#{dpath}.output"))
|
@@ -90,7 +118,11 @@ class DaemonTest < Test::Unit::TestCase
|
|
90
118
|
assert(l[3] =~ /Probing running jobs\n/)
|
91
119
|
end
|
92
120
|
ensure
|
93
|
-
|
121
|
+
begin
|
122
|
+
Process.kill('KILL', $child) if !$child.nil?
|
123
|
+
rescue Errno::ESRCH
|
124
|
+
false
|
125
|
+
end
|
94
126
|
end
|
95
127
|
|
96
128
|
def test_last_alive
|
@@ -102,18 +134,19 @@ class DaemonTest < Test::Unit::TestCase
|
|
102
134
|
end
|
103
135
|
|
104
136
|
def test_options
|
105
|
-
|
106
|
-
|
107
|
-
assert_equal(
|
108
|
-
assert_equal(
|
109
|
-
assert_equal(
|
110
|
-
assert_equal(
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
137
|
+
d1 = $d1
|
138
|
+
assert_respond_to(d1, :default_options)
|
139
|
+
assert_equal(:normal, d1.default_options[:dir_mode])
|
140
|
+
assert_equal(2, d1.runopts(:latency))
|
141
|
+
assert_equal(1, d1.maxjobs)
|
142
|
+
assert_equal(2, d1.latency)
|
143
|
+
assert_equal(1, d1.ppn)
|
144
|
+
d1.runopts(:alo, :ha)
|
145
|
+
assert_equal(:ha, d1.runopts(:alo))
|
146
|
+
d1.runopts(:maxjobs, '1')
|
147
|
+
assert_equal(1, d1.maxjobs)
|
148
|
+
assert_raise { d1.runopts(:latency, '!') }
|
149
|
+
assert_equal('bash', d1.runopts(:type))
|
117
150
|
end
|
118
151
|
|
119
152
|
def test_say
|
@@ -130,4 +163,153 @@ class DaemonTest < Test::Unit::TestCase
|
|
130
163
|
assert_nil(d.last_alive)
|
131
164
|
end
|
132
165
|
|
166
|
+
def test_maxjobs_json
|
167
|
+
d1 = $d1
|
168
|
+
helper_datasets_with_results(3)
|
169
|
+
assert_equal(0, d1.jobs_running.size)
|
170
|
+
assert_equal(0, d1.jobs_to_run.size)
|
171
|
+
capture_stdout { d1.in_loop }
|
172
|
+
assert_equal(1, d1.jobs_running.size)
|
173
|
+
assert_equal(2, d1.jobs_to_run.size)
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_maxjobs_runopts
|
177
|
+
d1 = $d1
|
178
|
+
helper_datasets_with_results(3)
|
179
|
+
d1.runopts(:maxjobs, 2)
|
180
|
+
assert_equal(0, d1.jobs_running.size)
|
181
|
+
assert_equal(0, d1.jobs_to_run.size)
|
182
|
+
capture_stdout { d1.in_loop }
|
183
|
+
assert_equal(2, d1.jobs_running.size)
|
184
|
+
assert_equal(1, d1.jobs_to_run.size)
|
185
|
+
end
|
186
|
+
|
187
|
+
def test_load_status
|
188
|
+
d1 = $d1
|
189
|
+
p1 = $p1
|
190
|
+
assert_equal(0, d1.jobs_running.size)
|
191
|
+
assert_nil(d1.load_status)
|
192
|
+
assert_equal(0, d1.jobs_running.size)
|
193
|
+
p1.add_dataset(MiGA::Dataset.new(p1, 'd1').name)
|
194
|
+
f = File.join(p1.path, 'daemon', 'status.json')
|
195
|
+
File.open(f, 'w') do |h|
|
196
|
+
h.puts '{"jobs_running":[{"ds":1,"ds_name":"d1"},{}],"jobs_to_run":[]}'
|
197
|
+
end
|
198
|
+
out = capture_stdout { d1.load_status }
|
199
|
+
assert_equal(2, d1.jobs_running.size)
|
200
|
+
assert(out.string =~ /Loading previous status/)
|
201
|
+
assert_equal(MiGA::Dataset, d1.jobs_running[0][:ds].class)
|
202
|
+
assert_nil(d1.jobs_running[1][:ds])
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_flush
|
206
|
+
d1 = $d1
|
207
|
+
p1 = $p1
|
208
|
+
helper_datasets_with_results
|
209
|
+
p1.add_dataset(MiGA::Dataset.new(p1, 'd1').name)
|
210
|
+
MiGA::Project.RESULT_DIRS.keys.each { |i| p1.metadata["run_#{i}"] = false }
|
211
|
+
f = File.join(p1.path, 'daemon', 'status.json')
|
212
|
+
File.open(f, 'w') do |h|
|
213
|
+
h.puts '{"jobs_running":' \
|
214
|
+
'[{"job":"p"},{"job":"d","ds":1,"ds_name":"d1"},' \
|
215
|
+
'{"job":"trimmed_reads","ds":1,"ds_name":"d0"}]' \
|
216
|
+
',"jobs_to_run":[]}'
|
217
|
+
end
|
218
|
+
capture_stdout { d1.load_status }
|
219
|
+
assert_equal(3, d1.jobs_running.size)
|
220
|
+
out = capture_stdout { d1.flush! }
|
221
|
+
assert(out.string =~ /Completed pid:/)
|
222
|
+
assert_equal([], d1.jobs_running)
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_next_host
|
226
|
+
d1 = $d1
|
227
|
+
f = File.join($tmp, 'nodes.txt')
|
228
|
+
File.open(f, 'w') { |h| h.puts 'localhost' }
|
229
|
+
assert_equal(true, d1.next_host)
|
230
|
+
out = capture_stdout { d1.runopts(:nodelist, f) }
|
231
|
+
assert(out.string =~ /Reading node list:/)
|
232
|
+
assert_equal(true, d1.next_host)
|
233
|
+
d1.runopts(:type, 'ssh')
|
234
|
+
assert_equal(0, d1.next_host)
|
235
|
+
f = File.join($p1.path, 'daemon', 'status.json')
|
236
|
+
File.open(f, 'w') do |h|
|
237
|
+
h.puts '{"jobs_running":[{"job":"p","hostk":0}], "jobs_to_run":[]}'
|
238
|
+
end
|
239
|
+
capture_stdout { d1.load_status }
|
240
|
+
assert_nil(d1.next_host)
|
241
|
+
end
|
242
|
+
|
243
|
+
def test_shutdown_when_done
|
244
|
+
$d1.runopts(:shutdown_when_done, true)
|
245
|
+
out = capture_stdout { assert(!$d1.in_loop) }
|
246
|
+
assert(out.string =~ /Nothing else to do/)
|
247
|
+
end
|
248
|
+
|
249
|
+
def test_update_format_0
|
250
|
+
f = File.join($tmp, 'daemon.json')
|
251
|
+
File.open(f, 'w') do |fh|
|
252
|
+
fh.puts '{"maxjobs":1,"ppn":1,"latency":2,"varsep":" ",
|
253
|
+
"var":"%1$s=%1$s","cmd":"echo %1$s","alive":"echo %1$d","type":"bash"}'
|
254
|
+
end
|
255
|
+
d2 = MiGA::Daemon.new($p1, f)
|
256
|
+
assert_equal('echo {{script}}', d2.runopts(:cmd))
|
257
|
+
assert_equal('echo {{pid}}', d2.runopts(:alive))
|
258
|
+
end
|
259
|
+
|
260
|
+
def test_launch_job_bash
|
261
|
+
t = File.join($tmp, 'launch_job_bash')
|
262
|
+
$d1.runopts(:type, 'bash')
|
263
|
+
$d1.runopts(:cmd, "echo {{task_name}} > '#{t}'")
|
264
|
+
helper_daemon_launch_job
|
265
|
+
assert_equal("project1:p:miga-project\n", File.read(t))
|
266
|
+
end
|
267
|
+
|
268
|
+
def test_launch_job_ssh
|
269
|
+
d1 = $d1
|
270
|
+
t = File.join($tmp, 'launch_job_ssh')
|
271
|
+
d1.runopts(:type, 'ssh')
|
272
|
+
d1.runopts(:cmd, "echo {{task_name}} > '#{t}'")
|
273
|
+
f = File.join($tmp, 'nodes.txt')
|
274
|
+
File.open(f, 'w') { |h| h.puts 'localhost' }
|
275
|
+
assert_raise('Unset environment variable: $MIGA_TEST_NODELIST') do
|
276
|
+
d1.runopts(:nodelist, '$MIGA_TEST_NODELIST')
|
277
|
+
end
|
278
|
+
ENV['MIGA_TEST_NODELIST'] = f
|
279
|
+
capture_stdout { d1.runopts(:nodelist, '$MIGA_TEST_NODELIST') }
|
280
|
+
helper_daemon_launch_job
|
281
|
+
assert_equal("project1:p:miga-project\n", File.read(t))
|
282
|
+
end
|
283
|
+
|
284
|
+
def test_launch_job_qsub
|
285
|
+
$d1.runopts(:type, 'qsub')
|
286
|
+
$d1.runopts(:cmd, 'echo {{task_name}}')
|
287
|
+
helper_daemon_launch_job
|
288
|
+
assert_equal('project1:p:miga-project', $d1.jobs_running.first[:pid])
|
289
|
+
end
|
290
|
+
|
291
|
+
def test_launch_job_failure
|
292
|
+
d1 = $d1
|
293
|
+
d1.runopts(:type, 'qsub')
|
294
|
+
d1.runopts(:cmd, 'echo ""')
|
295
|
+
helper_datasets_with_results.first.inactivate!
|
296
|
+
capture_stdout { d1.check_project }
|
297
|
+
out = capture_stdout { d1.launch_job(d1.jobs_to_run.shift) }
|
298
|
+
assert(out.string =~ /Unsuccessful project1:p:miga-project, rescheduling/)
|
299
|
+
assert_equal(0, d1.jobs_running.size)
|
300
|
+
assert_equal(1, d1.jobs_to_run.size)
|
301
|
+
end
|
302
|
+
|
303
|
+
def helper_daemon_launch_job
|
304
|
+
d1 = $d1
|
305
|
+
helper_datasets_with_results.first.inactivate!
|
306
|
+
assert_equal(0, d1.jobs_to_run.size, 'The queue should be empty')
|
307
|
+
capture_stdout { d1.check_project }
|
308
|
+
assert_equal(1, d1.jobs_to_run.size, 'The queue should have one job')
|
309
|
+
capture_stdout { d1.flush! }
|
310
|
+
sleep(1)
|
311
|
+
assert_equal(0, d1.jobs_to_run.size, 'There should be nothing running')
|
312
|
+
assert_equal(1, d1.jobs_running.size, 'There should be one job running')
|
313
|
+
end
|
314
|
+
|
133
315
|
end
|
data/test/format_test.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class FormatTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
$tmp = Dir.mktmpdir
|
7
|
+
end
|
8
|
+
|
9
|
+
def teardown
|
10
|
+
FileUtils.rm_rf $tmp
|
11
|
+
end
|
12
|
+
|
13
|
+
def helper_write_file(content)
|
14
|
+
f = File.join($tmp, 'f.fa')
|
15
|
+
File.open(f, 'w') { |h| h.print content }
|
16
|
+
f
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_clean_fasta
|
20
|
+
c = ">MyFa|not-good\nACTG123ACTG-XXNN*\n>GoodOne + spaces!\n\nA C T G .\n"
|
21
|
+
cc = ">MyFa|not_good\nACTGACTG-XXNN\n>GoodOne + spaces!\nACTG.\n"
|
22
|
+
f = helper_write_file(c)
|
23
|
+
assert_equal(c, File.read(f))
|
24
|
+
MiGA::MiGA.clean_fasta_file(f)
|
25
|
+
assert_equal(cc, File.read(f))
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_wrap_fasta
|
29
|
+
c = ">MyFa\n" + ('X' * 150)
|
30
|
+
cc = ">MyFa\n" + ('X' * 80) + "\n" + ('X' * 70) + "\n"
|
31
|
+
f = helper_write_file(c)
|
32
|
+
assert_equal(c, File.read(f))
|
33
|
+
MiGA::MiGA.clean_fasta_file(f)
|
34
|
+
assert_equal(cc, File.read(f))
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_gz_fasta
|
38
|
+
c = ">a-\na"
|
39
|
+
cc = ">a_\na\n"
|
40
|
+
f = helper_write_file(c)
|
41
|
+
assert_equal(c, File.read(f))
|
42
|
+
`gzip "#{f}"`
|
43
|
+
MiGA::MiGA.clean_fasta_file("#{f}.gz")
|
44
|
+
`gzip -d "#{f}.gz"`
|
45
|
+
assert_equal(cc, File.read(f))
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_seqs_length_fasta
|
49
|
+
c = ">a\nACA\n>b\nACG\n>c\nACTGA\n>d\nGTGAG\n"
|
50
|
+
f = helper_write_file(c)
|
51
|
+
o = MiGA::MiGA.seqs_length(f, :fasta)
|
52
|
+
assert_equal(4.0, o[:avg])
|
53
|
+
assert_equal(1.0, o[:var])
|
54
|
+
assert_equal(1.0, o[:sd])
|
55
|
+
assert_nil(o[:gc])
|
56
|
+
assert_nil(o[:n50])
|
57
|
+
assert_nil(o[:med])
|
58
|
+
o = MiGA::MiGA.seqs_length(f, :fasta, gc: true)
|
59
|
+
assert_equal(50.0, o[:gc])
|
60
|
+
assert_nil(o[:n50])
|
61
|
+
o = MiGA::MiGA.seqs_length(f, :fasta, n50: true)
|
62
|
+
assert_nil(o[:gc])
|
63
|
+
assert_equal(5, o[:n50])
|
64
|
+
o = MiGA::MiGA.seqs_length(f, :fasta, gc: true, n50: true)
|
65
|
+
assert_equal(50.0, o[:gc])
|
66
|
+
assert_equal(5, o[:n50])
|
67
|
+
assert_equal(4.0, o[:med])
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_seqs_length_fastq
|
71
|
+
c = "@a\nac\n+\n!!\n@b\ntggg\n+\n####\n@c\nngt\n+\n!!!\n"
|
72
|
+
f = helper_write_file(c)
|
73
|
+
o = MiGA::MiGA.seqs_length(f, :fastq)
|
74
|
+
assert_equal(3.0, o[:avg])
|
75
|
+
assert_nil(o[:med])
|
76
|
+
o = MiGA::MiGA.seqs_length(f, :fastq, n50: true)
|
77
|
+
assert_equal(3, o[:med])
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_tabulate
|
81
|
+
tab = MiGA::MiGA.tabulate(%w[a b], [%w[123 45], %w[678 90]])
|
82
|
+
assert_equal(' a b ', tab[0])
|
83
|
+
assert_equal(' - - ', tab[1])
|
84
|
+
assert_equal('123 45', tab[2])
|
85
|
+
assert_equal('678 90', tab[3])
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
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: 0.6.
|
4
|
+
version: 0.6.2.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: 2020-03-
|
11
|
+
date: 2020-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: daemons
|
@@ -193,6 +193,7 @@ files:
|
|
193
193
|
- test/common_test.rb
|
194
194
|
- test/daemon_test.rb
|
195
195
|
- test/dataset_test.rb
|
196
|
+
- test/format_test.rb
|
196
197
|
- test/hook_test.rb
|
197
198
|
- test/json_test.rb
|
198
199
|
- test/metadata_test.rb
|