diff --git a/lib/vagrant/errors.rb b/lib/vagrant/errors.rb index a90c0b21b..22ea2e09e 100644 --- a/lib/vagrant/errors.rb +++ b/lib/vagrant/errors.rb @@ -336,6 +336,10 @@ module Vagrant error_key(:provider_not_found) end + class PluginGemError < VagrantError + error_key(:plugin_gem_error) + end + class PluginLoadError < VagrantError status_code(81) error_key(:plugin_load_error) diff --git a/plugins/commands/plugin/action/install_gem.rb b/plugins/commands/plugin/action/install_gem.rb index 1abd010cf..71be71b0c 100644 --- a/plugins/commands/plugin/action/install_gem.rb +++ b/plugins/commands/plugin/action/install_gem.rb @@ -17,23 +17,10 @@ module VagrantPlugins def call(env) plugin_name = env[:plugin_name] - # First, install the gem - begin - # Set the GEM_HOME so that it is installed into our local gems path - old_gem_home = ENV["GEM_HOME"] - ENV["GEM_HOME"] = env[:gems_path].to_s - p ENV["GEM_PATH"] - @logger.debug("Set GEM_HOME to: #{ENV["GEM_HOME"]}") - - @logger.info("Installing gem: #{plugin_name}") - env[:ui].info( - I18n.t("vagrant.commands.plugin.installing", :name => plugin_name)) - Gem.clear_paths - Gem::GemRunner.new.run( - ["install", plugin_name, "--no-ri", "--no-rdoc"]) - ensure - ENV["GEM_HOME"] = old_gem_home - end + # Install the gem + env[:ui].info(I18n.t("vagrant.commands.plugin.installing", + :name => plugin_name)) + env[:gem_helper].cli(["install", plugin_name, "--no-ri", "--no-rdoc"]) # Mark that we installed the gem env[:plugin_state_file].add_plugin(plugin_name) diff --git a/plugins/commands/plugin/command/install.rb b/plugins/commands/plugin/command/install.rb index ffa137672..dc5b2fa6b 100644 --- a/plugins/commands/plugin/command/install.rb +++ b/plugins/commands/plugin/command/install.rb @@ -16,6 +16,7 @@ module VagrantPlugins # Install the gem @env.action_runner.run(Action.action_install, { + :gem_helper => GemHelper.new(@env.gems_path), :plugin_name => argv[0], :plugin_state_file => StateFile.new(@env.data_dir.join("plugins.json")) }) diff --git a/plugins/commands/plugin/gem_helper.rb b/plugins/commands/plugin/gem_helper.rb new file mode 100644 index 000000000..d7fd81b49 --- /dev/null +++ b/plugins/commands/plugin/gem_helper.rb @@ -0,0 +1,47 @@ +require "rubygems" +require "rubygems/gem_runner" + +require "log4r" + +module VagrantPlugins + module CommandPlugin + # This class provides methods to help with calling out to the + # `gem` command but using the RubyGems API. + class GemHelper + def initialize(gem_home) + @gem_home = gem_home.to_s + @logger = Log4r::Logger.new("vagrant::plugins::plugincommand::gemhelper") + end + + def cli(argv) + # Initialize the UI to use for RubyGems. This allows us to capture + # the stdout/stderr without actually going to the real STDOUT/STDERR. + # The final "false" here tells RubyGems we're not a TTY, so don't + # ask us things. + gem_ui = Gem::StreamUI.new(StringIO.new, StringIO.new, StringIO.new, false) + + # Set the GEM_HOME so that it is installed into our local gems path + old_gem_home = ENV["GEM_HOME"] + ENV["GEM_HOME"] = @gem_home + @logger.debug("Set GEM_HOME to: #{ENV["GEM_HOME"]}") + @logger.info("Calling gem with argv: #{argv.inspect}") + Gem.clear_paths + Gem::DefaultUserInteraction.use_ui(gem_ui) do + Gem::GemRunner.new.run(argv) + end + rescue Gem::SystemExitException => e + # This means that something forced an exit within RubyGems. + # We capture this to check whether it succeeded or not by + # checking the "exit_code" + raise Vagrant::Errors::PluginGemError, :output => gem_ui.errs.string.chomp if e != 0 + ensure + # Restore the old GEM_HOME + ENV["GEM_HOME"] = old_gem_home + + # Log the output properly + @logger.debug("Gem STDOUT: #{gem_ui.outs.string}") + @logger.debug("Gem STDERR: #{gem_ui.errs.string}") + end + end + end +end diff --git a/plugins/commands/plugin/plugin.rb b/plugins/commands/plugin/plugin.rb index c7cf5e24f..db9763319 100644 --- a/plugins/commands/plugin/plugin.rb +++ b/plugins/commands/plugin/plugin.rb @@ -16,6 +16,7 @@ DESC end autoload :Action, File.expand_path("../action", __FILE__) + autoload :GemHelper, File.expand_path("../gem_helper", __FILE__) autoload :StateFile, File.expand_path("../state_file", __FILE__) end end diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 1ce45e7e6..214bbd1a3 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -165,6 +165,11 @@ en: no_env: |- A Vagrant environment is required to run this command. Run `vagrant init` to set one up. + plugin_gem_error: |- + An error occurred within RubyGems, the underlying system used to + manage Vagrant plugins. The output of the errors are shown below: + + %{output} plugin_load_error: |- The plugin "%{plugin}" could not be found. Please make sure that it is properly installed via `vagrant gem`.