rbbt-util 5.32.26 → 5.33.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rbbt/annotations/annotated_array.rb +4 -0
  3. data/lib/rbbt/annotations/util.rb +29 -0
  4. data/lib/rbbt/entity.rb +3 -1
  5. data/lib/rbbt/hpc/orchestrate/batches.rb +152 -0
  6. data/lib/rbbt/hpc/orchestrate/chains.rb +173 -0
  7. data/lib/rbbt/hpc/orchestrate/rules.rb +70 -0
  8. data/lib/rbbt/hpc/orchestrate.old.rb +220 -0
  9. data/lib/rbbt/hpc/orchestrate.rb +24 -200
  10. data/lib/rbbt/hpc/slurm.rb +1 -0
  11. data/lib/rbbt/persist/tsv/adapter.rb +25 -0
  12. data/lib/rbbt/persist/tsv.rb +1 -1
  13. data/lib/rbbt/persist.rb +6 -4
  14. data/lib/rbbt/resource/path.rb +4 -0
  15. data/lib/rbbt/tsv/util.rb +12 -1
  16. data/lib/rbbt/util/concurrency/processes.rb +2 -1
  17. data/lib/rbbt/util/log.rb +6 -2
  18. data/lib/rbbt/util/migrate.rb +6 -1
  19. data/lib/rbbt/util/misc/inspect.rb +4 -1
  20. data/lib/rbbt/util/misc.rb +5 -0
  21. data/lib/rbbt/util/python.rb +1 -1
  22. data/lib/rbbt/workflow/definition.rb +1 -1
  23. data/lib/rbbt/workflow/examples.rb +0 -65
  24. data/lib/rbbt/workflow/integration/nextflow.rb +74 -14
  25. data/lib/rbbt/workflow/step/accessor.rb +5 -71
  26. data/lib/rbbt/workflow/step/dependencies.rb +8 -2
  27. data/lib/rbbt/workflow/step/info.rb +1 -1
  28. data/lib/rbbt/workflow/step/run.rb +1 -1
  29. data/lib/rbbt/workflow/step/save_load_inputs.rb +179 -0
  30. data/lib/rbbt/workflow/step.rb +2 -1
  31. data/lib/rbbt/workflow/task.rb +2 -2
  32. data/lib/rbbt/workflow/util/orchestrator.rb +11 -2
  33. data/lib/rbbt/workflow.rb +9 -2
  34. data/share/rbbt_commands/hpc/tail +0 -13
  35. data/share/rbbt_commands/lsf/tail +0 -13
  36. data/share/rbbt_commands/slurm/tail +0 -13
  37. data/share/rbbt_commands/tsv/keys +14 -15
  38. data/share/rbbt_commands/tsv/read_excel +2 -2
  39. data/share/rbbt_commands/workflow/task +15 -5
  40. data/test/rbbt/annotations/test_util.rb +11 -0
  41. data/test/rbbt/hpc/orchestrate/test_batches.rb +113 -0
  42. data/test/rbbt/hpc/orchestrate/test_chains.rb +139 -0
  43. data/test/rbbt/hpc/orchestrate/test_rules.rb +92 -0
  44. data/test/rbbt/hpc/test_orchestrate.rb +144 -0
  45. data/test/rbbt/util/test_misc.rb +4 -0
  46. data/test/rbbt/workflow/step/test_dependencies.rb +14 -13
  47. data/test/rbbt/workflow/step/test_save_load_inputs.rb +46 -0
  48. metadata +17 -2
@@ -44,7 +44,7 @@ class Step
44
44
  end
45
45
 
46
46
  def self.files_dir(path)
47
- path.nil? ? nil : path + '.files'
47
+ path.nil? ? nil : Path.setup(path + '.files')
48
48
  end
49
49
 
50
50
  def self.info_file(path)
@@ -86,76 +86,6 @@ class Step
86
86
  end
87
87
  end
88
88
 
