Skip to content
Closed
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
6 changes: 4 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@ jobs:
fail-fast: false
matrix:
ruby:
- jruby-9.4.1.0
- jruby-9.4.12.0
- "2.7"
- "3.0"
- "3.1"
- "3.2"
- "3.3"
- "3.4"

runs-on: 'ubuntu-latest'

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dynamic-readme.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: update-templates

on:
on:
push:
branches:
- main
Expand Down
2 changes: 1 addition & 1 deletion lib/terrapin/command_line.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def run(interpolations = {})

unless @expected_outcodes.include?(@exit_status)
message = [
"Command '#{full_command}' returned #{@exit_status}. Expected #{@expected_outcodes.join(", ")}",
"Command '#{full_command}' returned #{@exit_status.inspect}. Expected #{@expected_outcodes.join(", ")}",
"Here is the command output: STDOUT:\n", command_output,
"\nSTDERR:\n", command_error_output
].join("\n")
Expand Down
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: 12 additions & 1 deletion spec/support/nonblocking_examples.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
shared_examples_for "a command that does not block" do
shared_examples_for "a command that does not block" do |opts = {}|
if opts[:supports_stderr]
it "does not block if the command output a lot on stderr" do
Timeout.timeout(5) do
output = subject.call("ruby -e '$stdout.puts %{hello}; $stderr.puts %{goodbye}*10_000'")

expect(output.output).to eq "hello\n"
expect(output.error_output).to eq "#{"goodbye" * 10_000}\n"
end
end
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

describe Terrapin::CommandLine::BackticksRunner do
if Terrapin::CommandLine::BackticksRunner.supported?
it_behaves_like 'a command that does not block'
it_behaves_like 'a command that does not block', { :supports_stderr => false }

it 'runs the command given and captures the output in an Output' do
output = subject.call("echo hello")
Expand Down
2 changes: 1 addition & 1 deletion spec/terrapin/command_line/runners/popen_runner_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

describe Terrapin::CommandLine::PopenRunner do
if Terrapin::CommandLine::PopenRunner.supported?
it_behaves_like 'a command that does not block'
it_behaves_like 'a command that does not block', { :supports_stderr => false }

it 'runs the command given and captures the output in an Output' do
output = subject.call("echo hello")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

describe Terrapin::CommandLine::ProcessRunner do
if Terrapin::CommandLine::ProcessRunner.supported?
it_behaves_like "a command that does not block"
it_behaves_like "a command that does not block", { :supports_stderr => true }

it 'runs the command given and captures the output' do
output = subject.call("echo hello")
Expand Down