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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b7ff73c17fe13dbe5952bb607981bba291cf29d34c372157281339061036157
4
- data.tar.gz: d5af6ded80c32042dbc3463fab085f2bc5c58ea9fc8755224baeb8d08f527ff1
3
+ metadata.gz: 2c317237c4cd2f049b56af6021272208c206f1810052dde4b1b5b41394f37139
4
+ data.tar.gz: '066558242d9bcc1a96f166349815398296cdb976190853a18ca52bdafe84c263'
5
5
  SHA512:
6
- metadata.gz: b178fdfbe3ee23519fa7a6c23d15e6a9f393c1bea610124fa1ccf8245edbb3b95bb8ae9b46382eae3ca2e2664b1dd536fdd7a7c2b34c23cba35fb4e82c8a4123
7
- data.tar.gz: 96e1ff434584528ae8dcf0b6435cc1dbe74a312eb9a1a1dbab86d7464dfe50eb38bced778caf0ef46446c11864495af4b8902ab76ac9700716f5d82ddf8370d9
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
- [:latency, :maxjobs, :nodelist, :ppn, :shutdown_when_done].each do |k|
78
- d.runopts(k, cli[k]) unless cli[k].nil?
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
@@ -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 unless runopts(:format_version)
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
- # Supported tasks include: start, stop, restart, status.
73
- def daemon(task, opts=[])
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) do
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 pid
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
- if ds.nil?
134
- say "Warning: Dataset #{n} listed but not loaded, reloading project"
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
- not job[:ds].next_preprocessing(false).nil?
201
+ !job[:ds].next_preprocessing(false).nil?
206
202
  when 'p'
