From 641a8daac8ca966176b93870c14d05dfd560349f Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 18 Mar 2012 17:41:26 -0600 Subject: [PATCH] safe_puts to avoid EPIPE [GH-819] --- CHANGELOG.md | 1 + lib/vagrant/command/base.rb | 6 +++++- lib/vagrant/command/gem.rb | 6 +++++- lib/vagrant/command/ssh_config.rb | 6 +++++- lib/vagrant/ui.rb | 7 ++++++- lib/vagrant/util/safe_puts.rb | 31 +++++++++++++++++++++++++++++++ 6 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 lib/vagrant/util/safe_puts.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 40a7f4e21..2601be51f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ setting. [GH-808] - `vagrant ssh` now works on Solaris, where `IdentitiesOnly` was not an available option. [GH-820] + - Output works properly in the face of broken pipes. [GH-819] ## 1.0.1 (March 11, 2012) diff --git a/lib/vagrant/command/base.rb b/lib/vagrant/command/base.rb index f364bafe9..38c2c144f 100644 --- a/lib/vagrant/command/base.rb +++ b/lib/vagrant/command/base.rb @@ -1,5 +1,7 @@ require 'log4r' +require "vagrant/util/safe_puts" + module Vagrant module Command # Base class for any CLI commands. @@ -7,6 +9,8 @@ module Vagrant # This class provides documentation on the interface as well as helper # functions that a command has. class Base + include Util::SafePuts + def initialize(argv, env) @argv = argv @env = env @@ -41,7 +45,7 @@ module Vagrant # Add the help option, which must be on every command. opts.on_tail("-h", "--help", "Print this help") do - puts opts.help + safe_puts(opts.help) return nil end diff --git a/lib/vagrant/command/gem.rb b/lib/vagrant/command/gem.rb index 4a135acac..319883587 100644 --- a/lib/vagrant/command/gem.rb +++ b/lib/vagrant/command/gem.rb @@ -1,9 +1,13 @@ require "rubygems" require "rubygems/gem_runner" +require "vagrant/util/safe_puts" + module Vagrant module Command class Gem < Base + include Util::SafePuts + def execute # Bundler sets up its own custom gem load paths such that our # own gems are never loaded. Therefore, give an error if a user @@ -20,7 +24,7 @@ module Vagrant if @argv.empty? || @argv.include?("-h") || @argv.include?("--help") @env.ui.info(I18n.t("vagrant.commands.gem.help_preamble"), :prefix => false) - puts + safe_puts end # We just proxy the arguments onto a real RubyGems command diff --git a/lib/vagrant/command/ssh_config.rb b/lib/vagrant/command/ssh_config.rb index 953f73404..c0474a0c1 100644 --- a/lib/vagrant/command/ssh_config.rb +++ b/lib/vagrant/command/ssh_config.rb @@ -1,8 +1,12 @@ require 'optparse' +require "vagrant/util/safe_puts" + module Vagrant module Command class SSHConfig < Base + include Util::SafePuts + def execute options = {} @@ -36,7 +40,7 @@ module Vagrant # Render the template and output directly to STDOUT template = "commands/ssh_config/config" - $stdout.puts(Util::TemplateRenderer.render(template, variables)) + safe_puts(Util::TemplateRenderer.render(template, variables)) end end end diff --git a/lib/vagrant/ui.rb b/lib/vagrant/ui.rb index 623a8ba31..e55c3d8d3 100644 --- a/lib/vagrant/ui.rb +++ b/lib/vagrant/ui.rb @@ -1,5 +1,7 @@ require "log4r" +require "vagrant/util/safe_puts" + module Vagrant module UI # Vagrant UIs handle communication with the outside world (typically @@ -43,6 +45,8 @@ module Vagrant # This is a UI implementation that outputs the text as is. It # doesn't add any color. class Basic < Interface + include Util::SafePuts + # Use some light meta-programming to create the various methods to # output text to the UI. These all delegate the real functionality # to `say`. @@ -112,7 +116,8 @@ module Vagrant channel = type == :error || opts[:channel] == :error ? $stderr : $stdout # Output! - channel.send(printer, format_message(type, message, opts)) + safe_puts(format_message(type, message, opts), + :io => channel, :printer => printer) end # This is called by `say` to format the message for output. diff --git a/lib/vagrant/util/safe_puts.rb b/lib/vagrant/util/safe_puts.rb new file mode 100644 index 000000000..6aed4b39e --- /dev/null +++ b/lib/vagrant/util/safe_puts.rb @@ -0,0 +1,31 @@ +module Vagrant + module Util + # This module provides a `safe_puts` method which outputs to + # the given IO object, and rescues any broken pipe errors and + # ignores them. This is useful in cases where you're outputting + # to stdout, for example, and the stdout is closed, but you want to + # keep running. + module SafePuts + # Uses `puts` on the given IO object and safely ignores any + # Errno::EPIPE. + # + # @param [String] message Message to output. + # @param [Hash] opts Options hash. + def safe_puts(message=nil, opts=nil) + message ||= "" + opts = { + :io => $stdout, + :printer => :puts + }.merge(opts || {}) + + begin + opts[:io].send(opts[:printer], message) + rescue Errno::EPIPE + # This is what makes this a `safe` puts. + return + end + end + end + end +end +