rbbt-util 5.37.16 → 5.38.0
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/hpc/batch.rb +15 -6
- data/lib/rbbt/hpc/orchestrate.rb +1 -0
- data/lib/rbbt/resource/path.rb +1 -0
- data/lib/rbbt/resource/rake.rb +1 -1
- data/lib/rbbt/util/misc/development.rb +8 -1
- data/lib/rbbt/util/misc/exceptions.rb +10 -0
- data/lib/rbbt/util/ssh.rb +65 -14
- data/lib/rbbt/workflow/remote_workflow/driver/ssh.rb +73 -13
- data/lib/rbbt/workflow/remote_workflow/remote_step/ssh.rb +12 -4
- data/lib/rbbt/workflow/step/run.rb +1 -1
- data/lib/rbbt/workflow/step/save_load_inputs.rb +5 -3
- data/lib/rbbt/workflow/step.rb +1 -1
- data/lib/rbbt/workflow/usage.rb +3 -3
- data/share/rbbt_commands/hpc/list +293 -293
- data/share/rbbt_commands/lsf/list +293 -293
- data/share/rbbt_commands/resource/find +1 -0
- data/share/rbbt_commands/slurm/list +293 -293
- data/share/rbbt_commands/workflow/task +9 -14
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: df9e238ba28f6bc0e16d1a22d8c9c34f7b57334f795ad9c4104ee1e689bc8fd5
         | 
| 4 | 
            +
              data.tar.gz: 61cc2c91be510161edde982567750f13abb2388cf624e15ca1e4c72633382a3b
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: a3528b56bfc0faebf62c701fcc637a43af8ffe0639a795859f56dca57749b60a3cd821941b7e7bf079cca27a9a8aa8d9d69f71235b41c1ff48e73b4292a31683
         | 
| 7 | 
            +
              data.tar.gz: dd71f1e7b233fb46d5e1210466bd6f64b0dd9162633d475f7e38bc8a057c853411bf27c35ffb3ce935f10b6e8d0055efdd7f5822adf09ff8f95a0bfa0efe8971
         | 
    
        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/resource/path.rb
    CHANGED
    
    
    
        data/lib/rbbt/resource/rake.rb
    CHANGED
    
    
| @@ -423,13 +423,20 @@ 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 | 
            +
                Log.debug "Run ssh script in #{server}:\n#{script}"
         | 
| 436 | 
            +
             | 
| 437 | 
            +
                SSHLine.ruby(server, script)
         | 
| 438 | 
            +
              end
         | 
| 439 | 
            +
             | 
| 433 440 | 
             
              def self.ssh_connection(server, reset = false)
         | 
| 434 441 | 
             
                @@ssh_connections ||= {}
         | 
| 435 442 | 
             
                @@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)
         | 
    
        data/lib/rbbt/util/ssh.rb
    CHANGED
    
    | @@ -1,25 +1,76 @@ | |
