lib/mattock/command-line.rb in mattock-0.3.4 vs lib/mattock/command-line.rb in mattock-0.4.0

- old
+ new

@@ -75,11 +75,11 @@ attr_reader :redirections alias_method :command_environment, :env def verbose - Rake.verbose && Rake.verbose != Rake::FileUtilsExt::DEFAULT + ::Rake.verbose && ::Rake.verbose != ::Rake::FileUtilsExt::DEFAULT end def name @name || executable end @@ -134,30 +134,57 @@ end def collect_result(pid, host_stdout, host_stderr) pid, status = Process.wait2(pid) - stdout = host_stdout.read - stderr = host_stderr.read + stdout = consume_buffer(host_stdout) + stderr = consume_buffer(host_stderr) result = CommandRunResult.new(command, status, {1 => stdout, 2 => stderr}) host_stdout.close host_stderr.close return result end + #Gets all the data out of buffer, even if somehow it doesn't have an EOF + #Escpecially useful for programs (e.g. ssh) that sometime set their stderr + #to O_NONBLOCK + def consume_buffer(io) + accumulate = [] + waits = 3 + begin + while chunk = io.read_nonblock(4096) + accumulate << chunk + end + rescue IO::WaitReadable => ex + retry if (waits -= 1) > 0 + end + return accumulate.join + rescue EOFError + return accumulate.join + end + #If I wasn't worried about writing my own limited shell, I'd say e.g. #Pipeline would be an explicit chain of pipes... which is probably as #originally intended :/ def execute collect_result(*spawn_process) end + #Run a command in the background. The command can survive the caller + def spin_off + pid, out, err = spawn_process + Process.detach(pid) + return pid, out, err + end + + #Run a command in parallel with the parent process - will kill it if it + #outlasts us def background pid, out, err = spawn_process + Process.detach(pid) at_exit do kill_process(pid) - Process.detach(pid) end return pid, out, err end def kill_process(pid)