commands/plugin: support installing from file

This commit is contained in:
Mitchell Hashimoto 2014-01-06 09:27:37 -08:00
parent 3f9fb2ef03
commit 86cab61c27
4 changed files with 82 additions and 34 deletions

View File

@ -1,3 +1,4 @@
require "monitor"
require "pathname" require "pathname"
require "set" require "set"
require "tempfile" require "tempfile"
@ -17,6 +18,8 @@ module Vagrant
end end
def initialize def initialize
@monitor = Monitor.new
@gem_home = ENV["GEM_HOME"] @gem_home = ENV["GEM_HOME"]
@gem_path = ENV["GEM_PATH"] @gem_path = ENV["GEM_PATH"]
@ -59,6 +62,41 @@ module Vagrant
internal_install(plugins, nil) internal_install(plugins, nil)
end end
# Installs a local '*.gem' file so that Bundler can find it.
#
# @param [String] path Path to a local gem file.
# @return [Gem::Specification]
def install_local(path)
# We have to do this load here because this file can be loaded
# before RubyGems is actually loaded.
require "rubygems/dependency_installer"
begin
require "rubygems/format"
rescue LoadError
# rubygems 2.x
end
# If we're installing from a gem file, determine the name
# based on the spec in the file.
pkg = if defined?(Gem::Format)
# RubyGems 1.x
Gem::Format.from_file_by_path(path)
else
# RubyGems 2.x
Gem::Package.new(path)
end
# Install the gem manually. If the gem exists locally, then
# Bundler shouldn't attempt to get it remotely.
with_isolated_gem do
installer = Gem::DependencyInstaller.new(
:document => [], :prerelease => false)
installer.install(path, "= #{pkg.spec.version}")
end
pkg.spec
end
# Update updates the given plugins, or every plugin if none is given. # Update updates the given plugins, or every plugin if none is given.
# #
# @param [Hash] plugins # @param [Hash] plugins
@ -84,6 +122,21 @@ module Vagrant
end end
end end
# During the duration of the yielded block, Bundler loud output
# is enabled.
def verbose
@monitor.synchronize do
begin
old_ui = ::Bundler.ui
require 'bundler/vendored_thor'
::Bundler.ui = ::Bundler::UI::Shell.new
yield
ensure
::Bundler.ui = old_ui
end
end
end
protected protected
# Builds a valid Gemfile for use with Bundler given the list of # Builds a valid Gemfile for use with Bundler given the list of

View File

@ -29,6 +29,13 @@ module Vagrant
# @param [String] name Name of the plugin (gem) # @param [String] name Name of the plugin (gem)
# @return [Gem::Specification] # @return [Gem::Specification]
def install_plugin(name, **opts) def install_plugin(name, **opts)
if name =~ /\.gem$/
# If this is a gem file, then we install that gem locally.
local_spec = Vagrant::Bundler.instance.install_local(name)
name = local_spec.name
opts[:version] = "= #{local_spec.version}"
end
plugins = installed_plugins plugins = installed_plugins
plugins[name] = { plugins[name] = {
"require" => opts[:require], "require" => opts[:require],
@ -37,11 +44,19 @@ module Vagrant
} }
result = nil result = nil
install_lambda = lambda do
Vagrant::Bundler.instance.install(plugins).each do |spec| Vagrant::Bundler.instance.install(plugins).each do |spec|
next if spec.name != name next if spec.name != name
next if result && result.version >= spec.version next if result && result.version >= spec.version
result = spec result = spec
end end
end
if opts[:verbose]
Vagrant::Bundler.instance.verbose(&install_lambda)
else
install_lambda.call
end
# Add the plugin to the state file # Add the plugin to the state file
@global_file.add_plugin( @global_file.add_plugin(

View File

@ -1,12 +1,3 @@
require "rubygems"
require "rubygems/dependency_installer"
begin
require "rubygems/format"
rescue LoadError
# rubygems 2.x
end
require "log4r" require "log4r"
require "vagrant/plugin/manager" require "vagrant/plugin/manager"
@ -27,24 +18,6 @@ module VagrantPlugins
sources = env[:plugin_sources] sources = env[:plugin_sources]
version = env[:plugin_version] version = env[:plugin_version]
# Determine the plugin name we'll look for in the installed set
# in order to determine the version and all that.
find_plugin_name = plugin_name
if plugin_name =~ /\.gem$/
# If we're installing from a gem file, determine the name
# based on the spec in the file.
pkg = if defined?(Gem::Format)
# RubyGems 1.x
Gem::Format.from_file_by_path(plugin_name)
else
# RubyGems 2.x
Gem::Package.new(plugin_name)
end
find_plugin_name = pkg.spec.name
version = pkg.spec.version
end
# Install the gem # Install the gem
plugin_name_label = plugin_name plugin_name_label = plugin_name
plugin_name_label += " --version '#{version}'" if version plugin_name_label += " --version '#{version}'" if version
@ -56,7 +29,9 @@ module VagrantPlugins
plugin_name, plugin_name,
version: version, version: version,
require: entrypoint, require: entrypoint,
sources: sources,) sources: sources,
verbose: !!env[:plugin_verbose],
)
# Record it so we can uninstall if something goes wrong # Record it so we can uninstall if something goes wrong
@installed_plugin_name = plugin_spec.name @installed_plugin_name = plugin_spec.name

View File

@ -10,12 +10,16 @@ module VagrantPlugins
include MixinInstallOpts include MixinInstallOpts
def execute def execute
options = {} options = { verbose: false }
opts = OptionParser.new do |o| opts = OptionParser.new do |o|
o.banner = "Usage: vagrant plugin install <name> [-h]" o.banner = "Usage: vagrant plugin install <name> [-h]"
o.separator "" o.separator ""
build_install_opts(o, options) build_install_opts(o, options)
o.on("--verbose", "Enable verbose output for plugin installation") do |v|
options[:verbose] = v
end
end end
# Parse the options # Parse the options
@ -28,7 +32,8 @@ module VagrantPlugins
:plugin_entry_point => options[:entry_point], :plugin_entry_point => options[:entry_point],
:plugin_version => options[:plugin_version], :plugin_version => options[:plugin_version],
:plugin_sources => options[:plugin_sources], :plugin_sources => options[:plugin_sources],
:plugin_name => argv[0] :plugin_name => argv[0],
:plugin_verbose => options[:verbose]
}) })
# Success, exit status 0 # Success, exit status 0