lib/shellshot.rb in shellshot-0.2.0 vs lib/shellshot.rb in shellshot-0.3.0

- old
+ new

@@ -1,20 +1,28 @@ require 'rubygems' +require 'tempfile' require 'system_timer' module Shellshot - + + class CommandError < RuntimeError; end + class Command alias_method :system_exec, :exec DEFAULT_TIMEOUT = 60 * 60 # 1 hour - attr_accessor :pid, :status + attr_accessor :pid, :status, :options def exec(command, options = {}) + + self.options = options + + prepare_pipes if no_stderr? self.pid = fork do + close_reading_pipe if no_stderr? redefine_stds(options) system_exec(command) end begin @@ -27,30 +35,81 @@ private def wait_for(seconds) SystemTimer.timeout(seconds) do - Process.wait(pid) + Process.wait(pid) self.status = $? + unless self.status.success? + raise CommandError, stderr_contents + end end end + def close_stderr + error_tempfile.close + end + def terminate_child_process - if pid + if pid Process.kill("KILL", pid) Process.wait(pid) # reaping zombie processes. Not sure if correct. end end def redefine_stds(options) - $stdout.reopen(File.open(options[:stdout], "w+")) if options[:stdout] - $stderr.reopen(File.open(options[:stderr], "w+")) if options[:stderr] - - if options[:stdall] - combined = File.open(options[:stdall], "w+") + if stdall_location + combined = File.open(stdall_location, "w+") $stdout.reopen(combined) $stderr.reopen(combined) + else + $stdout.reopen(File.open(stdout_location, "w+")) if stdout_location + if no_stderr? + $stderr.reopen(@wr) + else + $stderr.reopen(File.open(stderr_location, "w+")) + end end + end + + def stderr_location + stdall_location || options[:stderr] + end + + def no_stderr? + !stderr_location + end + + def stdout_location + stdall_location || options[:stdout] + end + + def stdall_location + options[:stdall] + end + + def close_reading_pipe + @rd.close + end + + def stderr_contents + if no_stderr? + @wr.close + contents = @rd.read + @rd.close + contents + else + File.read(stderr_location) + end + end + + def prepare_pipes + @rd, @wr = IO.pipe + end + + def close_pipes + @rd.close + @wr.close end end def self.exec(command, options = {}) Shellshot::Command.new().exec(command, options)