89
- def self.save_inputs(inputs, input_types, dir)
90
- inputs.each do |name,value|
91
- type = input_types[name]
92
- type = type.to_s if type
93
- path = File.join(dir, name.to_s)
94
-
95
- Log.debug "Saving job input #{name} (#{type}) into #{path}"
96
- case
97
- when Step === value
98
- Open.ln_s(value.path, path)
99
- when type.to_s == "file"
100
- if String === value && File.exists?(value)
101
- value = File.expand_path(value)
102
- Open.ln_s(value, path)
103
- else
104
- value = value.collect{|v| v = "#{v}" if Path === v; v }if Array === value
105
- value = "#{value}" if Path === value
106
- Open.write(path + '.yaml', value.to_yaml)
107
- end
108
- when Array === value
109
- Open.write(path, value.collect{|v| Step === v ? v.path : v.to_s} * "\n")
110
- when IO === value
111
- if value.filename && String === value.filename && File.exists?(value.filename)
112
- Open.ln_s(value.filename, path)
113
- else
114
- Open.write(path, value)
115
- end
116
- else
117
- Open.write(path, value.to_s)
118
- end
119
- end.any?
120
- end
121
-
122
- def self.save_job_inputs(job, dir, options = nil)
123
- options = IndiferentHash.setup options.dup if options
124
-
125
- task_name = Symbol === job.overriden ? job.overriden : job.task_name
126
- workflow = job.workflow
127
- workflow = Kernel.const_get workflow if String === workflow
128
- if workflow
129
- task_info = IndiferentHash.setup(workflow.task_info(task_name))
130
- input_types = IndiferentHash.setup(task_info[:input_types])
131
- task_inputs = IndiferentHash.setup(task_info[:inputs])
132
- input_defaults = IndiferentHash.setup(task_info[:input_defaults])
133
- else
134
- task_info = IndiferentHash.setup({})
135
- input_types = IndiferentHash.setup({})
136
- task_inputs = IndiferentHash.setup({})
137
- input_defaults = IndiferentHash.setup({})
138
- end
139
-
140
- inputs = IndiferentHash.setup({})
141
- real_inputs = job.real_inputs || job.info[:real_inputs]
142
- job.recursive_inputs.zip(job.recursive_inputs.fields).each do |value,name|
143
- next unless task_inputs.include? name.to_sym
144
- next unless real_inputs.include? name.to_sym
145
- next if options && ! options.include?(name)
146
- next if value.nil?
147
- next if input_defaults[name] == value
148
- inputs[name] = value
149
- end
150
-
151
- if options && options.include?('override_dependencies')
152
- inputs.merge!(:override_dependencies => open[:override_dependencies])
153
- input_types = IndiferentHash.setup(input_types.merge(:override_dependencies => :array))
154
- end
155
- save_inputs(inputs, input_types, dir)
156
-
157
- inputs.keys
158
- end
159
89
 
160
90
  def name
