Instead of shelling out, use the RubyGems API to install plugins
This gets us an accurate name of the gem even if it is installed from a file.
This commit is contained in:
parent
8cde263a14
commit
1162c2dbfc
|
@ -340,6 +340,10 @@ module Vagrant
|
|||
error_key(:plugin_gem_error)
|
||||
end
|
||||
|
||||
class PluginInstallBadEntryPoint < VagrantError
|
||||
error_key(:plugin_install_bad_entry_point)
|
||||
end
|
||||
|
||||
class PluginLoadError < VagrantError
|
||||
status_code(81)
|
||||
error_key(:plugin_load_error)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
require "rubygems"
|
||||
require "rubygems/gem_runner"
|
||||
require "rubygems/dependency_installer"
|
||||
|
||||
require "log4r"
|
||||
|
||||
|
@ -20,14 +20,43 @@ module VagrantPlugins
|
|||
# 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"])
|
||||
installed_gems = env[:gem_helper].with_environment do
|
||||
installer = Gem::DependencyInstaller.new(:document => [])
|
||||
installer.install(plugin_name)
|
||||
end
|
||||
|
||||
# The plugin spec is the last installed gem since RubyGems
|
||||
# currently always installed the requested gem last.
|
||||
@logger.debug("Installed #{installed_gems.length} gems.")
|
||||
plugin_spec = installed_gems.last
|
||||
|
||||
# Store the installed name so we can uninstall it if things go
|
||||
# wrong.
|
||||
@installed_plugin_name = plugin_spec.name
|
||||
|
||||
# Mark that we installed the gem
|
||||
env[:plugin_state_file].add_plugin(plugin_name)
|
||||
@logger.info("Adding the plugin to the state file...")
|
||||
env[:plugin_state_file].add_plugin(plugin_spec.name)
|
||||
|
||||
# Tell the user
|
||||
env[:ui].success(I18n.t("vagrant.commands.plugin.installed",
|
||||
:name => plugin_spec.name))
|
||||
|
||||
# Continue
|
||||
@app.call(env)
|
||||
end
|
||||
|
||||
def recover(env)
|
||||
# If any error happens, we uninstall it and remove it from
|
||||
# the state file. We can only do this if we successfully installed
|
||||
# the gem in the first place.
|
||||
if @installed_plugin_name
|
||||
new_env = env.dup
|
||||
new_env.delete(:interrupted)
|
||||
new_env[:plugin_name] = @installed_plugin_name
|
||||
new_env[:action_runner].run(Action.action_uninstall, new_env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,8 +7,16 @@ module VagrantPlugins
|
|||
module Command
|
||||
class Install < Base
|
||||
def execute
|
||||
options = {}
|
||||
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant plugin install <name> [-h]"
|
||||
o.separator ""
|
||||
|
||||
o.on("--entry-point NAME", String,
|
||||
"The name of the entry point file for loading the plugin.") do |entry_point|
|
||||
options[:entry_point] = entry_point
|
||||
end
|
||||
end
|
||||
|
||||
# Parse the options
|
||||
|
@ -17,7 +25,10 @@ module VagrantPlugins
|
|||
raise Vagrant::Errors::CLIInvalidUsage, :help => opts.help.chomp if argv.length < 1
|
||||
|
||||
# Install the gem
|
||||
action(Action.action_install, :plugin_name => argv[0])
|
||||
action(Action.action_install, {
|
||||
:plugin_entry_point => options[:entry_point],
|
||||
:plugin_name => argv[0]
|
||||
})
|
||||
|
||||
# Success, exit status 0
|
||||
0
|
||||
|
|
|
@ -13,37 +13,6 @@ module VagrantPlugins
|
|||
@logger = Log4r::Logger.new("vagrant::plugins::plugincommand::gemhelper")
|
||||
end
|
||||
|
||||
# This executes the `gem` command with the given arguments. Under
|
||||
# the covers this is actually using the RubyGems API directly,
|
||||
# instead of shelling out, which allows for more fine-grained control.
|
||||
#
|
||||
# @param [Array<String>] argv The arguments to send to the `gem` command.
|
||||
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
|
||||
with_environment do
|
||||
@logger.info("Calling gem with argv: #{argv.inspect}")
|
||||
Gem::DefaultUserInteraction.use_ui(gem_ui) do
|
||||
Gem::GemRunner.new.run(argv)
|
||||
end
|
||||
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.exit_code != 0
|
||||
ensure
|
||||
# Log the output properly
|
||||
@logger.debug("Gem STDOUT: #{gem_ui.outs.string}")
|
||||
@logger.debug("Gem STDERR: #{gem_ui.errs.string}")
|
||||
end
|
||||
|
||||
# This will yield the given block with the proper ENV setup so
|
||||
# that RubyGems only sees the gems in the Vagrant-managed gem
|
||||
# path.
|
||||
|
|
|
@ -170,6 +170,11 @@ en:
|
|||
manage Vagrant plugins. The output of the errors are shown below:
|
||||
|
||||
%{output}
|
||||
plugin_install_bad_entry_point: |-
|
||||
Attempting to load the plugin '%{name}' failed, because
|
||||
the entry point doesn't exist. The entry point attempted was
|
||||
'%{entry_point}'. If this is not correct, please manually
|
||||
specify an `--entry-point` when installing the plugin.
|
||||
plugin_load_error: |-
|
||||
The plugin "%{plugin}" could not be found. Please make sure that it is
|
||||
properly installed via `vagrant plugin`.
|
||||
|
@ -412,6 +417,8 @@ en:
|
|||
plugin:
|
||||
no_plugins: |-
|
||||
No plugins installed.
|
||||
installed: |-
|
||||
Installed the '%{name}' plugin!
|
||||
installing: |-
|
||||
Installing the '%{name}' plugin. This can take a few minutes...
|
||||
uninstalling: |-
|
||||
|
|
Loading…
Reference in New Issue