module Ratch class BatchManager # Task cache, which prevents batch runs from re-executing. attr :cache # New BatchManager. def initialize @cache = {} end # def batch(batchfile, arguments=nil) @cache[batchfile] ||= run(batchfile, arguments) end # TODO How to handle arguments? def run(batchfile, arguments=nil) BatchFile.new(batchfile).call # # TODO probably should raise error instead # abort "missing batch file -- #{batchfile}" unless File.file?(batchfile) # script = File.read($0 = batchfile) # #instance_eval(script) # eval(script, binding, $0) end # def done?(batchfile) batchfile == $0 or @cache.key?(batchfile) end end # module Batchable # Reference batch manager. def batch_manager @batch_manager ||= BatchManager.new end # Batch run, ie. run and cache. # Usually this can be take care of by method_missing. # But, in some cases, built in method names block task # calls, so you have to use #batch to invoke those. def batch(batchfile, arguments=nil) batch_manager.batch(batchfile, arguments=nil) # why did I have task instead of batchfile before? end # Lauch a batch file (non-cached) def launch(batchfile, arguments=nil) batch_manager.run(batchfile, arguments=nil) end # Is a batch run complete or in the process of being completed? def done?(batchfile) batch_manager.done?(batchfile) end # Shell runner. # TODO Does this belong here? def sh(cmd) if noharm? puts cmd true else puts "--> system call: #{cmd}" if trace? system(cmd) end end # Abort running. #def abort(msg=nil) # puts msg if msg # exit 0 #end end # module OpenBatchable # If method is missing try to run an external task # or binary by that name. If it is a binary, arguments # translate into commandline parameters. For example: # # tar 'foo/', :x=>true, :v=>true, :z=>true, :f=>'foo.tar.gz' # # or # # tar '-xvzf', "foo.tar.gz", "foo/" # # becomes # # tar -x -v -z -f foo.tar.gz foo/ # # If it is a task, it will be cached. Tasks only ever run once. # To run them more than once you can manually execute them with #run. # Likewise you can manually run and cache by calling #batch. # This is good to know, b/c in some cases built in method names # block task calls, so you have to #batch to invoke them. def method_missing(sym,*args) puts "method_missing: #{sym}" if debug? name = sym.to_s task = task?(name) done = task && done?(task) cache = task && !done && name[1,-1] != '!' bin = bin?(name) if (!task || done) none = task && done && !bin #task = name if bin return super unless task || bin return if none # nothing to do params = args.to_params if bin cmd = "#{File.basename(bin)} #{params}" res = sh(cmd) elsif task cmd = "./#{task} #{params}" puts "--> #{cache ? '' : 'not-'}cached execution: #{cmd}" if trace? res = run(task, args) if cache #@batch_catch[task] ||= (system(cmd); true) batch_catch[task] ||= res end end return res end end end