Skip to content

Instantly share code, notes, and snippets.

@moxley
Last active December 25, 2016 16:58
Show Gist options
  • Save moxley/dc8eb956971ef68291de to your computer and use it in GitHub Desktop.
Save moxley/dc8eb956971ef68291de to your computer and use it in GitHub Desktop.
Runs shell command with similar IO stream behavior as a shell script: Stdout and stderr of command are captured and piped to caller's stdout and stderr.
require "open4"
require 'stringio'
class ShellCommand
class CommandError < StandardError
attr_reader :stderr_string
def initialize(message, stderr_string)
super(message)
@stderr_string = stderr_string
end
end
def self.call(command)
new.call(command)
end
def thread_for_output_stream(stream, dest_stream, tee_buffer=nil)
Thread.new do
begin
while !stream.eof?
str = stream.read
dest_stream.puts(str)
tee_buffer.puts(str) if tee_buffer
end
ensure
stream.close
end
end
end
def call(command)
pid, p_i, p_o, p_e = Open4.popen4(command)
p_i.close
error_output = StringIO.new
threads = [
thread_for_output_stream(p_o, $stdout),
thread_for_output_stream(p_e, $stderr, error_output)
]
_, status = Process::waitpid2(pid)
threads.each { |t| t.join }
raise CommandError.new("Command #{command} failed", error_output.string) if status.exitstatus != 0
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment