rbbt-util 5.30.13 → 5.31.4

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: 1f5bed0870bd27e4ef4d95a01ad49c4e6fb9e64a6e89eeb82e613e4523b4956f
4
- data.tar.gz: efa0cdc96054711ad3069c3ead053b68dba25198cab1a76163d3b21b5ddf93fb
3
+ metadata.gz: 346571583494c278a4499a2ad2bddc248af37176a7acb3a2457af05941b7a074
4
+ data.tar.gz: 32539316c53ef634de003ea246e8a649de978f66ea48e9666218eac51f85f4b6
5
5
  SHA512:
6
- metadata.gz: 6e1039b390a000f83c29a419294e87d960f6de97e3a6bd341f3772fec279ec0619bbdaf43ced206d83125c02d8e3617e83a365c089b2e4a7463f85c26f12bde2
7
- data.tar.gz: 45f167302faebbfed96b6babe0f5f5941d2722ecd6557b38dc82a997ab75b300ba11abf393def4414b9388fc101b778072119e49a719243d2fc9fd110c69c5b6
6
+ metadata.gz: 4636806a9917c98906f492afd57c2b776b9269b97c07ec205d1f6248a1f91ef3a280003e234f4052288b4d959bc16c9121ac8d12effb81973585b2cbbf499301
7
+ data.tar.gz: 3ef61d067b36a953fd284954db046607de7050a933461a0ebc8b7096abe9d943527165337cf375b43e5f97d20b2ee27722c603684a4e1e63fb20bec56d57dc13
data/lib/rbbt/hpc.rb CHANGED
@@ -1,3 +1,6 @@
1
1
  require 'rbbt-util'
2
2
  require 'rbbt/util/cmd'
3
+ require 'rbbt/hpc/batch'
4
+ require 'rbbt/hpc/orchestrate'
3
5
  require 'rbbt/hpc/slurm'