207
- not project.next_task(nil, false).nil?
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
- # Retrieves the host index of an available node (if any), nil otherwise. If
225
- # #nodelist is not set, returns true as long as #maxjobs is not reached
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 nodelist.nil?
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
- availk = allk - busyk
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.' % project.name
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
- private
290
-
291
- def launch_job(job, hostk = nil)
292
- # Execute job
293
- case runopts(:type)
294
- when 'ssh'
295
- # Remote job
296
- job[:hostk] = hostk
297
- job[:cmd] = job[:cmd].miga_variables(host: nodelist[hostk])
298
- job[:pid] = spawn job[:cmd]
299
- Process.detach job[:pid] unless [nil, '', 0].include?(job[:pid])
300
- when 'bash'
301
- # Local job
302
- job[:pid] = spawn job[:cmd]
303
- Process.detach job[:pid] unless [nil, '', 0].include?(job[:pid])
304
- else
305
- # Schedule cluster job (qsub, msub, slurm)
306
- job[:pid] = `#{job[:cmd]}`.chomp
307
- end
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
- # Check if registered
310
- if [nil, '', 0].include? job[:pid]
311
- job[:pid] = nil
312
- @jobs_to_run << job
313
- say "Unsuccessful #{job[:task_name]}, rescheduling"
314
- else
315
- @jobs_running << job
316
- say "Spawned pid:#{job[:pid]}#{
317
- " to #{job[:hostk]}:#{nodelist[job[:hostk]]}" if job[:hostk]
318
- } for #{job[:task_name]}"
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
- def update_format_0
323
- say 'Outdated daemon.json format, updating from version 0'
324
- {
325
- cmd: %w[script vars cpus log task_name],
326
- var: %w[key value],
327
- alive: %w[pid],
328
- kill: %w[pid]
329
- }.each do |k,v|
330
- runopts(
331
- k, sprintf(
332
- runopts(k).gsub(/%(\d+)\$d/, '%\\1$s'),
333
- *v.map{ |i| "{{#{i}}}" }
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
@@ -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 ; @@RESULT_DIRS.keys.map{ |k| result k }.compact ; end
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
- self.send("add_result_#{result_type}", base, opts) : nil
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
- not ignore_task?(t) and not add_result(t, save).nil?
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 and add_result(t, save).nil?
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 or (t==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? and next_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? and next_task==task
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 not get_result(task).nil?
149
+ elsif !get_result(task).nil?
148
150
  :complete
149
151
  elsif @@PREPROCESSING_TASKS.index(task) <
150
- @@PREPROCESSING_TASKS.index(first_preprocessing)
152
+ @@PREPROCESSING_TASKS.index(first_preprocessing)
151
153
  :-
152
154
  elsif ignore_task?(task)
153
- if not is_active?
155
+ if !is_active?
154
156
  :ignore_inactive
155
157
  elsif metadata["run_#{task}"]
156
158
  :ignore_force
157
- elsif task == :taxonomy and project.metadata[:ref_project].nil?
159
+ elsif task == :taxonomy && project.metadata[:ref_project].nil?
158
160
  :ignore_project
159
- elsif @@_EXCLUDE_NOREF_TASKS_H[task] && ! is_ref?
161
+ elsif @@_EXCLUDE_NOREF_TASKS_H[task] && !is_ref?
160
162
  :ignore_noref
161
- elsif @@_ONLY_MULTI_TASKS_H[task] && ! is_multi?
163
+ elsif @@_ONLY_MULTI_TASKS_H[task] && !is_multi?
162
164
  :ignore_multi
163
- elsif @@_ONLY_NONMULTI_TASKS_H[task] && ! is_nonmulti?
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? or not File.size? db
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
- # Add result type +:raw_reads+ at +base+ (no +_opts+ supported).
197
- def add_result_raw_reads(base, _opts)
198
- return nil unless result_files_exist?(base, '.1.fastq')
199
- r = MiGA::Result.new("#{base}.json")
200
- add_files_to_ds_result(r, name,
201
- ( result_files_exist?(base, '.2.fastq') ?
202
- {pair1: '.1.fastq', pair2: '.2.fastq'} :
203
- {single: '.1.fastq'} ))
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
- r = add_files_to_ds_result(r, name, single: ".1.clipped.fastq")
207
+ { single: '.1.fastq' }
217
208
  end
218
- r.add_file(:trimming_sumary, "#{name}.1.fastq.trimmed.summary.txt")
219
- r
220
- end
209
+ )
210
+ end
221
211
 
222
- ##
223
- # Add result type +:read_quality+ at +base+ (no +_opts+ supported).
224
- def add_result_read_quality(base, _opts)
225
- return nil unless result_files_exist?(base, %w[.solexaqa .fastqc])
226
- r = MiGA::Result.new("#{base}.json")
227
- add_files_to_ds_result(r, name,
228
- solexaqa: ".solexaqa", fastqc: ".fastqc")
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
- # Add result type +:trimmed_fasta+ at +base+ (no +_opts+ supported).
233
- def add_result_trimmed_fasta(base, _opts)
234
- return nil unless
235
- result_files_exist?(base, ".CoupledReads.fa") or
236
- result_files_exist?(base, ".SingleReads.fa") or
237
- result_files_exist?(base, %w[.1.fasta .2.fasta])
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
- # Add result type +:assembly+ at +base+. Hash +opts+ supports
245
- # +is_clean: Boolean+.
246
- def add_result_assembly(base, opts)
247
- return nil unless result_files_exist?(base, ".LargeContigs.fna")
248
- r = MiGA::Result.new("#{base}.json")
249
- r = add_files_to_ds_result(r, name, largecontigs: ".LargeContigs.fna",
250
- allcontigs: ".AllContigs.fna", assembly_data: '')
251
- opts[:is_clean] ||= false
252
- r.clean! if opts[:is_clean]
253
- unless r.clean?
254
- MiGA::MiGA.clean_fasta_file(r.file_path :largecontigs)
255
- r.clean!
256
- end
257
- r
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
- # Add result type +:cds+ at +base+. Hash +opts+ supports +is_clean: Boolean+
262
- def add_result_cds(base, opts)
263
- return nil unless result_files_exist?(base, %w[.faa])
264
- r = MiGA::Result.new("#{base}.json")
265
- r = add_files_to_ds_result(r, name, proteins: ".faa", genes: ".fna",
266
- gff2: ".gff2", gff3: ".gff3", tab: ".tab")
267
- opts[:is_clean] ||= false
268
- r.clean! if opts[:is_clean]
269
- unless r.clean?
270
- MiGA::MiGA.clean_fasta_file(r.file_path :proteins)
271
- MiGA::MiGA.clean_fasta_file(r.file_path :genes) if r.file_path :genes
272
- r.clean!
273
- end
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
- # Add result type +:essential_genes+ at +base+ (no +_opts+ supported).
279
- def add_result_essential_genes(base, _opts)
280
- return nil unless result_files_exist?(base, %w[.ess.faa .ess .ess/log])
281
- r = MiGA::Result.new("#{base}.json")
282
- add_files_to_ds_result(r, name, ess_genes: '.ess.faa',
283
- collection: '.ess', report: '.ess/log', alignments: '.ess/proteins.aln')
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
- # Add result type +:ssu+ at +base+. Hash +opts+ supports +is_clean: Boolean+
288
- def add_result_ssu(base, opts)
289
- return MiGA::Result.new("#{base}.json") if result(:assembly).nil?
290
- return nil unless result_files_exist?(base, ".ssu.fa")
291
- r = MiGA::Result.new("#{base}.json")
292
- r = add_files_to_ds_result(r, name, longest_ssu_gene: ".ssu.fa",
293
- gff: ".ssu.gff", all_ssu_genes: ".ssu.all.fa")
294
- opts[:is_clean] ||= false
295
- r.clean! if opts[:is_clean]
296
- unless r.clean?
297
- MiGA::MiGA.clean_fasta_file(r.file_path :longest_ssu_gene)
298
- r.clean!
299
- end
300
- r
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
- # Add result type +:mytaxa+ at +base+ (no +_opts+ supported).
305
- def add_result_mytaxa(base, _opts)
306
- if is_multi?
307
- return nil unless result_files_exist?(base, '.mytaxa') or
308
- result_files_exist?(base, '.nomytaxa.txt')
309
- r = MiGA::Result.new("#{base}.json")
310
- add_files_to_ds_result(
311
- r, name,
312
- mytaxa: '.mytaxa', blast: '.blast',
313
- mytaxain: '.mytaxain', nomytaxa: '.nomytaxa.txt',
314
- species: '.mytaxa.Species.txt', genus: '.mytaxa.Genus.txt',
315
- phylum: '.mytaxa.Phylum.txt', innominate: '.mytaxa.innominate',
316
- kronain: '.mytaxa.krona', krona: '.html'
317
- )
318
- else
319
- MiGA::Result.new("#{base}.json")
320
- end
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
- # Add result type +:mytaxa_scan+ at +base+ (no +_opts+ supported).
325
- def add_result_mytaxa_scan(base, _opts)
326
- if is_nonmulti?
327
- return nil unless
328
- result_files_exist?(base, %w[.pdf .mytaxa]) or
329
- result_files_exist?(base, '.nomytaxa.txt')
330
- r = MiGA::Result.new("#{base}.json")
331
- add_files_to_ds_result(r, name, nomytaxa: '.nomytaxa.txt',
332
- mytaxa: '.mytaxa', report: '.pdf', regions_archive: '.reg.tar',
333
- # Intermediate / Deprecated
334
- blast: '.blast', mytaxain: '.mytaxain', wintax: '.wintax',
335
- gene_ids: '.wintax.genes', region_ids: '.wintax.regions',
336
- regions: '.reg')
337
- else
338
- MiGA::Result.new("#{base}.json")
339
- end
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
- # Add result type +:distances+ at +base+ (no +_opts+ supported).
344
- def add_result_distances(base, _opts)
345
- if is_nonmulti?
346
- if is_ref?
347
- add_result_distances_ref(base)
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
- add_result_distances_multi(base)
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
- # Add result type +:taxonomy+ at +base+ (no +_opts+ supported).
358
- def add_result_taxonomy(base, _opts)
359
- add_result_distances_nonref(base)
360
- end
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
- # Add result type +:distances+ for _multi_ datasets at +base+.
370
- def add_result_distances_multi(base)
371
- MiGA::Result.new("#{base}.json")
372
- end
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
- # Add result type +:distances+ for _nonmulti_ reference datasets at +base+.
376
- def add_result_distances_ref(base)
377
- pref = File.dirname(base)
378
- return nil unless
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
- # Add result type +:distances+ for _nonmulti_ query datasets at +base+.
388
- def add_result_distances_nonref(base)
389
- return nil unless
390
- result_files_exist?(base, %w[.aai-medoids.tsv .aai.db]) or
391
- result_files_exist?(base, %w[.ani-medoids.tsv .ani.db])
392
- r = MiGA::Result.new("#{base}.json")
393
- add_files_to_ds_result(
394
- r, name,
395
- aai_medoids: '.aai-medoids.tsv',
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
- # Add files in +rel_files+ Hash to the result +r+ with dataset name +name+.
404
- def add_files_to_ds_result(r, name, rel_files)
405
- files = {}
406
- rel_files.each{ |k,v| files[k] = name + v }
407
- r.add_files(files)
408
- r
409
- end
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
@@ -25,7 +25,7 @@ module MiGA::Project::Dataset
25
25
  end
26
26
 
27
27
  ##
28
- # Returns MiGA::Dataset.
28
+ # Returns MiGA::Dataset
29
29
  def dataset(name)
30
30
  name = name.miga_name
31
31
  return nil unless MiGA::Dataset.exist?(self, name)
@@ -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, 1, 0]
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, 10)
21
+ VERSION_DATE = Date.new(2020, 3, 11)
22
22
 
23
23
  ##
24
24
  # Reference of MiGA.
@@ -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)
@@ -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
- $child = fork { d.start(['--shush']) }
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.expand_path("daemon/MiGA:#{p.name}",p.path)
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
- Process.kill('KILL', $child) unless $child.nil?
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
- assert_respond_to($d1, :default_options)
106
- assert_equal(:normal, $d1.default_options[:dir_mode])
107
- assert_equal(2, $d1.runopts(:latency))
108
- assert_equal(1, $d1.maxjobs)
109
- assert_equal(2, $d1.latency)
110
- assert_equal(1, $d1.ppn)
111
- $d1.runopts(:alo, :ha)
112
- assert_equal(:ha, $d1.runopts(:alo))
113
- $d1.runopts(:maxjobs, '1')
114
- assert_equal(1, $d1.maxjobs)
115
- assert_raise { $d1.runopts(:latency, '!') }
116
- assert_equal('bash', $d1.runopts(:type))
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
@@ -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.1.0
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-10 00:00:00.000000000 Z
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