rbbt-util 5.37.16 → 5.38.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/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)
|