safe_puts to avoid EPIPE [GH-819]

This commit is contained in:
Mitchell Hashimoto 2012-03-18 17:41:26 -06:00
parent a8ca0353e9
commit 641a8daac8
6 changed files with 53 additions and 4 deletions

View File

@ -8,6 +8,7 @@
setting. [GH-808] setting. [GH-808]
- `vagrant ssh` now works on Solaris, where `IdentitiesOnly` was not - `vagrant ssh` now works on Solaris, where `IdentitiesOnly` was not
an available option. [GH-820] an available option. [GH-820]
- Output works properly in the face of broken pipes. [GH-819]
## 1.0.1 (March 11, 2012) ## 1.0.1 (March 11, 2012)

View File

@ -1,5 +1,7 @@
require 'log4r' require 'log4r'
require "vagrant/util/safe_puts"
module Vagrant module Vagrant
module Command module Command
# Base class for any CLI commands. # Base class for any CLI commands.
@ -7,6 +9,8 @@ module Vagrant
# This class provides documentation on the interface as well as helper # This class provides documentation on the interface as well as helper
# functions that a command has. # functions that a command has.
class Base class Base
include Util::SafePuts
def initialize(argv, env) def initialize(argv, env)
@argv = argv @argv = argv
@env = env @env = env
@ -41,7 +45,7 @@ module Vagrant
# Add the help option, which must be on every command. # Add the help option, which must be on every command.
opts.on_tail("-h", "--help", "Print this help") do opts.on_tail("-h", "--help", "Print this help") do
puts opts.help safe_puts(opts.help)
return nil return nil
end end

View File

@ -1,9 +1,13 @@
require "rubygems" require "rubygems"
require "rubygems/gem_runner" require "rubygems/gem_runner"
require "vagrant/util/safe_puts"
module Vagrant module Vagrant
module Command module Command
class Gem < Base class Gem < Base
include Util::SafePuts
def execute def execute
# Bundler sets up its own custom gem load paths such that our # Bundler sets up its own custom gem load paths such that our
# own gems are never loaded. Therefore, give an error if a user # 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") if @argv.empty? || @argv.include?("-h") || @argv.include?("--help")
@env.ui.info(I18n.t("vagrant.commands.gem.help_preamble"), @env.ui.info(I18n.t("vagrant.commands.gem.help_preamble"),
:prefix => false) :prefix => false)
puts safe_puts
end end
# We just proxy the arguments onto a real RubyGems command # We just proxy the arguments onto a real RubyGems command

View File

@ -1,8 +1,12 @@
require 'optparse' require 'optparse'
require "vagrant/util/safe_puts"
module Vagrant module Vagrant
module Command module Command
class SSHConfig < Base class SSHConfig < Base
include Util::SafePuts
def execute def execute
options = {} options = {}
@ -36,7 +40,7 @@ module Vagrant
# Render the template and output directly to STDOUT # Render the template and output directly to STDOUT
template = "commands/ssh_config/config" template = "commands/ssh_config/config"
$stdout.puts(Util::TemplateRenderer.render(template, variables)) safe_puts(Util::TemplateRenderer.render(template, variables))
end end
end end
end end

View File

@ -1,5 +1,7 @@
require "log4r" require "log4r"
require "vagrant/util/safe_puts"
module Vagrant module Vagrant
module UI module UI
# Vagrant UIs handle communication with the outside world (typically # 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 # This is a UI implementation that outputs the text as is. It
# doesn't add any color. # doesn't add any color.
class Basic < Interface class Basic < Interface
include Util::SafePuts
# Use some light meta-programming to create the various methods to # Use some light meta-programming to create the various methods to
# output text to the UI. These all delegate the real functionality # output text to the UI. These all delegate the real functionality
# to `say`. # to `say`.
@ -112,7 +116,8 @@ module Vagrant
channel = type == :error || opts[:channel] == :error ? $stderr : $stdout channel = type == :error || opts[:channel] == :error ? $stderr : $stdout
# Output! # Output!
channel.send(printer, format_message(type, message, opts)) safe_puts(format_message(type, message, opts),
:io => channel, :printer => printer)
end end
# This is called by `say` to format the message for output. # This is called by `say` to format the message for output.

View File

@ -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