#!/usr/bin/env ruby require 'rbbt/util/simpleopt' require 'rbbt/workflow' require 'rbbt/workflow/usage' YAML::ENGINE.yamler = 'syck' if defined? YAML::ENGINE and YAML::ENGINE.respond_to? :yamler def usage(workflow = nil, task = nil, error = nil) puts SOPT.doc puts "## WORKFLOW" puts if workflow.nil? puts "No workflow specified" exit -1 end if task.nil? workflow.load_tasks if workflow.respond_to? :load_tasks workflow.doc else puts workflow.to_s puts "=" * workflow.to_s.length puts puts workflow.workflow_description puts workflow.doc(task) if error puts puts "Error: " << error end end exit 0 end def SOPT_options(workflow, task) sopt_options = [] workflow.rec_inputs(task.name).each do |name| short = name.to_s.chars.first boolean = workflow.rec_input_types(task.name)[name].to_sym == :boolean sopt_options << "-#{short}--#{name}*" end sopt_options * ":" end def fix_options(workflow, task, job_options) option_types = workflow.rec_input_types(task.name) job_options_cleaned = {} job_options.each do |name, value| value = case option_types[name].to_sym when :boolean %w(true TRUE T yes).include? value when :float value.to_f when :integer value.to_i when :string, :text case when value == '-' STDIN.read when (String === value and File.exists?(value) and not File.directory?(value)) Open.read(value) else value end when :array if Array === value value else str = case when value == '-' STDIN.read when (String === value and File.exists?(value)) Open.read(value) else value end if $array_separator str.split(/#{$array_separator}/) else str.split(/[,|\s]/) end end when :tsv case value when TSV value when '-' TSV.open(STDIN) else TSV.open(value) end else value end job_options_cleaned[name] = value end job_options_cleaned end options = SOPT.get <<EOF -h--help Show this help: -as--array_separator* Change the character that separates elements of Arrays, ',', '|', or '\\n' by default: -cl--clean Clean the last step of the job so that it gets recomputed: -rcl--recursive_clean Clean the last step and its dependencies to recompute the job completely: -jn--jobname* Job name to use. The name 'Default' is used by default: -pn--printname Print the name of the job and exit without starting it: EOF workflow = ARGV.shift usage if workflow.nil? task = ARGV.shift # Set log, fork, clean, recursive_clean and help help = !!options.delete(:help) do_fork = !!options.delete(:fork) do_exec = !!options.delete(:exec) clean = !!options.delete(:clean) recursive_clean = !!options.delete(:recursive_clean) $array_separator = options.delete(:array_separator) # Get workflow if Rbbt.etc.remote_workflows.exists? remote_workflows = Rbbt.etc.remote_workflows.yaml else remote_workflows = {} end if remote_workflows.include? workflow require 'rbbt/rest/client' workflow = WorkflowRESTClient.new remote_workflows[workflow], workflow else Workflow.require_workflow workflow workflow = Workflow.workflows.select{|mod| Misc.snake_case(mod.to_s) == Misc.snake_case(workflow)}.first workflow = Workflow.workflows.last if workflow.nil? end # Set task namespace = nil, nil case when task.nil? usage workflow when (task =~ /\./) namespace, task = options.delete(:task).split('.') namespace = Misc.string2const(namespace) else task_name = task.to_sym task = workflow.tasks[task_name] raise "Task not found: #{ task_name }" if task.nil? end usage workflow, task if help name = options.delete(:jobname) || "Default" # get job args sopt_option_string = SOPT_options(workflow, task) job_options = SOPT.get sopt_option_string job_options = fix_options(workflow, task, job_options) #- get job job = workflow.job(task.name, name, job_options) # clean job if clean and job.done? != false job.clean sleep 1 job = workflow.job(task.name, name, job_options) end if recursive_clean and job.done? job.recursive_clean sleep 1 job = workflow.job(task.name, name, job_options) end # run begin if do_exec res = job.exec case when Array === res puts res * "\n" when TSV === res puts res when Hash === res puts res.to_yaml else puts res end exit 0 end if do_fork job.fork while not job.done? Log.debug "#{job.step}: #{job.messages.last}" sleep 2 end raise job.messages.last if job.error? else res = job.run(true) end if options.delete(:printname) puts job.name exit 0 else Log.low "Job name: #{job.name}" end rescue ParameterException usage(workflow, task, $!.message) end if Step === res puts Open.read(res.path) if File.exists? res.path else puts res end exit 0