161
91
  @name ||= path.sub(/.*\/#{Regexp.quote task_name.to_s}\/(.*)/, '\1')
@@ -224,8 +154,12 @@ class Step
224
154
  value = Annotated.purge value if defined? Annotated
225
155
  Open.lock(info_file, :lock => info_lock) do
226
156
  i = info(false).dup
157
+ value = Annotated.purge(value)
158
+
227
159
  i[key] = value
160
+
228
161
  dump = Step.serialize_info(i)
162
+
229
163
  @info_cache = IndiferentHash.setup(i)
230
164
  Misc.sensiblewrite(info_file, dump, :force => true, :lock => false) if Open.exists?(info_file)
231
165
  @info_cache_time = Time.now
@@ -254,7 +254,12 @@ class Step
254
254
  when :bootstrap
255
255
  cpus = rest.nil? ? nil : rest.first
256
256
 
257
- cpus = config('dep_cpus', 'bootstrap', :default => [5, list.length / 2].min) if cpus.nil? || cpus.to_i == 0
257
+ if cpus.nil?
258
+ keys = ['bootstrap'] + list.collect{|d| [d.task_name, d.task_signature] }.flatten.uniq
259
+ cpus = config('dep_cpus', *keys, :default => [5, list.length / 2].min)
260
+ elsif Symbol === cpus
261
+ cpus = config('dep_cpus', cpus, :default => [5, list.length / 2].min)
262
+ end
258
263
 
259
264
  respawn = rest && rest.include?(:respawn)
260
265
  respawn = false if rest && rest.include?(:norespawn)
@@ -369,7 +374,8 @@ class Step
369
374
  next unless step.dependencies and step.dependencies.any?
370
375
  (step.dependencies + step.input_dependencies).each do |step_dep|
371
376
  next unless step.dependencies.include?(step_dep)
372
- next if step_dep.done? or step_dep.running? or (ComputeDependency === step_dep and (step_dep.compute == :nodup or step_dep.compute == :ignore))
377
+ next if step_dep.done? or step_dep.running? or
378
+ (ComputeDependency === step_dep and (step_dep.compute == :nodup or step_dep.compute == :ignore))
373
379
  dep_step[step_dep.path] ||= []
374
380
  dep_step[step_dep.path] << step
375
381
  end
@@ -101,7 +101,7 @@ class Step
101
101
  seen = []
102
102
  while path = deps.pop
103
103
  dep_info = archived_info[path]
104
- if dep_info
104
+ if Hash === dep_info
105
105
  dep_info[:inputs].each do |k,v|
106
106
  all_inputs[k] = v unless all_inputs.include?(k)
107
107
  end if dep_info[:inputs]
@@ -419,7 +419,7 @@ class Step
419
419
  set_info :dependencies, dependencies.collect{|dep| [dep.task_name, dep.name, dep.path]}
420
420
 
421
421
  config_keys = Rbbt::Config::GOT_KEYS[config_keys_pre.length..-1]
422
- set_info :config_keys, config_keys
422
+ set_info :config_keys, config_keys.uniq
423
423
 
424
424
  if result.nil? && File.exists?(self.tmp_path) && ! File.exists?(self.path)
425
425
  Open.mv self.tmp_path, self.path
@@ -0,0 +1,179 @@
1
+ module Workflow
2
+ def self.load_inputs(dir, input_names, input_types)
3
+ inputs = {}
4
+ if File.exists?(dir) && ! File.directory?(dir)
5
+ Log.debug "Loading inputs from #{dir}, not a directory trying as tar.gz"
6
+ tarfile = dir
7
+ digest = CMD.cmd("md5sum '#{tarfile}'").read.split(" ").first
8
+ tmpdir = Rbbt.tmp.input_bundle[digest].find
9
+ Misc.untar(tarfile, tmpdir) unless File.exists? tmpdir
10
+ files = tmpdir.glob("*")
11
+ if files.length == 1 && File.directory?(files.first)
12
+ tmpdir = files.first
13
+ end
14
+ load_inputs(tmpdir, input_names, input_types)
15
+ else
16
+ dir = Path.setup(dir.dup)
17
+ input_names.each do |input|
18
+ file = dir[input].find
19
+ file = dir.glob(input.to_s + ".*").reject{|f| f =~ /\.md5$/}.first if file.nil? or not (File.symlink?(file) || file.exists?)
20
+ Log.debug "Trying #{ input }: #{file}"
21
+ next unless file and (File.symlink?(file) || file.exists?)
22
+
23
+ type = input_types[input]
24
+
25
+ type = :io if file.split(".").last == 'as_io'
26
+
27
+ type = :path if file.split(".").last == 'as_path'
28
+
29
+ type = :nofile if file.split(".").last == 'nofile'
30
+
31
+ case type
32
+ when :nofile
33
+ inputs[input.to_sym] = Open.realpath(file)
34
+ when :path
35
+ inputs[input.to_sym] = Open.realpath(Open.read(file).strip)
36
+ when :io
37
+ inputs[input.to_sym] = Open.open(Open.realpath(file))
38
+ when :file, :binary
39
+ Log.debug "Pointing #{ input } to #{file}"
40
+ if file =~ /\.yaml/
41
+ inputs[input.to_sym] = YAML.load(Open.read(file))
42
+ else
43
+ if File.symlink?(file)
44
+ link_target = File.expand_path(File.readlink(file), File.dirname(file))
45
+ inputs[input.to_sym] = link_target
46
+ else
47
+ inputs[input.to_sym] = Open.realpath(file)
48
+ end
49
+ end
50
+ when :text
51
+ Log.debug "Reading #{ input } from #{file}"
52
+ inputs[input.to_sym] = Open.read(file)
53
+ when :array
54
+ Log.debug "Reading array #{ input } from #{file}"
55
+ inputs[input.to_sym] = Open.read(file).split("\n")
56
+ when :tsv
57
+ Log.debug "Opening tsv #{ input } from #{file}"
58
+ inputs[input.to_sym] = TSV.open(file)
59
+ when :boolean
60
+ inputs[input.to_sym] = (file.read.strip == 'true')
61
+ else
62
+ Log.debug "Loading #{ input } from #{file}"
63
+ inputs[input.to_sym] = file.read.strip
64
+ end
65
+
66
+ end
67
+ inputs = IndiferentHash.setup(inputs)
68
+
69
+ dir.glob("*#*").each do |od|
70
+ name = File.basename(od)
71
+ value = Open.read(od)
72
+ Log.debug "Loading override dependency #{ name } as #{value}"
73
+ inputs[name] = value.chomp
74
+ end
75
+
76
+ inputs
77
+ end
78
+ end
79
+
80
+ def task_inputs_from_directory(task_name, directory)
81
+ task_info = self.task_info(task_name)
82
+ Workflow.load_inputs(directory, task_info[:inputs], task_info[:input_types])
83
+ end
84
+
85
+ def job_for_directory_inputs(task_name, directory, jobname = nil)
86
+ inputs = task_inputs_from_directory(task_name, directory)
87
+ job(task_name, jobname, inputs)
88
+ end
89
+
90
+ end
91
+
92
+ class Step
93
+ def self.save_inputs(inputs, input_types, input_options, dir)
94
+ inputs.each do |name,value|
95
+ type = input_types[name]
96
+ type = type.to_s if type
97
+ path = File.join(dir, name.to_s)
98
+
99
+ path = path + '.as_io' if (IO === value || Step === value) && ! (input_options[name] && input_options[name][:nofile])
100
+ Log.debug "Saving job input #{name} (#{type}) into #{path}"
101
+
102
+ case
103
+ when IO === value
104
+ Open.write(path, value.to_s)
105
+ when Step === value
106
+ Open.ln_s(value.path, path)
107
+ when type.to_s == "binary"
108
+ if String === value && File.exists?(value)
109
+ value = File.expand_path(value)
110
+ Open.ln_s(value, path)
111
+ elsif String === value && Misc.is_filename?(value, false)
112
+ Open.write(path + '.as_path' , value)
113
+ else
114
+ Open.write(path, value, :mode => 'wb')
115
+ end
116
+ when type.to_s == "file"
117
+ if String === value && File.exists?(value)
118
+ value = File.expand_path(value)
119
+ Open.ln_s(value, path)
120
+ else
121
+ value = value.collect{|v| v = "#{v}" if Path === v; v } if Array === value
122
+ value = "#{value}" if Path === value
123
+ Open.write(path + '.yaml', value.to_yaml)
124
+ end
125
+ when Array === value
126
+ Open.write(path, value.collect{|v| Step === v ? v.path : v.to_s} * "\n")
127
+ when IO === value
128
+ if value.filename && String === value.filename && File.exists?(value.filename)
129
+ Open.ln_s(value.filename, path)
130
+ else
131
+ Open.write(path, value)
132
+ end
133
+ else
134
+ Open.write(path, value.to_s)
135
+ end
136
+ end.any?
137
+ end
138
+
139
+ def self.save_job_inputs(job, dir, options = nil)
140
+ options = IndiferentHash.setup options.dup if options
141
+
142
+ task_name = Symbol === job.overriden ? job.overriden : job.task_name
143
+ workflow = job.workflow
144
+ workflow = Kernel.const_get workflow if String === workflow
145
+ if workflow
146
+ task_info = IndiferentHash.setup(workflow.task_info(task_name))
147
+ input_types = IndiferentHash.setup(task_info[:input_types])
148
+ input_options = IndiferentHash.setup(task_info[:input_options])
149
+ task_inputs = IndiferentHash.setup(task_info[:inputs])
150
+ input_defaults = IndiferentHash.setup(task_info[:input_defaults])
151
+ else
152
+ task_info = IndiferentHash.setup({})
153
+ input_types = IndiferentHash.setup({})
154
+ task_inputs = IndiferentHash.setup({})
155
+ task_options = IndiferentHash.setup({})
156
+ input_defaults = IndiferentHash.setup({})
157
+ end
158
+
159
+ inputs = IndiferentHash.setup({})
160
+ real_inputs = job.real_inputs || job.info[:real_inputs]
161
+ job.recursive_inputs.zip(job.recursive_inputs.fields).each do |value,name|
162
+ next unless task_inputs.include? name.to_sym
163
+ next unless real_inputs.include? name.to_sym
164
+ next if options && ! options.include?(name)
165
+ next if value.nil?
166
+ next if input_defaults[name] == value
167
+ inputs[name] = value
168
+ end
169
+
170
+ if options && options.include?('override_dependencies')
171
+ inputs.merge!(:override_dependencies => open[:override_dependencies])
172
+ input_types = IndiferentHash.setup(input_types.merge(:override_dependencies => :array))
173
+ end
174
+
175
+ save_inputs(inputs, input_types, input_options, dir)
176
+
177
+ inputs.keys
178
+ end
179
+ end
@@ -6,6 +6,7 @@ require 'rbbt/workflow/step/accessor'
6
6
  require 'rbbt/workflow/step/prepare'
7
7
  require 'rbbt/workflow/step/status'
8
8
  require 'rbbt/workflow/step/info'
9
+ require 'rbbt/workflow/step/save_load_inputs'
9
10
 
10
11
  class Step
11
12
  attr_accessor :clean_name, :path, :task, :workflow, :inputs, :dependencies, :bindings
@@ -321,7 +322,7 @@ class Step
321
322
  def load
322
323
  res = begin
323
324
  @result = nil if IO === @result && @result.closed?
324
- if @result && @path != @result
325
+ if @result && @path != @result && ! StreamArray === @result
325
326
  res = @result
326
327
  else
327
328
  join if not done?
@@ -90,11 +90,11 @@ module Task
90
90
 
91
91
  maps = (Array === dep and Hash === dep.last) ? dep.last.keys : []
92
92
  raise "Dependency task not found: #{dep}" if task.nil?
93
- next if seen.include? [wf, task.name]
93
+ next if seen.include? [wf, task.name, maps]
94
94
 
95
95
  task.workflow = wf if wf
96
96
 
97
- seen << [wf, task.name]
97
+ seen << [wf, task.name, maps]
98
98
  new_inputs = task.inputs - maps
99
99
  next unless new_inputs.any?
100
100
  if task_inputs[task].nil?
@@ -65,7 +65,10 @@ module Workflow
65
65
 
66
66
  IndiferentHash.setup(resources)
67
67
 
68
- default_resources = rules["default_resources"] || rules["defaults"]["resources"]
68
+ default_resources = rules["default_resources"]
69
+ default_resources ||= rules["defaults"]["resources"] if rules["defaults"]
70
+ default_resources ||= {}
71
+
69
72
  default_resources.each{|k,v| resources[k] ||= v } if default_resources
70
73
 
71
74
  resources
@@ -98,6 +101,10 @@ module Workflow
98
101
  candidates
99
102
  end
100
103
 
104
+ def self.process(*args)
105
+ self.new.process(*args)
106
+ end
107
+
101
108
  attr_accessor :available_resources, :resources_requested, :resources_used, :timer
102
109
 
103
110
  def initialize(timer = 5, available_resources = {})
@@ -176,7 +183,9 @@ module Workflow
176
183
  end
177
184
  end
178
185
 
179
- def process(rules, jobs)
186
+ def process(rules, jobs = nil)
187
+ jobs, rules = rules, {} if jobs.nil?
188
+ jobs = [jobs] if Step === jobs
180
189
  begin
181
190
 
182
191
  workload = Orchestrator.workload(jobs)
data/lib/rbbt/workflow.rb CHANGED
@@ -244,7 +244,7 @@ module Workflow
244
244
  when :hash
245
245
  clean_inputs = Annotated.purge(inputs)
246
246
  clean_inputs = clean_inputs.collect{|i| Symbol === i ? i.to_s : i }
247
- deps_str = dependencies.collect{|d| (Step === d || (defined?(RemoteStep) && RemoteStep === Step)) ? "Step: " << (d.overriden? ? d.path : d.short_path) : d }
247
+ deps_str = dependencies.collect{|d| (Step === d || (defined?(RemoteStep) && RemoteStep === Step)) ? "Step: " << (Symbol === d.overriden ? d.path : d.short_path) : d }
248
248
  key_obj = {:inputs => clean_inputs, :dependencies => deps_str }
249
249
  key_str = Misc.obj2str(key_obj)
250
250
  hash_str = Misc.digest(key_str)
@@ -465,7 +465,14 @@ module Workflow
465
465
  extension = nil
466
466
  if dependencies.any?
467
467
  dep_basename = File.basename(dependencies.last.path)
468
- extension = dep_basename.split(".").last if dep_basename.include?('.')
468
+ if dep_basename.include? "."
469
+ parts = dep_basename.split(".")
470
+ extension = [parts.pop]
471
+ while parts.last.length <= 4
472
+ extension << parts.pop
473
+ end
474
+ extension = extension.reverse * "."
475
+ end
469
476
  end
470
477
  end
471
478
 
@@ -13,19 +13,6 @@ Queue a job in Marenostrum
13
13
  $ rbbt slurm tail <directory> [options]
14
14
 
15
15
  -h--help Print this help
16
- -d--done Done jobs only
17
- -e--error Error jobs only
18
- -a--aborted SLURM aboted jobs
19
- -r--running Running jobs only
20
- -q--queued Queued jobs only
21
- -j--job* Job ids
22
- -s--search* Regular expression
23
- -t--tail* Show the last lines of the STDERR
24
- -p--progress Report progress of job and the dependencies
25
- -SBP--sbatch_parameters show sbatch parameters
26
- -PERF--procpath_performance show Procpath performance summary
27
- -sacct--sacct_peformance show sacct performance summary
28
- -bs--batch_system* Batch system to use: auto, lsf, slurm (default is auto-detect)
29
16
  EOF
30
17
 
31
18
  if options[:help]
@@ -13,19 +13,6 @@ Queue a job in Marenostrum
13
13
  $ rbbt slurm tail <directory> [options]
14
14
 
15
15
  -h--help Print this help
16
- -d--done Done jobs only
17
- -e--error Error jobs only
18
- -a--aborted SLURM aboted jobs
19
- -r--running Running jobs only
20
- -q--queued Queued jobs only
21
- -j--job* Job ids
22
- -s--search* Regular expression
23
- -t--tail* Show the last lines of the STDERR
24
- -p--progress Report progress of job and the dependencies
25
- -SBP--sbatch_parameters show sbatch parameters
26
- -PERF--procpath_performance show Procpath performance summary
27
- -sacct--sacct_peformance show sacct performance summary
28
- -bs--batch_system* Batch system to use: auto, lsf, slurm (default is auto-detect)
29
16
  EOF
30
17
 
31
18
  if options[:help]
@@ -13,19 +13,6 @@ Queue a job in Marenostrum
13
13
  $ rbbt slurm tail <directory> [options]
14
14
 
15
15
  -h--help Print this help
16
- -d--done Done jobs only
17
- -e--error Error jobs only
18
- -a--aborted SLURM aboted jobs
19
- -r--running Running jobs only
20
- -q--queued Queued jobs only
21
- -j--job* Job ids
22
- -s--search* Regular expression
23
- -t--tail* Show the last lines of the STDERR
24
- -p--progress Report progress of job and the dependencies
25
- -SBP--sbatch_parameters show sbatch parameters
26
- -PERF--procpath_performance show Procpath performance summary
27
- -sacct--sacct_peformance show sacct performance summary
28
- -bs--batch_system* Batch system to use: auto, lsf, slurm (default is auto-detect)
29
16
  EOF
30
17
 
31
18
  if options[:help]
@@ -41,19 +41,18 @@ parser = TSV::Parser.new TSV.get_stream(file), options.merge(:fields => [])
41
41
 
42
42
  options[:merge] = false if options[:merge] == "false"
43
43
 
44
- Thread.new do
45
- line = parser.first_line
46
- bar = Log::ProgressBar.new
47
- while line
48
- bar.tick
49
-
50
- line = Misc.fixutf8(line)
51
- line = parser.process line
52
- raise SKIP_LINE if line.empty?
53
- parts = parser.chop_line line
54
- key, values = parser.get_values parts
55
- values = parser.cast_values values if parser.cast?
56
-
57
- puts key
58
- end
44
+ line = parser.first_line
45
+ bar = Log::ProgressBar.new
46
+ while line
47
+ bar.tick
48
+
49
+ line = Misc.fixutf8(line)
50
+ line = parser.process line
51
+ raise SKIP_LINE if line.empty?
52
+ parts = parser.chop_line line
53
+ key, values = parser.get_values parts
54
+ values = parser.cast_values values if parser.cast?
55
+
56
+ puts key
57
+ line = parser.stream.gets
59
58
  end
@@ -22,7 +22,7 @@ Use - to read from STDIN
22
22
  -h--help Print this help
23
23
  -s--sheet* Sheet to extract
24
24
  -skip--skip_rows* Initial rows to skip
25
-
25
+ -o--original Dump the rows without parsing them into TSV
26
26
  EOF
27
27
  if options[:help]
28
28
  if defined? rbbt_usage
@@ -39,5 +39,5 @@ raise ParameterException, "No excel file given" if excelfile.nil?
39
39
 
40
40
  options[:zipped] ||= true if options[:merge]
41
41
  require 'rbbt/tsv/excel'
42
- puts TSV.excel(excelfile, options).to_s
42
+ puts TSV.excel(excelfile, options.merge(:text => options[:original]))
43
43
 
@@ -104,7 +104,7 @@ def fix_options(workflow, task, job_options)
104
104
  elsif input_options[name] and input_options[name][:stream] and value == "-"
105
105
  STDIN
106
106
  else
107
- if Array === value
107
+ if Array === value || IO === value
108
108
  value
109
109
  else
110
110
  array_separator = $array_separator
@@ -137,6 +137,8 @@ def fix_options(workflow, task, job_options)
137
137
  TSV.open(STDIN, :unnamed => true, :sep => $field_separator, :sep2 => ($array_separator || "|"))
138
138
  when (Misc.is_filename?(value) and String)
139
139
  TSV.open(value, :unnamed => true, :sep => $field_separator, :sep2 => ($array_separator || "|"))
140
+ when IO
141
+ TSV.open(value, :unnamed => true, :sep => $field_separator, :sep2 => ($array_separator || "|"))
140
142
  else
141
143
  TSV.open(StringIO.new(value), :unnamed => true, :sep => $field_separator, :sep2 => ($array_separator || "|"))
142
144
  end
@@ -189,6 +191,7 @@ The `recursive_clean` cleans all the job dependency steps recursively.
189
191
  -rcl--recursive_clean Clean the last step and its dependencies to recompute the job completely
190
192
  -uaj--update_all_jobs Consider all dependencies when checking for updates, even when they have no info files
191
193
  --fork Run job asyncronously and monitor progress. It monitors detached processes as well
194
+ --orchestrate Run the job through the orchestrator
192
195
  --detach Run job asyncronously and detach process
193
196
  --exec Run job with no persistence
194
197
  -O--output* Save job result into file
@@ -436,6 +439,9 @@ begin
436
439
  end
437
440
 
438
441
  job.fork
442
+ elsif options[:orchestrate]
443
+ require 'rbbt/workflow/util/orchestrator'
444
+ Workflow::Orchestrator.process job
439
445
  else
440
446
  job.run(:stream)
441
447
  res = job
@@ -571,10 +577,14 @@ when Step
571
577
  elsif detach
572
578
  exit! 0
573
579
  else
574
- res.join
575
- Open.open(res.path, :mode => 'rb') do |io|
576
- Misc.consume_stream(io, false, out)
577
- end if Open.exist?(res.path) || Open.remote?(res.path) || Open.ssh?(res.path)
580
+ if %w(float integer string boolean).include?(res.result_type.to_s)
581
+ out.puts res.load
582
+ else
583
+ res.join
584
+ Open.open(res.path, :mode => 'rb') do |io|
585
+ Misc.consume_stream(io, false, out)
586
+ end if Open.exist?(res.path) || Open.remote?(res.path) || Open.ssh?(res.path)
587
+ end
578
588
  end
579
589
  else
580
590
  if Array === res
@@ -1,6 +1,11 @@
1
1
  require File.join(File.expand_path(File.dirname(__FILE__)), '../..', 'test_helper.rb')
2
2
  require 'rbbt/annotations'
3
3
 
4
+ module TestEntityString
5
+ extend Entity
6
+ self.annotation :code
7
+ end
8
+
4
9
  class TestAnnotation < Test::Unit::TestCase
5
10
  def test_marshal
6
11
  a = "STRING"
@@ -9,5 +14,11 @@ class TestAnnotation < Test::Unit::TestCase
9
14
  assert !(Annotated === Marshal.load(Marshal.dump(a)))
10
15
  assert_equal a, Marshal.load(Marshal.dump(a))
11
16
  end
17
+
18
+ def test_hash
19
+ e = TestEntityString.setup("TEST", :code => 10)
20
+ assert_equal "TEST", Annotated.to_hash(e)[:literal]
21
+ assert_equal 10, Annotated.to_hash(e)[:info][:code]
22
+ end
12
23
  end
13
24