| 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 cmd(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 | 
            +
                @ch.send_data(cmd)
         | 
| 55 | 
            +
                @ch.send_data("echo DONECMD: $?\n")
         | 
| 56 | 
            +
                @ssh.loop{ !@complete_output }
         | 
| 57 | 
            +
                if @exit_status.to_i == 0
         | 
| 58 | 
            +
                  return @output
         | 
| 59 | 
            +
                else
         | 
| 60 | 
            +
                  raise SSHProcessFailed.new @host, "Ruby script:\n#{script}"
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
              end
         | 
| 25 63 |  | 
| 64 | 
            +
              @connections = {}
         | 
| 65 | 
            +
              def self.open(host, user = nil)
         | 
| 66 | 
            +
                @connections[[host, user]] ||= SSHLine.new host, user
         | 
| 67 | 
            +
              end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
              def self.run(server, cmd)
         | 
| 70 | 
            +
                open(server).cmd(cmd)
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              def self.ruby(server, script)
         | 
| 74 | 
            +
                open(server).ruby(script)
         | 
| 75 | 
            +
              end
         | 
| 76 | 
            +
            end
         | 
| @@ -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,40 @@ 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 | 
            -
                  job | 
| 231 | 
            -
             | 
| 232 | 
            -
             | 
| 227 | 
            +
                  job_list = [job] 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
         | 
| 245 | 
            +
                  iif all_deps
         | 
| 246 | 
            +
             | 
| 247 | 
            +
                  missing_deps = []
         | 
| 248 | 
            +
                  all_deps.each do |dep,jobs|
         | 
| 249 | 
            +
                    next if dep.done?
         | 
| 250 | 
            +
                    Log.medium "Producing #{dep.workflow}:#{dep.short_path} dependency for #{Misc.fingerprint jobs}"
         | 
| 251 | 
            +
                    dep.run(true)
         | 
| 252 | 
            +
                    missing_deps << dep
         | 
| 233 253 | 
             
                  end 
         | 
| 254 | 
            +
                  Step.wait_for_jobs missing_deps
         | 
| 234 255 |  | 
| 235 | 
            -
                  migrate_dependencies =  | 
| 236 | 
            -
                  migrate_dependencies  | 
| 237 | 
            -
                  Log.medium "Migrating #{migrate_dependencies.length} dependencies from #{job.path} to #{ server }" 
         | 
| 256 | 
            +
                  migrate_dependencies = all_deps.keys.select{|d| d.done? }.collect{|d| d.path }
         | 
| 257 | 
            +
                  Log.medium "Migrating #{migrate_dependencies.length} dependencies from #{Misc.fingerprint job_list} to #{ server }" 
         | 
| 238 258 | 
             
                  Step.migrate(migrate_dependencies, search_path, :target => server) if migrate_dependencies.any?
         | 
| 239 259 | 
             
                end
         | 
| 240 260 |  | 
| @@ -242,7 +262,6 @@ job.clean | |
| 242 262 | 
             
                  inputs = job.inputs.to_hash.slice(*job.real_inputs.map{|i| i.to_s})
         | 
| 243 263 | 
             
                  job.dependencies.each do |dep|
         | 
| 244 264 | 
             
                    next if dep.done?
         | 
| 245 | 
            -
                    iif [dep, dep.inputs, dep.real_inputs]
         | 
| 246 265 | 
             
                    inputs = dep.inputs.to_hash.slice(*dep.real_inputs.map{|i| i.to_s}).merge(inputs)
         | 
| 247 266 | 
             
                    inputs = missing_dep_inputs(dep).merge(inputs)
         | 
| 248 267 | 
             
                  end
         | 
| @@ -279,6 +298,47 @@ job.clean | |
| 279 298 | 
             
                  rjob
         | 
| 280 299 | 
             
                end
         | 
| 281 300 |  | 
| 301 | 
            +
                def self.relay_job_list(job_list, server, options = {})
         | 
| 302 | 
            +
                  migrate, produce, produce_dependencies, search_path, run_type, slurm_options = Misc.process_options options.dup,
         | 
| 303 | 
            +
                    :migrate, :produce, :produce_dependencies, :search_path, :run_type, :slurm_options
         | 
| 304 | 
            +
             | 
| 305 | 
            +
                  search_path ||= 'user'
         | 
| 306 | 
            +
             | 
| 307 | 
            +
                  produce = true if migrate
         | 
| 308 | 
            +
             | 
| 309 | 
            +
                  upload_dependencies(job_list, server, search_path, options[:produce_dependencies])
         | 
| 310 | 
            +
             | 
| 311 | 
            +
                  rjobs_job = job_list.collect do |job|
         | 
| 312 | 
            +
                    
         | 
| 313 | 
            +
                    workflow_name = job.workflow.to_s
         | 
| 314 | 
            +
                    remote_workflow = RemoteWorkflow.new("ssh://#{server}:#{workflow_name}", "#{workflow_name}")
         | 
| 315 | 
            +
                    inputs = job.recursive_inputs.to_hash.slice(*job.real_inputs.map{|i| i.to_s})
         | 
| 316 | 
            +
                    Log.medium "Relaying dependency #{job.workflow}:#{job.short_path} to #{server} (#{inputs.keys * ", "})"
         | 
| 317 | 
            +
             | 
| 318 | 
            +
                    rjob = remote_workflow.job(job.task_name.to_s, job.clean_name, inputs)
         | 
| 319 | 
            +
             | 
| 320 | 
            +
                    override_dependencies = job.rec_dependencies.select{|dep| dep.done? }.collect{|dep| [dep.workflow.to_s, dep.task_name.to_s] * "#" << "=" << Rbbt.identify(dep.path)}
         | 
| 321 | 
            +
                    rjob.override_dependencies = override_dependencies
         | 
| 322 | 
            +
             | 
| 323 | 
            +
                    rjob.run_type = run_type
         | 
| 324 | 
            +
                    rjob.slurm_options = slurm_options || {}
         | 
| 325 | 
            +
             | 
| 326 | 
            +
                    rjob.run(true)
         | 
| 327 | 
            +
             | 
| 328 | 
            +
                    [rjob, job]
         | 
| 329 | 
            +
                  end
         | 
| 330 | 
            +
             | 
| 331 | 
            +
                  if options[:migrate]
         | 
| 332 | 
            +
                    rjobs_job.each do |rjob,job|
         | 
| 333 | 
            +
                      rjob.produce
         | 
| 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)
         | 
| @@ -64,7 +64,7 @@ class RemoteStep | |
| 64 64 | 
             
                  RemoteWorkflow::SSH.orchestrate_slurm_job(File.join(base_url, task.to_s), @input_id, @base_name, @slurm_options || {})
         | 
| 65 65 | 
             
                end
         | 
| 66 66 |  | 
| 67 | 
            -
                def  | 
| 67 | 
            +
                def issue
         | 
| 68 68 | 
             
                  input_types = {}
         | 
| 69 69 | 
             
                  init_job
         | 
| 70 70 | 
             
                  @remote_path = case @run_type
         | 
| @@ -76,6 +76,10 @@ class RemoteStep | |
| 76 76 | 
             
                                   _orchestrate_slurm
         | 
| 77 77 | 
             
                                 end
         | 
