#!/usr/bin/env ruby $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib') $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'vendor') begin require 'trollop' require 'output_catcher' require 'pp' require 'etc' require 'log4r' rescue LoadError require 'rubygems' retry end require 'rpipe' STEPS = %w(recon preproc stats) VERSION_NUMBER = "0.0.0" VERSION_LINE = "rpipe %s WADRC Imaging Core" % VERSION_NUMBER BANNER = <<-EOS A utility for running neuroimaging rpipe jobs. Usage: rpipe [options] EOS # Main Function for the CLI runner. def run! options, driver = setup_options run_with_logging File.basename(driver, File.extname(driver)), options do $Log.info "Begin Pipelining #{driver} | #{Etc.getlogin} on #{`hostname`}" run_pipe(options, driver) $Log.info "Finished Pipelining #{driver}" end end # Perform Each of the Jobs in a Pipe def run_pipe(options, driver) pipe = RPipe.new(driver) pp pipe if options[:debug] if options[:only_given] case options[:only] when "recon" pipe.recon_jobs.each { |job| job.perform } when "preproc" pipe.preproc_jobs.each { |job| job.perform } when "stats" pipe.stats_jobs.each { |job| job.perform } end else pipe.recon_jobs.each { |job| job.perform } pipe.preproc_jobs.each { |job| job.perform } pipe.stats_jobs.each { |job| job.perform } end end # Setup Trollop Options def setup_options opts = Trollop::options do version VERSION_LINE banner BANNER opt :only, "Perform only a certain step (recon, preproc, stats)", :type => String opt :debug, "Be more wordy than usual for debugging" opt :log_directory, "Output Directory for processing logs.", :type => String end if opts[:only_given] unless STEPS.include?(opts[:only]) Trollop::die :only, "must be one of recon, preproc, or stats" end end Trollop::die "Driver file not given" if (ARGV.size < 1) driver = ARGV.shift Trollop::die "Driver file #{driver} does not exist. Check the path to that file and try again" unless File.exist?(driver) pp opts if opts[:debug] return opts, driver end # Setup Tee IO's for Out and Error and start logs for them. def run_with_logging(logfile_stem, options, &block) if options[:log_directory] log_dir = options[:log_directory] else # If no explicit directory has been passed as an argument, check to see if # a directory named "logs" exists. If so, use that, otherwise use the current directory. log_dir = File.directory?('logs') ? 'logs' : '.' end out_logfile = File.join(log_dir, logfile_stem + '.out') error_logfile = File.join(log_dir, logfile_stem + '.err') command_logfile = File.join(log_dir, logfile_stem + '.sh') teeout = Tee.new(out_logfile, :out, 'a') teeerr = Tee.new(error_logfile, :err, 'a') setup_runner_logger(command_logfile, teeout, teeerr, options) begin yield rescue Exception => e $ErrorLog.error e raise e ensure # Discard the error log if there were no errors. # Size returns nil for an empty file. teeerr.close File.delete(error_logfile) unless File.size?(error_logfile) end end # Log Commands to a file and Output to stdout def setup_runner_logger(command_logfile, teeout, teeerr, options) console_pattern = "#{'*' * 10} %m [ %d ]" $Log = Log4r::Logger.new('output') $Log.level = Log4r::DEBUG $Log.add Log4r::IOOutputter.new(:stdout, teeout, :formatter => FlashFormatter.new) $CommandLog = Log4r::Logger.new('command::output') $CommandLog.add Log4r::FileOutputter.new(:file, :filename => command_logfile, :trunc => false, :formatter => Log4r::PatternFormatter.new(:pattern => "%m")) $CommandLog.add Log4r::IOOutputter.new(:stdout, teeout, :formatter => FlashFormatter.new) $ErrorLog = Log4r::Logger.new('error::output') $ErrorLog.add Log4r::IOOutputter.new(:stderr, teeerr, :formatter => Log4r::PatternFormatter.new(:pattern => "%m")) end # Formatter for Logging class FlashFormatter < Log4r::Formatter # Easy-to-read formatting def format(logevent) buff = "\n" buff << "+" * 120 + "\n" buff << sprintf("\t%s\n", logevent.data) buff << sprintf("\t%s\n", Time.now) buff << "+" * 120 + "\n" buff << "\n" return buff end end # All that for this. run!