autoflow 0.8.5 → 0.9.6
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 +5 -5
- data/autoflow.gemspec +5 -4
- data/bin/AutoFlow +10 -0
- data/bin/flow_logger +9 -0
- data/lib/autoflow/batch.rb +72 -5
- data/lib/autoflow/queue_manager.rb +7 -1
- data/lib/autoflow/queue_managers/bash_manager.rb +2 -2
- data/lib/autoflow/queue_managers/slurm_manager.rb +18 -4
- data/lib/autoflow/stack.rb +7 -4
- data/lib/autoflow/version.rb +1 -1
- metadata +32 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1e2701342ff440d0d59eb570fe27b29207d53086ba8136a7a36cf4d6645282c1
|
4
|
+
data.tar.gz: 617a0049af3be6e649947f73eabe68ac38016fd0e687b42ef1c3081faebe3db7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 768d88e9b31cce325d703a27659e63485ae801701bdc4a668218df71888d4517a62be5f95c681f29828a7ef93d00a3cacf51af66e354cd4c56b0d5b415511722
|
7
|
+
data.tar.gz: e5495d58e69440871e743613716866eeb1a93968214cc50fc5da2298beb5cb3d5dadcf67bdcf0ce0ce208696740866805ba6cbfc12cce1d056e2d0ead6f44ce7
|
data/autoflow.gemspec
CHANGED
@@ -19,10 +19,11 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_runtime_dependency 'net-ssh', '>= 2.8.0'
|
22
|
-
spec.add_runtime_dependency 'git', '>=
|
22
|
+
spec.add_runtime_dependency 'git', '>= 0.8.1'
|
23
23
|
spec.add_runtime_dependency 'win32console', '>= 1.3.2' if !ENV['OS'].nil? && ENV['OS'].downcase.include?('windows')
|
24
|
-
spec.add_runtime_dependency 'colorize', '
|
25
|
-
spec.add_runtime_dependency 'terminal-table', '
|
26
|
-
spec.
|
24
|
+
spec.add_runtime_dependency 'colorize', '>= 0.7.3'
|
25
|
+
spec.add_runtime_dependency 'terminal-table', '>= 2.0.0'
|
26
|
+
spec.add_runtime_dependency 'openssl', '>= 2.2.0'
|
27
|
+
spec.add_development_dependency "bundler", ">= 2.2.7"
|
27
28
|
spec.add_development_dependency "rake"
|
28
29
|
end
|
data/bin/AutoFlow
CHANGED
@@ -83,6 +83,11 @@ optparse = OptionParser.new do |opts|
|
|
83
83
|
options[:add] = add
|
84
84
|
end
|
85
85
|
|
86
|
+
options[:additional_job_options] = nil
|
87
|
+
opts.on( '-A', '--additional_job_options STRING', 'Additional option in queue system jobs. Format: "parameter:value"' ) do |opt|
|
88
|
+
options[:additional_job_options] = opt.split(':')
|
89
|
+
end
|
90
|
+
|
86
91
|
options[:batch] = false
|
87
92
|
opts.on( '-b', '--batch', 'Workflow execution using batch' ) do
|
88
93
|
options[:batch] = true
|
@@ -103,6 +108,11 @@ optparse = OptionParser.new do |opts|
|
|
103
108
|
options[:external_dependencies] = external_dependencies.split(',')
|
104
109
|
end
|
105
110
|
|
111
|
+
options[:extended_logging] = false
|
112
|
+
opts.on( '-e', '--extended_logging', 'If set the command /usr/bin/time will be used instead of shell built-in version. Data will be saved in process_data file of task folder' ) do
|
113
|
+
options[:extended_logging] = true
|
114
|
+
end
|
115
|
+
|
106
116
|
options[:retry] = false
|
107
117
|
opts.on( '-f', '--force', 'Execute all jobs, including any job commented with %' ) do
|
108
118
|
options[:retry] = true
|
data/bin/flow_logger
CHANGED
@@ -296,6 +296,15 @@ OptionParser.new do |opts|
|
|
296
296
|
opts.on("-H", "--html", "Make a workflow execution full report in html format") do |opt|
|
297
297
|
options[:html] = true
|
298
298
|
end
|
299
|
+
|
300
|
+
# Set a banner, displayed at the top of the help screen.
|
301
|
+
opts.banner = "Usage: flow_logger [options] \n\n"
|
302
|
+
|
303
|
+
# This displays the help screen
|
304
|
+
opts.on( '-h', '--help', 'Display this screen' ) do
|
305
|
+
puts opts
|
306
|
+
exit
|
307
|
+
end
|
299
308
|
end.parse!
|
300
309
|
|
301
310
|
#################################################################################################
|
data/lib/autoflow/batch.rb
CHANGED
@@ -4,14 +4,15 @@ class Batch
|
|
4
4
|
@@all_batch = {}
|
5
5
|
@@jobs_names = []
|
6
6
|
@@batch_iterator_relations = {}
|
7
|
-
@@
|
7
|
+
@@nested_iteration_relations = {}
|
8
8
|
@@general_computation_attrib = {
|
9
9
|
:cpu => nil,
|
10
10
|
:mem => nil,
|
11
11
|
:time => nil,
|
12
12
|
:node => nil,
|
13
13
|
:multinode => nil,
|
14
|
-
:ntask => nil
|
14
|
+
:ntask => nil,
|
15
|
+
:additional_job_options => nil
|
15
16
|
}
|
16
17
|
|
17
18
|
def self.set_general_attrib(attrib_hash)
|
@@ -20,6 +21,7 @@ class Batch
|
|
20
21
|
|
21
22
|
|
22
23
|
def initialize(tag, init, main_command, id, exec_folder)
|
24
|
+
@regex_deps = nil
|
23
25
|
replace_regexp(tag, init, main_command)
|
24
26
|
@name = nil
|
25
27
|
@id = id
|
@@ -63,6 +65,7 @@ class Batch
|
|
63
65
|
data = /!JobRegExp:([^ \n]+):([^ \n]+)!([^ \n]+)/.match(command) # *to1 with regexp
|
64
66
|
#data[0] => reference string (command), data[1] => batch_pattern, data[2] => iterator_pattern, data[3] => adyacent string to regexp as regexp/file_name
|
65
67
|
job_names = get_dependencies_by_regexp(data[1], data[2])
|
68
|
+
@regex_deps = 'command' if job_names.length > 0
|
66
69
|
new_string = job_names.map{|jn| jn + ')' + data[3] }.join(' ')
|
67
70
|
command.gsub!(data[0], new_string)
|
68
71
|
#puts command.inspect
|
@@ -72,6 +75,9 @@ class Batch
|
|
72
75
|
data = /JobRegExp:([^ \n]+):([^;\] \n]+)/.match(tag) # 1to1 with regexp
|
73
76
|
#data[0] => reference string (command), data[1] => batch_pattern, data[2] => iterator_pattern
|
74
77
|
job_names = get_dependencies_by_regexp(data[1], data[2])
|
78
|
+
if job_names.length > 0
|
79
|
+
@regex_deps = 'tag'
|
80
|
+
end
|
75
81
|
new_string = job_names.map{|jn| jn + ')'}.join(';')
|
76
82
|
tag.gsub!(data[0], new_string)
|
77
83
|
end
|
@@ -188,6 +194,8 @@ class Batch
|
|
188
194
|
@attrib[:time] = fields[index+1]
|
189
195
|
elsif field == '-u'
|
190
196
|
@attrib[:multinode] = fields[index+1].to_i
|
197
|
+
elsif field == '-A'
|
198
|
+
@attrib[:additional_job_options] = fields[index+1].split(':')
|
191
199
|
end
|
192
200
|
end
|
193
201
|
if fields.include?('-s')
|
@@ -253,6 +261,7 @@ class Batch
|
|
253
261
|
new_job = duplicate_job(tmp_j, iter)
|
254
262
|
check_dependencies(new_job, iter, temp_jobs)
|
255
263
|
parse_iter(iter, @name, new_job)
|
264
|
+
add_nested_iteration_relation(tmp_j, new_job)
|
256
265
|
@@jobs_names << new_job.name
|
257
266
|
jobs << new_job
|
258
267
|
@jobs << new_job
|
@@ -261,6 +270,7 @@ class Batch
|
|
261
270
|
end
|
262
271
|
temp_jobs = delete_jobs(jobs2delete, temp_jobs) #Remove temporal jobs
|
263
272
|
else
|
273
|
+
check_regex_dependencies
|
264
274
|
@iterator.each_with_index do |iter, num|
|
265
275
|
job_attrib = @attrib.dup
|
266
276
|
if !iter.nil?
|
@@ -283,6 +293,61 @@ class Batch
|
|
283
293
|
return jobs
|
284
294
|
end
|
285
295
|
|
296
|
+
def add_nested_iteration_relation(tmp_j, new_job)
|
297
|
+
query = @@nested_iteration_relations[tmp_j.name]
|
298
|
+
if query.nil?
|
299
|
+
@@nested_iteration_relations[tmp_j.name] = [new_job.name]
|
300
|
+
else
|
301
|
+
query << new_job.name
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
def check_regex_dependencies
|
306
|
+
if @regex_deps == 'tag'
|
307
|
+
new_job_names = []
|
308
|
+
@iterator.each do |iter|
|
309
|
+
new_names = find_job_names(iter.gsub(')', ''))
|
310
|
+
new_job_names.concat(new_names)
|
311
|
+
end
|
312
|
+
@iterator = new_job_names.map{|nj| nj + ')'} if !new_job_names.empty?
|
313
|
+
elsif @regex_deps == 'command'
|
314
|
+
[@initialization, @main_command].each do |command|
|
315
|
+
patterns = command.scan(/([^\s)]+)\)([^\s]*)/)
|
316
|
+
if !patterns.empty?
|
317
|
+
patterns.each do |putative_job, sufix|
|
318
|
+
job_names = find_job_names(putative_job)
|
319
|
+
if !job_names.empty?
|
320
|
+
new_string = job_names.map{|jn| "#{jn})#{sufix}"}.join(' ')
|
321
|
+
old_string = "#{putative_job})#{sufix}"
|
322
|
+
command.gsub!(old_string, new_string)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def find_job_names(name)
|
331
|
+
final_names = []
|
332
|
+
intermediary_names = @@nested_iteration_relations[name]
|
333
|
+
if !intermediary_names.nil?
|
334
|
+
while !intermediary_names.empty?
|
335
|
+
final_names = intermediary_names
|
336
|
+
i_names = []
|
337
|
+
intermediary_names.each do |i_n|
|
338
|
+
query = @@nested_iteration_relations[i_n]
|
339
|
+
i_names.concat(query) if !query.nil?
|
340
|
+
end
|
341
|
+
if !i_names.empty?
|
342
|
+
intermediary_names = i_names
|
343
|
+
else
|
344
|
+
break
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
return final_names
|
349
|
+
end
|
350
|
+
|
286
351
|
#tmp_j => job to set dependencies in iteration
|
287
352
|
#iter => sufix of current iteration
|
288
353
|
#jobs => array of jobs which has the job dependency
|
@@ -313,7 +378,7 @@ class Batch
|
|
313
378
|
def handle_dependencies(dinamic_variables)
|
314
379
|
[@initialization, @main_command].each do |instructions|
|
315
380
|
if instructions.class.to_s == 'String'
|
316
|
-
scan_dependencies(instructions)
|
381
|
+
#scan_dependencies(instructions) # NOT NECESSARY? REMOVED BY COLLISION CON REGEX SYSTEM. THE DINAMYC VARIABLES ARE NO USED
|
317
382
|
dinamic_variables.concat(collect_dinamic_variables(instructions))
|
318
383
|
@dependencies.concat(check_dependencies_with_DinVar(instructions, dinamic_variables))
|
319
384
|
end
|
@@ -336,8 +401,10 @@ class Batch
|
|
336
401
|
@dependencies << [name, '1to1', "!#{name}*!"]
|
337
402
|
end
|
338
403
|
if command.include?("!#{name}!") && !string_overlap(matched_regions, "!#{name}!", command)
|
339
|
-
command =~ /!#{name}!([^ \n]+)/
|
340
|
-
|
404
|
+
#command =~ /!#{name}!([^ \n]+)/
|
405
|
+
command.scan(/!#{name}!([^ \n]+)/).each do |string_match|
|
406
|
+
@dependencies << [name, '*to1', "!#{name}!", string_match.first]
|
407
|
+
end
|
341
408
|
end
|
342
409
|
local_dependencies = command.scan(/#{name}([^\( \n]+)\)/)
|
343
410
|
local_dependencies.each do |local_dependency|
|
@@ -15,6 +15,7 @@ class QueueManager
|
|
15
15
|
@write_sh = options[:write_sh]
|
16
16
|
@external_dependencies = options[:external_dependencies]
|
17
17
|
@active_jobs = []
|
18
|
+
@extended_logging = options[:extended_logging]
|
18
19
|
end
|
19
20
|
|
20
21
|
########################################################################################
|
@@ -267,7 +268,12 @@ class QueueManager
|
|
267
268
|
|
268
269
|
def write_job(job, sh_name)
|
269
270
|
write_file(sh_name, job.initialization) if !job.initialization.nil?
|
270
|
-
|
271
|
+
if @extended_logging
|
272
|
+
log_command = '/usr/bin/time -o process_data -v '
|
273
|
+
else
|
274
|
+
log_command = 'time '
|
275
|
+
end
|
276
|
+
write_file(sh_name, log_command + job.parameters)
|
271
277
|
end
|
272
278
|
|
273
279
|
def get_dependencies(job, id = nil)
|
@@ -1,20 +1,34 @@
|
|
1
1
|
require 'queue_manager'
|
2
2
|
class SlurmManager < QueueManager
|
3
|
+
def parse_additional_options(string, attribs)
|
4
|
+
expresions = %w[%C %T %M %N ]
|
5
|
+
values = [attribs[:cpu], attribs[:time], attribs[:mem], attribs[:node]]
|
6
|
+
new_string = string.dup
|
7
|
+
expresions.each_with_index do |exp, i|
|
8
|
+
new_string.gsub!(exp, "#{values[i]}")
|
9
|
+
end
|
10
|
+
return new_string
|
11
|
+
end
|
12
|
+
|
3
13
|
def write_header(id, job, sh_name)
|
4
14
|
if !job.attrib[:ntask]
|
5
15
|
write_file(sh_name, "#SBATCH --cpus=#{job.attrib[:cpu]}")
|
6
16
|
else
|
7
17
|
write_file(sh_name, "#SBATCH --ntasks=#{job.attrib[:cpu]}")
|
8
18
|
write_file(sh_name, "#SBATCH --nodes=#{job.attrib[:multinode]}") if job.attrib[:multinode] > 0
|
9
|
-
write_file(sh_name, 'srun hostname -s > workers') if job.attrib[:cpu_asign] == 'list'
|
10
19
|
end
|
11
20
|
write_file(sh_name, "#SBATCH --mem=#{job.attrib[:mem]}")
|
12
21
|
write_file(sh_name, "#SBATCH --time=#{job.attrib[:time]}")
|
13
22
|
write_file(sh_name, "#SBATCH --constraint=#{job.attrib[:node]}") if !job.attrib[:node].nil?
|
14
23
|
write_file(sh_name, '#SBATCH --error=job.%J.err')
|
15
24
|
write_file(sh_name, '#SBATCH --output=job.%J.out')
|
25
|
+
write_file(sh_name, "#SBATCH --#{job.attrib[:additional_job_options][0]}=#{parse_additional_options(job.attrib[:additional_job_options][1], job.attrib)}") if !job.attrib[:additional_job_options].nil?
|
26
|
+
if job.attrib[:ntask]
|
27
|
+
write_file(sh_name, 'srun hostname -s > workers') if job.attrib[:cpu_asign] == 'list'
|
28
|
+
end
|
16
29
|
end
|
17
30
|
|
31
|
+
|
18
32
|
def submit_job(job, ar_dependencies)
|
19
33
|
final_dep = get_all_deps(ar_dependencies)
|
20
34
|
dependencies = nil
|
@@ -34,13 +48,13 @@ class SlurmManager < QueueManager
|
|
34
48
|
end
|
35
49
|
|
36
50
|
def self.available?(options)
|
37
|
-
available =
|
51
|
+
available = true
|
38
52
|
shell_output = system_call("type 'sbatch'", nil, options[:remote], options[:ssh])
|
39
|
-
available =
|
53
|
+
available = false if shell_output.empty?
|
40
54
|
return available
|
41
55
|
end
|
42
56
|
|
43
57
|
def self.priority
|
44
58
|
return 100
|
45
59
|
end
|
46
|
-
end
|
60
|
+
end
|
data/lib/autoflow/stack.rb
CHANGED
@@ -16,7 +16,8 @@ class Stack
|
|
16
16
|
:time => options[:time],
|
17
17
|
:node => options[:node_type],
|
18
18
|
:multinode => options[:use_multinode],
|
19
|
-
:ntask => options[:use_ntasks]
|
19
|
+
:ntask => options[:use_ntasks],
|
20
|
+
:additional_job_options => options[:additional_job_options]
|
20
21
|
})
|
21
22
|
@@folder_name = :program_name
|
22
23
|
@@folder_name = :job_name if options[:key_name]
|
@@ -76,8 +77,10 @@ class Stack
|
|
76
77
|
line.gsub!(/\s/,'')
|
77
78
|
pairs = line.split(',')
|
78
79
|
pairs.each do |pair|
|
79
|
-
pair =~ /(.+)=(.+)/
|
80
|
-
variable_type[$1] = $2
|
80
|
+
#pair =~ /(.+)=(.+)/
|
81
|
+
#variable_type[$1] = $2
|
82
|
+
var, value = pair.split('=', 2)
|
83
|
+
variable_type[var] = value
|
81
84
|
end
|
82
85
|
end
|
83
86
|
end
|
@@ -297,7 +300,7 @@ class Stack
|
|
297
300
|
end
|
298
301
|
file.puts '}'
|
299
302
|
file.close
|
300
|
-
system('dot -
|
303
|
+
system('dot -Tpdf '+name+representation_type+'.dot -o '+name+representation_type+'.pdf')
|
301
304
|
end
|
302
305
|
|
303
306
|
end
|
data/lib/autoflow/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: autoflow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pedro Seoane
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-03-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: net-ssh
|
@@ -30,56 +30,70 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 0.8.1
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 0.8.1
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: colorize
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: 0.7.3
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 0.7.3
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: terminal-table
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 2.0.0
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: 2.0.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: openssl
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.2.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.2.0
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: bundler
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
72
86
|
requirements:
|
73
|
-
- - "
|
87
|
+
- - ">="
|
74
88
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
89
|
+
version: 2.2.7
|
76
90
|
type: :development
|
77
91
|
prerelease: false
|
78
92
|
version_requirements: !ruby/object:Gem::Requirement
|
79
93
|
requirements:
|
80
|
-
- - "
|
94
|
+
- - ">="
|
81
95
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
96
|
+
version: 2.2.7
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: rake
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -131,7 +145,7 @@ homepage: ''
|
|
131
145
|
licenses:
|
132
146
|
- MIT
|
133
147
|
metadata: {}
|
134
|
-
post_install_message:
|
148
|
+
post_install_message:
|
135
149
|
rdoc_options: []
|
136
150
|
require_paths:
|
137
151
|
- lib
|
@@ -146,9 +160,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
146
160
|
- !ruby/object:Gem::Version
|
147
161
|
version: '0'
|
148
162
|
requirements: []
|
149
|
-
|
150
|
-
|
151
|
-
signing_key:
|
163
|
+
rubygems_version: 3.2.3
|
164
|
+
signing_key:
|
152
165
|
specification_version: 4
|
153
166
|
summary: '"This gem take a pipeline and launch it on a queue system"'
|
154
167
|
test_files:
|