| 78 78 | 
             
                  @started = true
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                def produce(*args)
         | 
| 82 | 
            +
                  issue
         | 
| 79 83 | 
             
                  while ! (done? || error? || aborted?)
         | 
| 80 84 | 
             
                    sleep 1
         | 
| 81 85 | 
             
                  end
         | 
| @@ -87,9 +91,13 @@ class RemoteStep | |
| 87 91 | 
             
                  load_res Open.open(path)
         | 
| 88 92 | 
             
                end
         | 
| 89 93 |  | 
| 90 | 
            -
                def run( | 
| 91 | 
            -
                   | 
| 92 | 
            -
             | 
| 94 | 
            +
                def run(stream = nil)
         | 
| 95 | 
            +
                  if stream
         | 
| 96 | 
            +
                    issue
         | 
| 97 | 
            +
                  else
         | 
| 98 | 
            +
                    produce
         | 
| 99 | 
            +
                    self.load unless args.first
         | 
| 100 | 
            +
                  end
         | 
| 93 101 | 
             
                end
         | 
| 94 102 |  | 
| 95 103 | 
             
                def clean
         | 
| @@ -247,7 +247,7 @@ class Step | |
| 247 247 | 
             
                      @exec = false
         | 
| 248 248 | 
             
                      init_info(true)
         | 
| 249 249 |  | 
| 250 | 
            -
                      workflow           = @workflow || @task.respond_to?(:workflow)  ?  @task.workflow : nil
         | 
| 250 | 
            +
                      #workflow           = @workflow || @task.respond_to?(:workflow)  ?  @task.workflow : nil
         | 
| 251 251 | 
             
                      result_type        = @task.respond_to?(:result_type)            ?  @task.result_type : nil
         | 
| 252 252 | 
             
                      result_description = @task.respond_to?(:result_description)     ?  @task.result_description : nil
         | 
| 253 253 |  | 
| @@ -67,9 +67,9 @@ module Workflow | |
| 67 67 | 
             
                      inputs[input.to_sym] = steps.first
         | 
| 68 68 | 
             
                    when :step_file
         | 
| 69 69 | 
             
                      path = Open.read(file).strip
         | 
| 70 | 
            -
                      path. | 
| 71 | 
            -
                       | 
| 72 | 
            -
                      path | 
| 70 | 
            +
                      step_path, relative = path.match(/(.*)\.files\/(.*)/).values_at 1, 2
         | 
| 71 | 
            +
                      step = Step.new Path.setup(step_path).find
         | 
| 72 | 
            +
                      path = step.file(relative)
         | 
| 73 73 | 
             
                      inputs[input.to_sym] = path
         | 
| 74 74 | 
             
                    when :step_file_array
         | 
| 75 75 | 
             
                      paths = Open.read(file).split("\n")
         | 
| @@ -149,6 +149,8 @@ class Step | |
| 149 149 | 
             
                case value
         | 
| 150 150 | 
             
                when Path
         | 
| 151 151 | 
             
                  if Step === value.resource
         | 
| 152 | 
            +
                    step = value.resource
         | 
| 153 | 
            +
                    value = File.join('var/jobs', step.workflow.to_s, step.short_path + '.files', Misc.path_relative_to(step.files_dir, value))
         | 
| 152 154 | 
             
                    path = path + '.as_step_file'
         | 
| 153 155 | 
             
                  else
         | 
| 154 156 | 
             
                    path = path + '.as_path'
         | 
    
        data/lib/rbbt/workflow/step.rb
    CHANGED
    
    
    
        data/lib/rbbt/workflow/usage.rb
    CHANGED
    
    | @@ -128,7 +128,7 @@ module Workflow | |
| 128 128 | 
             
                  break if child
         | 
| 129 129 |  | 
| 130 130 | 
             
                  if child
         | 
| 131 | 
            -
                    description << "-> | 
| 131 | 
            +
                    description << "->" << task_name.to_s
         | 
| 132 132 | 
             
                  elsif first
         | 
| 133 133 | 
             
                    description << "" << task_name.to_s
         | 
| 134 134 | 
             
                  else
         | 
| @@ -201,10 +201,10 @@ module Workflow | |
| 201 201 | 
             
                    description = description.split("\n\n").first
         | 
| 202 202 |  | 
| 203 203 | 
             
                    next if abridge && ! final.include?(name)
         | 
| 204 | 
            -
                    puts Misc.format_definition_list_item(name.to_s, description, Log.tty_size || 80,  | 
| 204 | 
            +
                    puts Misc.format_definition_list_item(name.to_s, description, Log.tty_size || 80, 30, :yellow)
         | 
| 205 205 |  | 
| 206 206 | 
             
                    prov_string = prov_string(dep_tree(name))
         | 
| 207 | 
            -
                    puts Misc.format_paragraph Log.color(:blue, "-> | 
| 207 | 
            +
                    puts Misc.format_paragraph Log.color(:blue, "->" + prov_string) if prov_string && ! prov_string.empty?
         | 
| 208 208 | 
             
                  end
         | 
| 209 209 |  | 
| 210 210 | 
             
                else
         |