6
+ require 'rbbt/hpc/lsf'
@@ -0,0 +1,621 @@
1
+ module HPC
2
+ class SBATCH < Exception;
3
+ attr_accessor :directory
4
+ def initialize(directory)
5
+ @directory = directory
6
+ end
7
+ end
8
+
9
+ module TemplateGeneration
10
+ def exec_cmd(job, options = {})
11
+ env_cmd = Misc.process_options options, :env_cmd
12
+ development = Misc.process_options options, :development
13
+
14
+ if options[:singularity]
15
+
16
+ group, user, user_group, scratch_group_dir, projects_group_dir = options.values_at :group, :user, :user_group, :scratch_group_dir, :projects_group_dir
17
+
18
+ singularity_img, singularity_opt_dir, singularity_ruby_inline = options.values_at :singularity_img, :singularity_opt_dir, :singularity_ruby_inline
19
+
20
+ singularity_cmd = %(singularity exec -e -B #{singularity_opt_dir}:/singularity_opt/ -B /apps/)
21
+
22
+ if contain = options[:contain]
23
+ contain = File.expand_path(contain)
24
+ singularity_cmd << %( -C -H "#{contain}" \
25
+ -B "#{options[:batch_dir]}" \
26
+ -B /scratch/tmp \
27
+ #{ group != user_group ? "-B /gpfs/projects/#{user_group}" : "" } \
28
+ -B #{scratch_group_dir} \
29
+ -B #{projects_group_dir} \
30
+ -B "#{singularity_ruby_inline}":"#{contain}/.ruby_inline":rw \
31
+ -B ~/git:"#{contain}/git":ro \
32
+ #{Open.exists?('~/.rbbt/software/opt/')? '-B ~/.rbbt/software/opt/:"/opt/":ro' : '' } \
33
+ -B ~/.rbbt:"#{contain}/home/":ro)
34
+ singularity_cmd << " #{singularity_img} "
35
+ end
36
+ env_cmd ||= ""
37
+ env_cmd << " TMPDIR='#{contain}/.rbbt/tmp' "
38
+ end
39
+
40
+ if env_cmd
41
+ exec_cmd = %(env #{env_cmd} rbbt)
42
+ else
43
+ exec_cmd = %(rbbt)
44
+ end
45
+
46
+ exec_cmd << "--dev '#{development}'" if development
47
+
48
+ exec_cmd = singularity_cmd + exec_cmd if singularity_cmd
49
+
50
+ exec_cmd
51
+ end
52
+
53
+ def rbbt_job_exec_cmd(job, options)
54
+
55
+ jobname = job.clean_name
56
+ workflow = job.workflow
57
+ task = job.task_name
58
+
59
+ Misc.add_defaults options, :jobname => jobname
60
+
61
+ task = Symbol === job.overriden ? job.overriden : job.task_name
62
+
63
+ if job.overriden
64
+ override_deps = job.rec_dependencies.
65
+ select{|dep| Symbol === dep.overriden }.
66
+ collect do |dep|
67
+
68
+ name = [dep.workflow.to_s, dep.task_name] * "#"
69
+ [name, dep.path] * "="
70
+ end * ","
71
+
72
+ options[:override_deps] = override_deps
73
+ end
74
+
75
+ # Save inputs into inputs_dir
76
+ inputs_dir = Misc.process_options options, :inputs_dir
77
+ saved = Step.save_job_inputs(job, inputs_dir) if inputs_dir
78
+ options[:load_inputs] = inputs_dir if saved && saved.any?
79
+
80
+ saved.each do |input|
81
+ options.delete input
82
+ end if saved
83
+
84
+ cmds = CMD.process_cmd_options options.merge(:add_option_dashes => true)
85
+
86
+ <<-EOF.strip
87
+ workflow task #{workflow} #{task} #{cmds}
88
+ EOF
89
+ end
90
+
91
+ def header(options)
92
+ header =<<-EOF
93
+ #!/bin/bash
94
+ EOF
95
+
96
+ header
97
+ end
98
+
99
+ def batch_options(job, options)
100
+ IndiferentHash.setup(options)
101
+
102
+ batch_options = IndiferentHash.setup({})
103
+
104
+ keys = [
105
+ :batch_dir,
106
+ :batch_modules,
107
+ :batch_name,
108
+ :contain,
109
+ :contain_and_sync,
110
+ :copy_image,
111
+ :drbbt,
112
+ :env_cmd,
113
+ :exclusive,
114
+ :highmem,
115
+ :manifest,
116
+ :nodes,
117
+ :queue,
118
+ :singularity,
119
+ :sync,
120
+ :task_cpus,
121
+ :time,
122
+ :user_group,
123
+ :wipe_container,
124
+ :workdir,
125
+ ]
126
+
127
+ keys.each do |key|
128
+ next if options[key].nil?
129
+ batch_options[key] = Misc.process_options options, key
130
+ end
131
+
132
+ batch_dir = batch_options[:batch_dir]
133
+
134
+ batch_name = File.basename(batch_dir)
135
+ inputs_dir = File.join(batch_dir, 'inputs_dir')
136
+
137
+ keys_from_config = [
138
+ :queue,
139
+ :highmem,
140
+ :exclusive,
141
+ :env_cmd,
142
+ :user_group,
143
+ :singularity_img,
144
+ :singularity_opt_dir,
145
+ :singularity_ruby_inline,
146
+ :singularity
147
+ ]
148
+
149
+ keys_from_config.each do |key|
150
+ next unless batch_options.include? key
151
+ default_value = Rbbt::Config.get(key, "batch_#{key}", "batch")
152
+ next if default_value.nil?
153
+ Misc.add_defaults batch_options, default_value
154
+ end
155
+
156
+ user = batch_options[:user] ||= ENV['USER'] || `whoami`.strip
157
+ group = batch_options[:group] ||= File.basename(File.dirname(ENV['HOME']))
158
+ batch_options[:scratch_group_dir] = File.join('/gpfs/scratch/', group)
159
+ batch_options[:projects_group_dir] = File.join('/gpfs/projects/', group)
160
+
161
+ if batch_options[:contain_and_sync]
162
+ if batch_options[:contain].nil?
163
+ contain_base = Rbbt::Config.get(:contain_base_dir, :batch_contain, :batch, :default => "/scratch/tmp/rbbt-[USER]")
164
+ contain_base = contain_base.sub('[USER]', user)
165
+ random_file = TmpFile.random_name
166
+ batch_options[:contain] = File.join(contain_base, random_file)
167
+ end
168
+
169
+ batch_options[:sync] ||= "~/.rbbt/var/jobs"
170
+ batch_options[:wipe_container] ||= 'post'
171
+ end
172
+
173
+ if batch_options[:contain] && ! batch_options[:singularity]
174
+ options[:workdir_all] = batch_options[:contain]
175
+ end
176
+
177
+ Misc.add_defaults batch_options,
178
+ :batch_name => batch_name,
179
+ :inputs_dir => inputs_dir,
180
+ :queue => 'debug',
181
+ :nodes => 1,
182
+ :step_path => job.path,
183
+ :task_cpus => 1,
184
+ :time => '2min',
185
+ :env_cmd => '_JAVA_OPTIONS="-Xms1g -Xmx${MAX_MEMORY}m"',
186
+ :singularity_img => ENV["SINGULARITY_IMG"] || "~/rbbt.singularity.img",
187
+ :singularity_ruby_inline => ENV["SINGULARITY_RUBY_INLINE"] || "~/.singularity_ruby_inline",
188
+ :singularity_opt_dir => ENV["SINGULARITY_OPT_DIR"] || "~/singularity_opt",
189
+ :workdir => Dir.pwd
190
+
191
+ exec_cmd = exec_cmd(job, batch_options)
192
+ rbbt_cmd = rbbt_job_exec_cmd(job, options)
193
+
194
+ Misc.add_defaults batch_options,
195
+ :exec_cmd => exec_cmd,
196
+ :rbbt_cmd => rbbt_cmd
197
+
198
+ batch_dir = batch_options[:batch_dir]
199
+
200
+ Misc.add_defaults batch_options,
201
+ :fout => File.join(batch_dir, 'std.out'),
202
+ :ferr => File.join(batch_dir, 'std.err'),
203
+ :fjob => File.join(batch_dir, 'job.id'),
204
+ :fdep => File.join(batch_dir, 'dependencies.list'),
205
+ :fcfdep => File.join(batch_dir, 'canfail_dependencies.list'),
206
+ :fexit => File.join(batch_dir, 'exit.status'),
207
+ :fsync => File.join(batch_dir, 'sync.log'),
208
+ :fsexit => File.join(batch_dir, 'sync.status'),
209
+ :fcmd => File.join(batch_dir, 'command.batch')
210
+
211
+ batch_options
212
+ end
213
+
214
+ def meta_data(options)
215
+ meta =<<-EOF
216
+ #MANIFEST: #{(options[:manifest] || []) * ", "}
217
+ #DEPENDENCIES: #{(options[:dependencies] || []) * ", "}
218
+ #EXEC_CMD: #{options[:exec_cmd]}
219
+ #CMD: #{options[:rbbt_cmd]}
220
+ #STEP_PATH: #{options[:step_path]}
221
+ EOF
222
+
223
+ meta = meta.split("\n").reject{|line| line =~ /: $/} * "\n"
224
+ meta
225
+ end
226
+
227
+ def load_modules(modules = [])
228
+ modules = modules.split(/,\s*/) if String === modules
229
+
230
+ str = ""
231
+ modules.each do |mod|
232
+ str << "module load #{ mod }" << "\n"
233
+ end if modules
234
+
235
+ str
236
+ end
237
+
238
+ def batch_system_variables
239
+ <<-EOF
240
+ let MAX_MEMORY="$(grep MemTotal /proc/meminfo|grep -o "[[:digit:]]*") / 1024"
241
+ EOF
242
+ end
243
+
244
+ def prepare_environment(options = {})
245
+ modules = options[:batch_modules]
246
+
247
+ prepare_environment = ""
248
+
249
+ functions = ""
250
+
251
+ if contain = options[:contain]
252
+ contain = File.expand_path(contain)
253
+ functions +=<<-EOF
254
+ function batch_erase_contain_dir(){
255
+ rm -Rfv '#{contain}' 2>1 >> '#{options[:fsync]}'
256
+ }
257
+ EOF
258
+
259
+ prepare_environment +=<<-EOF
260
+ if ls -A '#{contain}' &> /dev/null ; then
261
+ empty_contain_dir="false"
262
+ else
263
+ empty_contain_dir="true"
264
+ fi
265
+ EOF
266
+
267
+ prepare_environment +=<<-EOF if options[:wipe_container] == 'force'
268
+ batch_erase_contain_dir()
269
+ EOF
270
+ end
271
+
272
+ if sync = options[:sync]
273
+ source = if options[:singularity]
274
+ File.join(options[:contain], '.rbbt/var/jobs')
275
+ elsif options[:contain]
276
+ File.join(options[:contain], 'var/jobs')
277
+ else
278
+ '~/.rbbt/var/jobs/'
279
+ end
280
+
281
+ source = File.expand_path(source)
282
+ sync = File.expand_path(sync)
283
+ functions +=<<-EOF
284
+ function batch_sync_contain_dir(){
285
+ mkdir -p "$(dirname '#{sync}')"
286
+ rsync -avztAXHP --copy-unsafe-links "#{source}/" "#{sync}/" 2>1 >> '#{options[:fsync]}'
287
+ sync_es="$?"
288
+ echo $sync_es > '#{options[:fsexit]}'
289
+ find '#{sync}' -type l -ls | awk '$13 ~ /^#{sync.gsub('/','\/')}/ { sub("#{source}", "#{sync}", $13); print $11, $13 }' | while read A B; do rm $A; ln -s $B $A; done
290
+ }
291
+ EOF
292
+ end
293
+
294
+ if options[:singularity]
295
+
296
+ group, user, user_group, scratch_group_dir, projects_group_dir = options.values_at :group, :user, :user_group, :scratch_group_dir, :projects_group_dir
297
+
298
+ singularity_img, singularity_opt_dir, singularity_ruby_inline = options.values_at :singularity_img, :singularity_opt_dir, :singularity_ruby_inline
299
+
300
+ prepare_environment +=<<-EOF
301
+ # Load singularity modules
302
+ module load intel/2018.1
303
+ module load singularity
304
+ mkdir -p "#{singularity_opt_dir}"
305
+ EOF
306
+
307
+ if contain
308
+
309
+ prepare_environment +=<<-EOF
310
+ # Prepare container for singularity
311
+ mkdir -p "#{contain}/.rbbt/etc/"
312
+
313
+ for dir in .ruby_inline git home; do
314
+ mkdir -p "#{contain}/$dir"
315
+ done
316
+
317
+ for tmpd in persist_locks produce_locks R_sockets sensiblewrite sensiblewrite_locks step_info_locks tsv_open_locks; do
318
+ mkdir -p "#{contain}/.rbbt/tmp/$tmpd"
319
+ done
320
+
321
+ # Copy environment
322
+ cp ~/.rbbt/etc/environment #{contain}/.rbbt/etc/
323
+
324
+ # Set search_paths
325
+ echo "singularity: /singularity_opt/{PKGDIR}/{TOPLEVEL}/{SUBPATH}" > #{contain}/.rbbt/etc/search_paths
326
+ echo "rbbt_user: /home/rbbt/.rbbt/{TOPLEVEL}/{SUBPATH}" >> #{contain}/.rbbt/etc/search_paths
327
+ echo "outside_home: #{contain}/home/{TOPLEVEL}/{SUBPATH}" >> #{contain}/.rbbt/etc/search_paths
328
+ echo "group_projects: #{projects_group_dir}/{PKGDIR}/{TOPLEVEL}/{SUBPATH}" >> #{contain}/.rbbt/etc/search_paths
329
+ echo "group_scratch: #{scratch_group_dir}/{PKGDIR}/{TOPLEVEL}/{SUBPATH}" >> #{contain}/.rbbt/etc/search_paths
330
+ echo "user_projects: #{projects_group_dir}/#{user}/{PKGDIR}/{TOPLEVEL}/{SUBPATH}" >> #{contain}/.rbbt/etc/search_paths
331
+ echo "user_scratch: #{scratch_group_dir}/#{user}/{PKGDIR}/{TOPLEVEL}/{SUBPATH}" >> #{contain}/.rbbt/etc/search_paths
332
+ EOF
333
+ end
334
+ end
335
+
336
+ batch_system_variables + load_modules(modules) + "\n" + functions + "\n" + prepare_environment
337
+ end
338
+
339
+ def execute(options)
340
+ exec_cmd, job_cmd = options.values_at :exec_cmd, :rbbt_cmd
341
+
342
+ <<-EOF
343
+ step_path=$(
344
+ #{exec_cmd} #{job_cmd} --printpath
345
+ )
346
+ exit_status=$?
347
+
348
+ [[ -z $BATCH_JOB_ID ]] || #{exec_cmd} workflow write_info --recursive --force=false --check_pid "$step_path" batch_job $BATCH_JOB_ID
349
+ [[ -z $BATCH_SYSTEM ]] || #{exec_cmd} workflow write_info --recursive --force=false --check_pid "$step_path" batch_system $BATCH_SYSTEM
350
+ EOF
351
+ end
352
+
353
+ def sync_environment(options = {})
354
+ sync_environment = ""
355
+
356
+ if options[:sync]
357
+ sync_environment +=<<-EOF
358
+ if [ $exit_status == '0' ]; then
359
+ batch_sync_contain_dir
360
+ else
361
+ sync_es=$exit_status
362
+ fi
363
+ EOF
364
+ end
365
+
366
+ sync_environment
367
+ end
368
+
369
+ def cleanup_environment(options = {})
370
+ cleanup_environment = ""
371
+ if options[:sync]
372
+ if options[:wipe_container] == 'force'
373
+ cleanup_environment +=<<-EOF
374
+ batch_erase_contain_dir
375
+ EOF
376
+ elsif options[:wipe_container] == 'post' || options[:wipe_container] == 'both'
377
+ cleanup_environment +=<<-EOF
378
+ if [ $sync_es == '0' -a $empty_contain_dir == 'true' ]; then
379
+ batch_erase_contain_dir
380
+ fi
381
+ EOF
382
+ end
383
+ end
384
+ cleanup_environment
385
+ end
386
+
387
+ def coda(options)
388
+ coda =<<-EOF
389
+ echo $exit_status > '#{options[:fexit]}'
390
+ EOF
391
+
392
+ if options[:sync]
393
+ coda +=<<-EOF
394
+ if [ $sync_es == '0' ]; then
395
+ exit $exit_status
396
+ else
397
+ exit $sync_es
398
+ fi
399
+ EOF
400
+ else
401
+ coda +=<<-EOF
402
+ exit $exit_status
403
+ EOF
404
+ end
405
+
406
+ coda
407
+ end
408
+
409
+ def job_template(job, options = {})
410
+ batch_options = batch_options job, options
411
+
412
+ header = self.header(batch_options)
413
+
414
+ meta_data = self.meta_data(batch_options)
415
+
416
+ prepare_environment = self.prepare_environment(batch_options)
417
+
418
+ execute = self.execute(batch_options)
419
+
420
+ sync_environment = self.sync_environment(batch_options)
421
+
422
+ cleanup_environment = self.cleanup_environment(batch_options)
423
+
424
+ coda = self.coda(batch_options)
425
+
426
+ <<-EOF
427
+ #{header}
428
+
429
+ # #{Log.color :green, "0. Meta-data"}
430
+ #{meta_data}
431
+
432
+ # #{Log.color :green, "1. Prepare environment"}
433
+ #{prepare_environment}
434
+
435
+ # #{Log.color :green, "2. Execute"}
436
+ #{execute}
437
+
438
+ # #{Log.color :green, "3. Sync and cleanup environment"}
439
+ #{sync_environment}
440
+ #{cleanup_environment}
441
+
442
+ # #{Log.color :green, "4. Exit"}
443
+ #{coda}
444
+ EOF
445
+ end
446
+
447
+ def prepare_submision(template, batch_dir, clean_batch_job = false, batch_dependencies = [])
448
+ Open.mkdir batch_dir
449
+ fcmd = File.join(batch_dir, 'command.batch')
450
+ fdep = File.join(batch_dir, 'dependencies.list')
451
+ fcfdep = File.join(batch_dir, 'canfail_dependencies.list')
452
+
453
+ Open.write(fcmd, template)
454
+
455
+ %w(std.out std.err job.id job.status dependencies.list canfail_dependencies.list exit.status sync.log inputs_dir).each do |filename|
456
+ path = File.join(batch_dir, filename)
457
+ Open.rm_rf path if File.exists? path
458
+ end if clean_batch_job
459
+
460
+ batch_dependencies = [] if batch_dependencies.nil?
461
+
462
+ canfail_dependencies = batch_dependencies.select{|dep| dep =~ /^canfail:(\d+)/ }.collect{|dep| dep.partition(":").last}
463
+ dependencies = batch_dependencies.reject{|dep| dep =~ /^canfail:(\d+)/ }
464
+
465
+ Open.write(fdep, dependencies * "\n") if dependencies.any?
466
+ Open.write(fcfdep, canfail_dependencies * "\n") if canfail_dependencies.any?
467
+
468
+ fcmd
469
+ end
470
+
471
+
472
+ def run_job(job, options = {})
473
+ system = self.to_s.split("::").last
474
+
475
+ batch_base_dir, clean_batch_job, remove_batch_dir, procpath, tail, batch_dependencies, dry_run = Misc.process_options options,
476
+ :batch_base_dir, :clean_batch_job, :remove_batch_dir, :batch_procpath, :tail, :batch_dependencies, :dry_run,
477
+ :batch_base_dir => File.expand_path(File.join('~/rbbt-batch'))
478
+
479
+ workflow = job.workflow
480
+ task_name = job.task_name
481
+
482
+ TmpFile.with_file(nil, remove_batch_dir, :tmpdir => batch_base_dir, :prefix => "#{system}_rbbt_job-#{workflow.to_s}-#{task_name}-") do |batch_dir|
483
+ Misc.add_defaults options,
484
+ :batch_dir => batch_dir,
485
+ :inputs_dir => File.join(batch_dir, "inputs_dir")
486
+
487
+ options[:procpath_performance] ||= File.join(batch_dir, "procpath##{procpath.gsub(',', '#')}") if procpath
488
+
489
+ template = self.job_template(job, options.dup)
490
+
491
+ fcmd = prepare_submision(template, options[:batch_dir], clean_batch_job, batch_dependencies)
492
+
493
+ batch_job = run_template(batch_dir, dry_run)
494
+
495
+ return batch_job unless tail
496
+
497
+ t_monitor = Thread.new do
498
+ self.follow_job(batch_dir, :STDERR)
499
+ end
500
+ self.wait_for_job(batch_dir)
501
+ t_monitor.raise Aborted
502
+ return unless Open.read(File.join(batch_dir, 'exit.status')).strip == '0'
503
+ path = Open.read(File.join(batch_dir, 'std.out')).strip
504
+ if Open.exists?(path) && job.path != path
505
+ Log.info "Path of BATCH job #{path} is different from original job #{job.path}. Stablishing link."
506
+ Open.ln path, job.path
507
+ Open.ln path + '.info', job.path + '.info' if Open.exists?(path + '.info')
508
+ Open.ln path + '.files', job.path + '.files' if Open.exists?(path + '.files')
509
+ end
510
+ batch_job
511
+
512
+ end
513
+ end
514
+
515
+ def follow_job(batch_dir, tail = true)
516
+ fjob = File.join(batch_dir, 'job.id')
517
+ fout = File.join(batch_dir, 'std.out')
518
+ ferr = File.join(batch_dir, 'std.err')
519
+ fexit = File.join(batch_dir, 'exit.status')
520
+ fstatus = File.join(batch_dir, 'job.status')
521
+
522
+ job = Open.read(fjob).strip if Open.exists?(fjob)
523
+
524
+ if job && ! File.exists?(fexit)
525
+ begin
526
+ status_txt = job_status(job)
527
+ STDERR.puts Log.color(:magenta, "Status [#{job.to_i}]:")
528
+ STDERR.puts status_txt
529
+ lines = status_txt.split("\n").length
530
+ rescue
531
+ if ! File.exists?(fexit)
532
+ STDERR.puts Log.color(:magenta, "Job #{job.to_i} not done and not running. STDERR:")
533
+ STDERR.puts Open.read(ferr)
534
+ end
535
+ return
536
+ end
537
+ end
538
+
539
+ if File.exists?(fexit)
540
+ exit_status = Open.read(fexit)
541
+ if exit_status.to_i == 0
542
+ STDERR.puts Log.color(:magenta, "Job #{job} done with exit_status 0. STDOUT:")
543
+ STDERR.puts Open.read(fout)
544
+ else
545
+ STDERR.puts Log.color(:magenta, "Job #{job.to_i} done with exit_status #{exit_status}. STDERR:")
546
+ STDERR.puts Open.read(ferr)
547
+ end
548
+ return
549
+ end
550
+
551
+ if tail
552
+ Log.severity = 10
553
+ while ! File.exists? fout
554
+ if job
555
+ STDERR.puts
556
+ Log.clear_line(STDERR)
557
+ STDERR.write Log.color(:magenta, "Waiting for Output")
558
+ 3.times do
559
+ STDERR.write Log.color(:magenta, ".")
560
+ sleep 1
561
+ end
562
+ status_txt = job_status(job)
563
+ lines.times do
564
+ Log.clear_line(STDERR)
565
+ end
566
+ Log.clear_line(STDERR)
567
+ STDERR.puts Log.color(:magenta, "Status [#{job.to_i}]:")
568
+ STDERR.puts status_txt
569
+ lines = status_txt.split("\n").length
570
+ end
571
+ end
572
+ STDERR.puts
573
+ Log.clear_line(STDERR)
574
+ STDERR.puts Log.color(:magenta, "Output:")
575
+ begin
576
+ status_txt = job_status(job)
577
+ Open.write(fstatus, status_txt) unless status_txt.nil? || status_txt.empty?
578
+ out = CMD.cmd("tail -f '#{fout}'", :pipe => true) if File.exists?(fout) and not tail == :STDERR
579
+ err = CMD.cmd("tail -f '#{ferr}'", :pipe => true) if File.exists?(ferr)
580
+
581
+ terr = Misc.consume_stream(err, true, STDERR) if err
582
+ tout = Misc.consume_stream(out, true, STDOUT) if out
583
+
584
+ sleep 3 while job_status(job).include? job.to_s
585
+ rescue Aborted
586
+ ensure
587
+ begin
588
+ terr.exit if terr
589
+ tout.exit if tout
590
+ err.close if err
591
+ err.join if err
592
+ rescue Exception
593
+ end
594
+
595
+ begin
596
+ out.close if out
597
+ out.join if out
598
+ rescue Exception
599
+ end
600
+ end
601
+ end
602
+ end
603
+
604
+ def wait_for_job(batch_dir, time = 1)
605
+ fexit = File.join(batch_dir, 'exit.status')
606
+ fjob = File.join(batch_dir, 'job.id')
607
+ job = Open.read(fjob) if Open.exists?(fjob)
608
+
609
+ while ! Open.exists?(fexit)
610
+ sleep time
611
+ end
612
+ end
613
+
614
+ end
615
+
616
+ module BATCH
617
+ extend HPC::TemplateGeneration
618
+ end
619
+
620
+ end
621
+