miga-base 0.6.1.0 → 0.6.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/miga/cli/action/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
|