Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 37 additions & 5 deletions lib/terrapin/command_line/multi_pipe.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,51 @@ def close_write
end

def read
@stdout_output = read_stream(@stdout_in)
@stderr_output = read_stream(@stderr_in)
read_streams(@stdout_in, @stderr_in)
end

def close_read
@stdout_in.close
begin
@stdout_in.close
rescue IOError
# do nothing
end

begin
@stderr_in.close
rescue IOError
# do nothing
end
end

def read_streams(output, error)
@stdout_output = ""
@stderr_output = ""
read_fds = [output, error]
while !read_fds.empty?
to_read, = IO.select(read_fds)
if to_read.include?(output)
@stdout_output << read_stream(output)
read_fds.delete(output) if output.closed?
end

if to_read.include?(error)
@stderr_output << read_stream(error)
read_fds.delete(error) if error.closed?
end
end
end

def read_stream(io)
result = String.new
while partial_result = io.read(8192)
result << partial_result
begin
while partial_result = io.read_nonblock(8192)
result << partial_result
end
rescue EOFError, Errno::EPIPE
io.close
rescue Errno::EINTR, Errno::EWOULDBLOCK, Errno::EAGAIN
# do nothing
end
result
end
Expand Down
13 changes: 13 additions & 0 deletions spec/support/nonblocking_examples.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
shared_examples_for "a command that does not block" do
it "does not block if the command output a lot on stderr" do
cmd = Terrapin::CommandLine.new(
"ruby",
"-e '$stdout.puts %{hello}; $stderr.puts %{goodbye}*10_000'",
:swallow_stderr => false
)
Timeout.timeout(5) do
cmd.run
end
expect(cmd.command_output).to eq "hello\n"
expect(cmd.command_error_output).to eq "#{"goodbye" * 10_000}\n"
end

it 'does not block if the command outputs a lot of data' do
garbage_file = Tempfile.new("garbage")
10.times{ garbage_file.write("A" * 1024 * 1024) }
Expand Down
Loading