pull pipe logic out into popen4-ish method

This commit is contained in:
Ryan Tomayko 2010-12-21 01:39:02 -08:00
Родитель 5cdf67cc5c
Коммит 3ed77ebceb
1 изменённых файлов: 43 добавлений и 21 удалений

Просмотреть файл

@ -93,29 +93,16 @@ module Grit
argv = @argv
argv = ['/bin/sh', '-c', argv.to_str] if argv.respond_to?(:to_str)
# create some pipes (see pipe(2) manual -- the ruby docs suck)
ird, iwr = IO.pipe
ord, owr = IO.pipe
erd, ewr = IO.pipe
# spawn the process and hook up the pipes
pid, stdin, stdout, stderr = popen4(@env, *(argv + [@options]))
# spawn the child process with either end of pipes hooked together
opts =
@options.merge(
# redirect fds # close other sides
:in => ird, iwr => :close,
:out => owr, ord => :close,
:err => ewr, erd => :close
)
pid = spawn(@env, *(argv + [opts]))
# we're in the parent, close child-side fds
[ird, owr, ewr].each { |fd| fd.close }
@out, @err = read_and_write(@input, iwr, ord, erd, @timeout, @max)
# async read from all streams into buffers
@out, @err = read_and_write(@input, stdin, stdout, stderr, @timeout, @max)
# grab exit status
@status = (::Process.waitpid(pid); $?)
rescue Object => boom
[ird, iwr, ord, owr, erd, ewr].each { |fd| fd.close rescue nil }
[stdin, stdout, stderr].each { |fd| fd.close rescue nil }
if @status.nil?
::Process.kill('TERM', pid) rescue nil
@status = (::Process.waitpid(pid); $?) rescue nil
@ -254,10 +241,45 @@ module Grit
end
end
# Start a process with spawn options and return
# popen4([env], command, arg1, arg2, [opt])
#
# env - The child process's environment as a Hash.
# command - The command and zero or more arguments.
# options - An options hash.
#
# See Ruby 1.9 IO.popen and Process::spawn docs for more info:
# http://www.ruby-doc.org/core-1.9/classes/IO.html#M001640
#
# Returns a [pid, stdin, stderr, stdout] tuple where pid is the child
# process's pid, stdin is a writeable IO object, and stdout + stderr are
# readable IO objects.
def popen4(*argv)
# create some pipes (see pipe(2) manual -- the ruby docs suck)
ird, iwr = IO.pipe
ord, owr = IO.pipe
erd, ewr = IO.pipe
# spawn the child process with either end of pipes hooked together
opts =
((argv.pop if argv[-1].is_a?(Hash)) || {}).merge(
# redirect fds # close other sides
:in => ird, iwr => :close,
:out => owr, ord => :close,
:err => ewr, erd => :close
)
pid = spawn(*(argv + [opts]))
[pid, iwr, ord, erd]
ensure
# we're in the parent, close child-side fds
[ird, owr, ewr].each { |fd| fd.close }
end
# Use native Process::spawn implementation on Ruby 1.9.
if ::Process.respond_to?(:spawn)
def spawn(env, *argv)
::Process.spawn(env, *argv)
def spawn(*argv)
::Process.spawn(*argv)
end
end
end