rbbt-util 5.37.16 → 5.38.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rbbt/annotations.rb +2 -0
- data/lib/rbbt/hpc/batch.rb +15 -6
- data/lib/rbbt/hpc/orchestrate.rb +1 -0
- data/lib/rbbt/persist.rb +2 -2
- data/lib/rbbt/resource/path.rb +1 -0
- data/lib/rbbt/resource/rake.rb +1 -1
- data/lib/rbbt/resource.rb +7 -2
- data/lib/rbbt/tsv/excel.rb +5 -1
- data/lib/rbbt/tsv/parser.rb +2 -2
- data/lib/rbbt/util/misc/development.rb +6 -1
- data/lib/rbbt/util/misc/exceptions.rb +10 -0
- data/lib/rbbt/util/misc/format.rb +3 -0
- data/lib/rbbt/util/misc/indiferent_hash.rb +9 -6
- data/lib/rbbt/util/misc/inspect.rb +22 -8
- data/lib/rbbt/util/misc/options.rb +1 -1
- data/lib/rbbt/util/misc/pipes.rb +3 -3
- data/lib/rbbt/util/open.rb +0 -1
- data/lib/rbbt/util/ssh.rb +107 -14
- data/lib/rbbt/workflow/remote_workflow/driver/ssh.rb +75 -15
- data/lib/rbbt/workflow/remote_workflow/remote_step/ssh.rb +16 -7
- data/lib/rbbt/workflow/remote_workflow/remote_step.rb +1 -0
- data/lib/rbbt/workflow/step/dependencies.rb +6 -5
- data/lib/rbbt/workflow/step/info.rb +1 -1
- data/lib/rbbt/workflow/step/run.rb +1 -1
- data/lib/rbbt/workflow/step/save_load_inputs.rb +9 -8
- data/lib/rbbt/workflow/step.rb +7 -2
- data/lib/rbbt/workflow/usage.rb +3 -3
- data/lib/rbbt/workflow.rb +1 -1
- data/share/rbbt_commands/hpc/list +293 -293
- data/share/rbbt_commands/lsf/list +293 -293
- data/share/rbbt_commands/resource/find +2 -1
- data/share/rbbt_commands/resource/glob +1 -1
- data/share/rbbt_commands/slurm/list +293 -293
- data/share/rbbt_commands/workflow/task +63 -21
- data/test/rbbt/test_resource.rb +7 -2
- data/test/rbbt/tsv/test_accessor.rb +21 -4
- data/test/rbbt/tsv/test_parser.rb +28 -0
- data/test/rbbt/util/misc/test_indiferent_hash.rb +14 -0
- data/test/rbbt/util/test_cmd.rb +7 -1
- data/test/rbbt/util/test_open.rb +3 -3
- data/test/rbbt/util/test_ssh.rb +10 -0
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1121593dec25c29d7986047727d555ed0e75df6b158f9f1332764ad4886462c5
|
4
|
+
data.tar.gz: c8e39ef65e23445cf5d0c8817af961a9206016c5e3665d87e042f0fadec2b8df
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 22c87766544a52c9c6f0d6da369422a452f553d1a61b82a54674f676a3867a6c1d29028c2efd031563f982cdadbce56d36950c8e100bd34ac2a7e95b39af8a58
|
7
|
+
data.tar.gz: 0a79edc89dad388bca9b94dfeccba1df64c4294e84c4f19743608038e55f8800181911d787980adae3ec1c715a993430ccbf2bc07d6212485b89843ada93de74
|
data/lib/rbbt/annotations.rb
CHANGED
data/lib/rbbt/hpc/batch.rb
CHANGED
@@ -556,23 +556,32 @@ env > #{batch_options[:fenv]}
|
|
556
556
|
fcmd
|
557
557
|
end
|
558
558
|
|
559
|
+
def batch_dir_for_id(batch_base_dir, id)
|
560
|
+
job_id_file = Dir.glob(File.join(batch_base_dir, '*/job.id')).select{|f| Open.read(f).strip == id.to_s }.first
|
561
|
+
job_id_file ? File.dirname(job_id_file) : nil
|
562
|
+
end
|
559
563
|
|
560
564
|
def run_job(job, options = {})
|
561
565
|
system = self.to_s.split("::").last
|
562
566
|
|
567
|
+
batch_base_dir, clean_batch_job, remove_batch_dir, procpath, tail, batch_dependencies, dry_run = Misc.process_options options,
|
568
|
+
:batch_base_dir, :clean_batch_job, :remove_batch_dir, :batch_procpath, :tail, :batch_dependencies, :dry_run,
|
569
|
+
:batch_base_dir => File.expand_path(File.join('~/rbbt-batch'))
|
570
|
+
|
563
571
|
if (batch_job = job.info[:batch_job]) && job_queued(batch_job)
|
564
572
|
Log.info "Job #{job.short_path} already queued in #{batch_job}"
|
565
|
-
return batch_job
|
573
|
+
return batch_job, batch_dir_for_id(batch_base_dir, batch_job)
|
566
574
|
end
|
567
575
|
|
568
576
|
if job.running?
|
569
577
|
Log.info "Job #{job.short_path} already running in #{job.info[:pid]}"
|
570
|
-
return job.info[:batch_job]
|
571
|
-
end
|
572
578
|
|
573
|
-
|
574
|
-
|
575
|
-
|
579
|
+
if job.info[:batch_job]
|
580
|
+
return job.info[:batch_job], batch_dir_for_id(batch_base_dir, batch_job)
|
581
|
+
else
|
582
|
+
return
|
583
|
+
end
|
584
|
+
end
|
576
585
|
|
577
586
|
workflow = job.original_workflow ||job.workflow
|
578
587
|
task_name = job.original_task_name || job.task_name
|
data/lib/rbbt/hpc/orchestrate.rb
CHANGED
data/lib/rbbt/persist.rb
CHANGED
@@ -115,7 +115,7 @@ module Persist
|
|
115
115
|
begin
|
116
116
|
case (type || :marshal).to_sym
|
117
117
|
when :path
|
118
|
-
path
|
118
|
+
Path.setup(Open.read(path).strip)
|
119
119
|
when :nil
|
120
120
|
nil
|
121
121
|
when :boolean
|
@@ -172,7 +172,7 @@ module Persist
|
|
172
172
|
|
173
173
|
case (type || :marshal).to_sym
|
174
174
|
when :path
|
175
|
-
|
175
|
+
Open.write(path, content)
|
176
176
|
when :nil
|
177
177
|
nil
|
178
178
|
when :boolean
|
data/lib/rbbt/resource/path.rb
CHANGED
data/lib/rbbt/resource/rake.rb
CHANGED
data/lib/rbbt/resource.rb
CHANGED
@@ -350,6 +350,7 @@ url='#{url}'
|
|
350
350
|
end
|
351
351
|
|
352
352
|
def identify(path)
|
353
|
+
return path unless path.start_with?("/")
|
353
354
|
path = File.expand_path(path)
|
354
355
|
path += "/" if File.directory?(path)
|
355
356
|
resource ||= Rbbt
|
@@ -357,6 +358,7 @@ url='#{url}'
|
|
357
358
|
locations -= [:current, "current"]
|
358
359
|
locations << :current
|
359
360
|
search_paths = IndiferentHash.setup(resource.search_paths)
|
361
|
+
choices = []
|
360
362
|
locations.uniq.each do |name|
|
361
363
|
pattern = search_paths[name]
|
362
364
|
pattern = resource.search_paths[pattern] while Symbol === pattern
|
@@ -370,12 +372,15 @@ url='#{url}'
|
|
370
372
|
"(?:/(?<REST>.*))?/?$"
|
371
373
|
if m = path.match(regexp)
|
372
374
|
if ! m.named_captures.include?("PKGDIR") || m["PKGDIR"] == resource.pkgdir
|
373
|
-
|
375
|
+
unlocated = ([m["TOPLEVEL"],m["SUBPATH"],m["REST"]] * "/")
|
376
|
+
unlocated.gsub!(/\/+/,'/')
|
377
|
+
unlocated[self.subdir] = "" if self.subdir
|
378
|
+
choices << self.annotate(unlocated)
|
374
379
|
end
|
375
380
|
end
|
376
381
|
end
|
377
382
|
end
|
378
|
-
|
383
|
+
choices.sort_by{|s| s.length }.first
|
379
384
|
end
|
380
385
|
end
|
381
386
|
|
data/lib/rbbt/tsv/excel.rb
CHANGED
@@ -154,7 +154,11 @@ module TSV
|
|
154
154
|
sheet1 = book.create_worksheet
|
155
155
|
sheet1.name = sheet if sheet
|
156
156
|
|
157
|
-
|
157
|
+
if fields
|
158
|
+
sheet1.row(0).concat fields if fields
|
159
|
+
else
|
160
|
+
sheet1.row(0).concat ["No field info"]
|
161
|
+
end
|
158
162
|
|
159
163
|
rows.each_with_index do |cells,i|
|
160
164
|
sheet1.row(i+1).concat cells
|
data/lib/rbbt/tsv/parser.rb
CHANGED
@@ -130,12 +130,12 @@ module TSV
|
|
130
130
|
keys = parts[key_position].split(@sep2, -1)
|
131
131
|
values = case
|
132
132
|
when field_positions.nil?
|
133
|
-
|
133
|
+
parts.tap{|o| o.delete_at key_position}
|
134
134
|
when field_positions.empty?
|
135
135
|
[]
|
136
136
|
else
|
137
137
|
parts.values_at *field_positions
|
138
|
-
end.collect{|value| (value.nil? || value.empty?) ? [] : value.split(@sep2, -1) }
|
138
|
+
end.collect{|value| (value.nil? || value.empty?) ? [""] : value.split(@sep2, -1) }
|
139
139
|
[keys, values]
|
140
140
|
end
|
141
141
|
|
@@ -423,13 +423,18 @@ def self.add_libdir(dir=nil)
|
|
423
423
|
end
|
424
424
|
end
|
425
425
|
|
426
|
-
def self.
|
426
|
+
def self.ssh_run_old(server, script = nil)
|
427
427
|
Log.debug "Run ssh script in #{server}:\n#{script}"
|
428
428
|
|
429
429
|
#CMD.cmd("ssh '#{server}' 'shopt -s expand_aliases; bash -l -c \"ruby\"' ", :in => script, :log => true).read
|
430
430
|
CMD.cmd("ssh '#{server}' ruby", :in => script, :log => true).read
|
431
431
|
end
|
432
432
|
|
433
|
+
def self.ssh_run(server, script = nil)
|
434
|
+
require 'rbbt/util/ssh'
|
435
|
+
SSHLine.ruby(server, script)
|
436
|
+
end
|
437
|
+
|
433
438
|
def self.ssh_connection(server, reset = false)
|
434
439
|
@@ssh_connections ||= {}
|
435
440
|
@@ssh_connections.delete server if reset
|
@@ -28,6 +28,16 @@ class ProcessFailed < StandardError;
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
class SSHProcessFailed < StandardError
|
32
|
+
attr_accessor :host, :cmd
|
33
|
+
def initialize(host, cmd)
|
34
|
+
@host = host
|
35
|
+
@cmd = cmd
|
36
|
+
message = "SSH server #{host} failed cmd '#{cmd}'"
|
37
|
+
super(message)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
31
41
|
class ConcurrentStreamProcessFailed < ProcessFailed
|
32
42
|
attr_accessor :concurrent_stream
|
33
43
|
def initialize(pid = Process.pid, msg = nil, concurrent_stream = nil)
|
@@ -27,6 +27,9 @@ module Misc
|
|
27
27
|
|
28
28
|
def self.format_paragraph(text, size = 80, indent = 0, offset = 0)
|
29
29
|
i = 0
|
30
|
+
offset = 0 if offset.nil?
|
31
|
+
indent = 0 if indent.nil?
|
32
|
+
size = 80 if size.nil?
|
30
33
|
size = size + offset + indent
|
31
34
|
re = /((?:\n\s*\n\s*)|(?:\n\s*(?=\*)))/
|
32
35
|
text.split(re).collect do |paragraph|
|
@@ -22,18 +22,21 @@ module IndiferentHash
|
|
22
22
|
@_default ||= self.default or self.default_proc
|
23
23
|
end
|
24
24
|
|
25
|
-
def [](key)
|
26
|
-
res = super(key)
|
25
|
+
def [](key, *args)
|
26
|
+
res = super(key, *args)
|
27
|
+
res = IndiferentHash.setup(res) if Hash === res
|
27
28
|
return res unless res.nil? or (_default? and not keys.include? key)
|
28
29
|
|
29
30
|
case key
|
30
31
|
when Symbol, Module
|
31
|
-
super(key.to_s)
|
32
|
+
res = super(key.to_s, *args)
|
32
33
|
when String
|
33
|
-
super(key.to_sym)
|
34
|
-
else
|
35
|
-
res
|
34
|
+
res = super(key.to_sym, *args)
|
36
35
|
end
|
36
|
+
|
37
|
+
res = IndiferentHash.setup(res) if Hash === res
|
38
|
+
|
39
|
+
res
|
37
40
|
end
|
38
41
|
|
39
42
|
def values_at(*key_list)
|
@@ -275,7 +275,6 @@ module Misc
|
|
275
275
|
|
276
276
|
|
277
277
|
def self.step_file?(path)
|
278
|
-
return true if defined?(Step) && Step === path.resource
|
279
278
|
return false unless path =~ /\.files(?:\/|$)/
|
280
279
|
parts = path.split("/")
|
281
280
|
job = parts.select{|p| p =~ /\.files$/}.first
|
@@ -283,9 +282,19 @@ module Misc
|
|
283
282
|
i = parts.index job
|
284
283
|
begin
|
285
284
|
workflow, task = parts.values_at i - 2, i - 1
|
286
|
-
|
285
|
+
_loaded = false
|
286
|
+
begin
|
287
|
+
Kernel.const_get(workflow)
|
288
|
+
rescue
|
289
|
+
if ! _loaded
|
290
|
+
Workflow.require_workflow workflow
|
291
|
+
_loaded = true
|
292
|
+
retry
|
293
|
+
end
|
294
|
+
raise $!
|
295
|
+
end
|
287
296
|
#return Kernel.const_get(workflow).tasks.include? task.to_sym
|
288
|
-
return
|
297
|
+
return parts[i-2..-1] * "/"
|
289
298
|
rescue
|
290
299
|
Log.exception $!
|
291
300
|
end
|
@@ -293,6 +302,8 @@ module Misc
|
|
293
302
|
false
|
294
303
|
end
|
295
304
|
|
305
|
+
RBBT_IDENTIFY_PATH = ENV["RBBT_IDENTIFY_PATH"] != 'false'
|
306
|
+
|
296
307
|
def self.obj2str(obj)
|
297
308
|
_obj = obj
|
298
309
|
obj = Annotated.purge(obj) if Annotated === obj
|
@@ -310,18 +321,21 @@ module Misc
|
|
310
321
|
'false'
|
311
322
|
when Hash
|
312
323
|
"{"<< obj.collect{|k,v| obj2str(k) + '=>' << obj2str(v)}*"," << "}"
|
313
|
-
when (defined?(Path)
|
324
|
+
when (defined?(Path) && Path)
|
314
325
|
if defined?(Step) && Open.exists?(Step.info_file(obj))
|
315
326
|
obj2str(Workflow.load_step(obj))
|
316
|
-
elsif step_file?(obj)
|
317
|
-
"Step file: " +
|
327
|
+
elsif step_file_path = step_file?(obj)
|
328
|
+
"Step file: " + step_file_path
|
318
329
|
else
|
319
330
|
if obj.exists?
|
331
|
+
obj = (obj.resource || Rbbt).identify obj if RBBT_IDENTIFY_PATH
|
320
332
|
if obj.directory?
|
321
333
|
files = obj.glob("**/*")
|
322
|
-
"directory: #{Misc.fingerprint(files)}"
|
323
|
-
|
334
|
+
"directory: #{Misc.fingerprint(files.collect{|f| Misc.path_relative_to(obj.find, f)}.sort)}"
|
335
|
+
elsif obj.located?
|
324
336
|
"file: " << Open.realpath(obj) << "--" << mtime_str(obj)
|
337
|
+
else
|
338
|
+
"path: " << obj
|
325
339
|
end
|
326
340
|
else
|
327
341
|
obj + " (file missing)"
|
data/lib/rbbt/util/misc/pipes.rb
CHANGED
@@ -318,9 +318,9 @@ module Misc
|
|
318
318
|
Open.mkdir dir unless Open.exists?(dir)
|
319
319
|
into_path, into = into, Open.open(into, :mode => 'w')
|
320
320
|
end
|
321
|
-
into.sync = true if IO === into
|
321
|
+
#into.sync = true if IO === into
|
322
322
|
into_close = false unless into.respond_to? :close
|
323
|
-
io.sync = true
|
323
|
+
#io.sync = true
|
324
324
|
|
325
325
|
begin
|
326
326
|
while c = io.readpartial(BLOCK_SIZE)
|
@@ -402,7 +402,7 @@ module Misc
|
|
402
402
|
when (IO === content or StringIO === content or File === content)
|
403
403
|
|
404
404
|
Open.write(tmp_path) do |f|
|
405
|
-
f.sync = true
|
405
|
+
#f.sync = true
|
406
406
|
while block = content.read(BLOCK_SIZE)
|
407
407
|
f.write block
|
408
408
|
end
|
data/lib/rbbt/util/open.rb
CHANGED
data/lib/rbbt/util/ssh.rb
CHANGED
@@ -1,25 +1,118 @@
|
|
1
|
-
|
1
|
+
require 'net/ssh'
|
2
2
|
|
3
|
-
|
4
|
-
server = server.sub(%r(^ssh:(//)?), '')
|
3
|
+
class SSHLine
|
5
4
|
|
6
|
-
|
7
|
-
|
5
|
+
def initialize(host, user = nil)
|
6
|
+
@host = host
|
7
|
+
@user = user
|
8
8
|
|
9
|
-
|
9
|
+
@ssh = Net::SSH.start(@host, @user)
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
@ch = @ssh.open_channel do |ch|
|
12
|
+
ch.exec 'bash'
|
13
|
+
end
|
14
14
|
|
15
|
-
|
15
|
+
@ch.on_data do |_,data|
|
16
|
+
if m = data.match(/DONECMD: (\d+)\n/)
|
17
|
+
@exit_status = m[1].to_i
|
18
|
+
@output << data.sub(m[0],'')
|
19
|
+
serve_output
|
20
|
+
else
|
21
|
+
@output << data
|
22
|
+
end
|
23
|
+
end
|
16
24
|
|
17
|
-
|
25
|
+
@ch.on_extended_data do |_,c,err|
|
26
|
+
STDERR.write err
|
27
|
+
end
|
18
28
|
end
|
19
29
|
|
20
|
-
def
|
21
|
-
|
30
|
+
def send_cmd(command)
|
31
|
+
@output = ""
|
32
|
+
@complete_output = false
|
33
|
+
@ch.send_data(command+"\necho DONECMD: $?\n")
|
22
34
|
end
|
23
35
|
|
24
|
-
|
36
|
+
def serve_output
|
37
|
+
@complete_output = true
|
38
|
+
end
|
39
|
+
|
40
|
+
def run(command)
|
41
|
+
send_cmd(command)
|
42
|
+
@ssh.loop{ ! @complete_output}
|
43
|
+
if @exit_status.to_i == 0
|
44
|
+
return @output
|
45
|
+
else
|
46
|
+
raise SSHProcessFailed.new @host, command
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def ruby(script)
|
51
|
+
@output = ""
|
52
|
+
@complete_output = false
|
53
|
+
cmd = "ruby -e \"#{script.gsub('"','\\"')}\"\n"
|
54
|
+
Log.debug "Running ruby on #{@host}:\n#{ script }"
|
55
|
+
@ch.send_data(cmd)
|
56
|
+
@ch.send_data("echo DONECMD: $?\n")
|
57
|
+
@ssh.loop{ !@complete_output }
|
58
|
+
if @exit_status.to_i == 0
|
59
|
+
return @output
|
60
|
+
else
|
61
|
+
raise SSHProcessFailed.new @host, "Ruby script:\n#{script}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def rbbt(script)
|
66
|
+
rbbt_script =<<-EOF
|
67
|
+
require 'rbbt-util'
|
68
|
+
require 'rbbt/workflow'
|
69
|
+
|
70
|
+
res = begin
|
71
|
+
old_stdout = STDOUT.dup; STDOUT.reopen(STDERR)
|
72
|
+
#{script}
|
73
|
+
ensure
|
74
|
+
STDOUT.reopen(old_stdout)
|
75
|
+
end
|
76
|
+
|
77
|
+
puts Marshal.dump(res)
|
78
|
+
EOF
|
79
|
+
|
80
|
+
m = ruby(rbbt_script)
|
81
|
+
Marshal.load m
|
82
|
+
end
|
83
|
+
|
84
|
+
def workflow(workflow, script)
|
85
|
+
preamble =<<-EOF
|
86
|
+
wf = Workflow.require_workflow('#{workflow}')
|
87
|
+
EOF
|
88
|
+
|
89
|
+
rbbt(preamble + "\n" + script)
|
90
|
+
end
|
91
|
+
|
92
|
+
@connections = {}
|
93
|
+
def self.open(host, user = nil)
|
94
|
+
@connections[[host, user]] ||= SSHLine.new host, user
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.run(server, cmd, options = nil)
|
98
|
+
cmd = cmd * " " if Array === cmd
|
99
|
+
cmd += " " + CMD.process_cmd_options(options) if options
|
100
|
+
open(server).run(cmd)
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.ruby(server, script)
|
104
|
+
open(server).ruby(script)
|
105
|
+
end
|
25
106
|
|
107
|
+
def self.rbbt(server, script)
|
108
|
+
open(server).rbbt(script)
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.workflow(server, workflow, script)
|
112
|
+
open(server).workflow(workflow, script)
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.command(server, command, argv = [], options = nil)
|
116
|
+
run(server, [command] + argv, options)
|
117
|
+
end
|
118
|
+
end
|
@@ -99,7 +99,7 @@ STDOUT.write res.to_json
|
|
99
99
|
JSON.parse(json)
|
100
100
|
end
|
101
101
|
|
102
|
-
def self.get_raw(url, params)
|
102
|
+
def self.get_raw(url, params = {})
|
103
103
|
server, path = parse_url(url)
|
104
104
|
script = path_script(path)
|
105
105
|
|
@@ -193,7 +193,8 @@ job.clean
|
|
193
193
|
new = Step.migrate(paths, :user, :target => server)
|
194
194
|
files.zip(new).each{|file,new| Open.write(file, new) }
|
195
195
|
|
196
|
-
|
196
|
+
SSHLine.run(server, "mkdir -p .rbbt/tmp/tmp-ssh_job_inputs/")
|
197
|
+
CMD.cmd_log("scp -r '#{dir}' #{server}:.rbbt/tmp/tmp-ssh_job_inputs/#{input_id}")
|
197
198
|
end
|
198
199
|
end
|
199
200
|
end
|
@@ -220,21 +221,39 @@ job.clean
|
|
220
221
|
# rjob.run
|
221
222
|
#end
|
222
223
|
|
223
|
-
def self.upload_dependencies(
|
224
|
+
def self.upload_dependencies(job_list, server, search_path = 'user', produce_dependencies = false)
|
224
225
|
server, path = parse_url(server) if server =~ /^ssh:\/\//
|
225
|
-
job.dependencies.each do |dep|
|
226
|
-
Log.medium "Producing #{dep.workflow}:#{dep.short_path} dependency for #{job.workflow}:#{job.short_path}"
|
227
|
-
dep.produce
|
228
|
-
end if produce_dependencies
|
229
226
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
227
|
+
job_list = [job_list] unless Array === job_list
|
228
|
+
|
229
|
+
all_deps = {}
|
230
|
+
if produce_dependencies
|
231
|
+
job_list.each do |job|
|
232
|
+
job.dependencies.each do |dep|
|
233
|
+
all_deps[dep] ||= []
|
234
|
+
all_deps[dep] << job
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
job_list.each do |job|
|
240
|
+
job.input_dependencies.each do |dep|
|
241
|
+
all_deps[dep] ||= []
|
242
|
+
all_deps[dep] << job
|
243
|
+
end
|
244
|
+
end
|
234
245
|
|
235
|
-
|
236
|
-
|
237
|
-
|
246
|
+
missing_deps = []
|
247
|
+
all_deps.each do |dep,jobs|
|
248
|
+
next if dep.done?
|
249
|
+
Log.medium "Producing #{dep.workflow}:#{dep.short_path} dependency for #{Misc.fingerprint jobs}"
|
250
|
+
dep.run(true)
|
251
|
+
missing_deps << dep
|
252
|
+
end if produce_dependencies
|
253
|
+
Step.wait_for_jobs missing_deps
|
254
|
+
|
255
|
+
migrate_dependencies = all_deps.keys.collect{|d| [d] + d.rec_dependencies + d.input_dependencies }.flatten.select{|d| d.done? }.collect{|d| d.path }
|
256
|
+
Log.medium "Migrating #{migrate_dependencies.length} dependencies from #{Misc.fingerprint job_list} to #{ server }"
|
238
257
|
Step.migrate(migrate_dependencies, search_path, :target => server) if migrate_dependencies.any?
|
239
258
|
end
|
240
259
|
|
@@ -242,7 +261,6 @@ job.clean
|
|
242
261
|
inputs = job.inputs.to_hash.slice(*job.real_inputs.map{|i| i.to_s})
|
243
262
|
job.dependencies.each do |dep|
|
244
263
|
next if dep.done?
|
245
|
-
iif [dep, dep.inputs, dep.real_inputs]
|
246
264
|
inputs = dep.inputs.to_hash.slice(*dep.real_inputs.map{|i| i.to_s}).merge(inputs)
|
247
265
|
inputs = missing_dep_inputs(dep).merge(inputs)
|
248
266
|
end
|
@@ -279,6 +297,48 @@ job.clean
|
|
279
297
|
rjob
|
280
298
|
end
|
281
299
|
|
300
|
+
def self.relay_job_list(job_list, server, options = {})
|
301
|
+
migrate, produce, produce_dependencies, search_path, run_type, slurm_options = Misc.process_options options.dup,
|
302
|
+
:migrate, :produce, :produce_dependencies, :search_path, :run_type, :slurm_options
|
303
|
+
|
304
|
+
search_path ||= 'user'
|
305
|
+
|
306
|
+
produce = true if migrate
|
307
|
+
|
308
|
+
upload_dependencies(job_list, server, search_path, options[:produce_dependencies])
|
309
|
+
|
310
|
+
rjobs_job = job_list.collect do |job|
|
311
|
+
|
312
|
+
workflow_name = job.workflow.to_s
|
313
|
+
remote_workflow = RemoteWorkflow.new("ssh://#{server}:#{workflow_name}", "#{workflow_name}")
|
314
|
+
inputs = IndiferentHash.setup(job.recursive_inputs.to_hash).slice(*job.real_inputs.map{|i| i.to_s})
|
315
|
+
Log.medium "Relaying dependency #{job.workflow}:#{job.short_path} to #{server} (#{inputs.keys * ", "})"
|
316
|
+
|
317
|
+
rjob = remote_workflow.job(job.task_name.to_s, job.clean_name, inputs)
|
318
|
+
|
319
|
+
override_dependencies = job.rec_dependencies.select{|dep| dep.done? }.collect{|dep| [dep.workflow.to_s, dep.task_name.to_s] * "#" << "=" << Rbbt.identify(dep.path)}
|
320
|
+
rjob.override_dependencies = override_dependencies
|
321
|
+
|
322
|
+
rjob.run_type = run_type
|
323
|
+
rjob.slurm_options = slurm_options || {}
|
324
|
+
|
325
|
+
rjob.run(true)
|
326
|
+
|
327
|
+
[rjob, job]
|
328
|
+
end
|
329
|
+
|
330
|
+
if options[:migrate]
|
331
|
+
rjobs_job.each do |rjob,job|
|
332
|
+
rjob.produce
|
333
|
+
iif [:migrate, job]
|
334
|
+
Step.migrate(Rbbt.identify(job.path), 'user', :source => server)
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
rjobs_job.collect{|p| p.first }
|
339
|
+
end
|
340
|
+
|
341
|
+
|
282
342
|
def self.relay(workflow, task, jobname, inputs, server, options = {})
|
283
343
|
job = workflow.job(task, jobname, inputs)
|
284
344
|
relay_job(job, server, options)
|