From 5ce6ead83be1a46241db53e401f44c9a40f598ce Mon Sep 17 00:00:00 2001 From: Max Lincoln Date: Wed, 9 Jul 2014 16:05:17 -0400 Subject: Support separate live stream for stderr --- lib/mixlib/shellout.rb | 24 +++++++++++-- lib/mixlib/shellout/unix.rb | 2 +- lib/mixlib/shellout/windows.rb | 2 +- spec/mixlib/shellout_spec.rb | 82 +++++++++++++++++++++++++++++++++++++++--- 4 files changed, 102 insertions(+), 8 deletions(-) diff --git a/lib/mixlib/shellout.rb b/lib/mixlib/shellout.rb index e446448..a633819 100644 --- a/lib/mixlib/shellout.rb +++ b/lib/mixlib/shellout.rb @@ -54,10 +54,13 @@ module Mixlib attr_accessor :valid_exit_codes # When live_stream is set, stdout and stderr of the subprocess will be - # copied to it as the subprocess is running. For example, if live_stream is - # set to STDOUT, the command's output will be echoed to STDOUT. + # copied to it as the subprocess is running. The stderr will also be copied, + # unless live_stderr_stream is set to nil or a different object. For example, + # if live_stream is set to STDOUT, the command's output will be echoed to STDOUT. attr_accessor :live_stream + attr_writer :live_stderr_stream + # ShellOut will push data from :input down the stdin of the subprocss. # Normally set via options passed to new. # Default: nil @@ -163,6 +166,20 @@ module Mixlib @command = command_args.size == 1 ? command_args.first : command_args end + # When live_stderr_stream is set, the stderr of the subprocess will be + # copied to it as the subprocess is running. For example, if live_stderr_stream is + # set to STDERR, the command's output will be echoed to STDERR. The default + # value is to match live_stream, so setting live_stream to STDOUT will also + # set live_stderr_stream to STDOUT. If you only want the stdout of the subprocess + # copied, then you should explicitly set live_stderr_stream to nil. + def live_stderr_stream + # We can't use ||= because it would override an explicit nil + unless defined?(@live_stderr_stream) + @live_stderr_stream = live_stream + end + @live_stderr_stream + end + # Set the umask that the subprocess will have. If given as a string, it # will be converted to an integer by String#oct. def umask=(new_umask) @@ -287,6 +304,9 @@ module Mixlib self.valid_exit_codes = Array(setting) when 'live_stream' self.live_stream = setting + when 'live_stderr_stream' + puts "Setting to #{setting}" + self.live_stderr_stream = setting when 'input' self.input = setting when 'logger' diff --git a/lib/mixlib/shellout/unix.rb b/lib/mixlib/shellout/unix.rb index 46c2c73..249c3d4 100644 --- a/lib/mixlib/shellout/unix.rb +++ b/lib/mixlib/shellout/unix.rb @@ -288,7 +288,7 @@ module Mixlib def read_stderr_to_buffer while chunk = child_stderr.read_nonblock(READ_SIZE) @stderr << chunk - @live_stream << chunk if @live_stream + live_stderr_stream << chunk if live_stderr_stream end rescue Errno::EAGAIN rescue EOFError diff --git a/lib/mixlib/shellout/windows.rb b/lib/mixlib/shellout/windows.rb index 832584a..62adc37 100644 --- a/lib/mixlib/shellout/windows.rb +++ b/lib/mixlib/shellout/windows.rb @@ -167,7 +167,7 @@ module Mixlib begin next_chunk = stderr_read.readpartial(READ_SIZE) @stderr << next_chunk - @live_stream << next_chunk if @live_stream + @live_stderr_stream << next_chunk if @live_stderr_stream rescue EOFError stderr_read.close open_streams.delete(stderr_read) diff --git a/spec/mixlib/shellout_spec.rb b/spec/mixlib/shellout_spec.rb index 5dcb6a7..72d550e 100644 --- a/spec/mixlib/shellout_spec.rb +++ b/spec/mixlib/shellout_spec.rb @@ -187,8 +187,56 @@ describe Mixlib::ShellOut do let(:value) { stream } let(:stream) { StringIO.new } + before(:each) do + shell_cmd.live_stream = stream + end + it "should set the live stream" do - should eql(value) + shell_cmd.live_stream.should eql(stream) + end + + it "should set the live stderr stream" do + shell_cmd.live_stderr_stream.should eql(stream) + end + end + + context 'when setting a live stream and live stderr stream separately' do + let(:accessor) { :live_stream } + let(:stream) { StringIO.new } + let(:value) { stream } + let(:stdout_stream) { StringIO.new } + let(:stderr_stream) { StringIO.new } + + before(:each) do + shell_cmd.live_stream = stdout_stream + shell_cmd.live_stderr_stream = stderr_stream + end + + it "should set the live stream" do + shell_cmd.live_stream.should eql(stdout_stream) + end + + it "should set the live stream" do + shell_cmd.live_stderr_stream.should eql(stderr_stream) + end + end + + context 'when setting a live stream and explicitly disabling live stderr stream' do + let(:accessor) { :live_stream } + let(:value) { stream } + let(:stream) { StringIO.new } + + before(:each) do + shell_cmd.live_stream = stream + shell_cmd.live_stderr_stream = nil + end + + it "should set the live stream" do + shell_cmd.live_stream.should eql(stream) + end + + it "should set the live stderr stream" do + shell_cmd.live_stderr_stream.should eql(nil) end end @@ -457,9 +505,35 @@ describe Mixlib::ShellOut do stream.string.should include("hello#{LINE_ENDING}") end - it "should copy the child's stderr to the live stream" do - shell_cmd.run_command - stream.string.should include("world#{LINE_ENDING}") + context "with default stderr stream" do + it "should copy the child's stderr to the live stream" do + shell_cmd.run_command + stream.string.should include("world#{LINE_ENDING}") + end + end + + context "without an stderr stream" do + it "should not copy the child's stderr to the live stream" do + shell_cmd.live_stderr_stream = nil + shell_cmd.run_command + stream.string.should_not include("world#{LINE_ENDING}") + end + end + + context "with a separate stderr stream" do + let(:stderr_stream) { StringIO.new } + + it "should not copy the child's stderr to the live stream" do + shell_cmd.live_stderr_stream = stderr_stream + shell_cmd.run_command + stream.string.should_not include("world#{LINE_ENDING}") + end + + it "should copy the child's stderr to the live stderr stream" do + shell_cmd.live_stderr_stream = stderr_stream + shell_cmd.run_command + stderr_stream.string.should include("world#{LINE_ENDING}") + end end end -- cgit v1.2.1