From 86cab61c275ae52a89d649f53a58185b699c5de9 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 6 Jan 2014 09:27:37 -0800 Subject: [PATCH] commands/plugin: support installing from file --- lib/vagrant/bundler.rb | 53 +++++++++++++++++++ lib/vagrant/plugin/manager.rb | 23 ++++++-- plugins/commands/plugin/action/install_gem.rb | 31 ++--------- plugins/commands/plugin/command/install.rb | 9 +++- 4 files changed, 82 insertions(+), 34 deletions(-) diff --git a/lib/vagrant/bundler.rb b/lib/vagrant/bundler.rb index 28810d48c..7a903a2cc 100644 --- a/lib/vagrant/bundler.rb +++ b/lib/vagrant/bundler.rb @@ -1,3 +1,4 @@ +require "monitor" require "pathname" require "set" require "tempfile" @@ -17,6 +18,8 @@ module Vagrant end def initialize + @monitor = Monitor.new + @gem_home = ENV["GEM_HOME"] @gem_path = ENV["GEM_PATH"] @@ -59,6 +62,41 @@ module Vagrant internal_install(plugins, nil) 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. # # @param [Hash] plugins @@ -84,6 +122,21 @@ module Vagrant 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 # Builds a valid Gemfile for use with Bundler given the list of diff --git a/lib/vagrant/plugin/manager.rb b/lib/vagrant/plugin/manager.rb index db37423ba..acb2352d1 100644 --- a/lib/vagrant/plugin/manager.rb +++ b/lib/vagrant/plugin/manager.rb @@ -29,6 +29,13 @@ module Vagrant # @param [String] name Name of the plugin (gem) # @return [Gem::Specification] 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[name] = { "require" => opts[:require], @@ -37,10 +44,18 @@ module Vagrant } result = nil - Vagrant::Bundler.instance.install(plugins).each do |spec| - next if spec.name != name - next if result && result.version >= spec.version - result = spec + install_lambda = lambda do + Vagrant::Bundler.instance.install(plugins).each do |spec| + next if spec.name != name + next if result && result.version >= spec.version + result = spec + end + end + + if opts[:verbose] + Vagrant::Bundler.instance.verbose(&install_lambda) + else + install_lambda.call end # Add the plugin to the state file diff --git a/plugins/commands/plugin/action/install_gem.rb b/plugins/commands/plugin/action/install_gem.rb index a6295ad6b..9f553a0ac 100644 --- a/plugins/commands/plugin/action/install_gem.rb +++ b/plugins/commands/plugin/action/install_gem.rb @@ -1,12 +1,3 @@ -require "rubygems" -require "rubygems/dependency_installer" - -begin - require "rubygems/format" -rescue LoadError - # rubygems 2.x -end - require "log4r" require "vagrant/plugin/manager" @@ -27,24 +18,6 @@ module VagrantPlugins sources = env[:plugin_sources] 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 plugin_name_label = plugin_name plugin_name_label += " --version '#{version}'" if version @@ -56,7 +29,9 @@ module VagrantPlugins plugin_name, version: version, require: entrypoint, - sources: sources,) + sources: sources, + verbose: !!env[:plugin_verbose], + ) # Record it so we can uninstall if something goes wrong @installed_plugin_name = plugin_spec.name diff --git a/plugins/commands/plugin/command/install.rb b/plugins/commands/plugin/command/install.rb index c4f11d739..b38a08e25 100644 --- a/plugins/commands/plugin/command/install.rb +++ b/plugins/commands/plugin/command/install.rb @@ -10,12 +10,16 @@ module VagrantPlugins include MixinInstallOpts def execute - options = {} + options = { verbose: false } opts = OptionParser.new do |o| o.banner = "Usage: vagrant plugin install [-h]" o.separator "" build_install_opts(o, options) + + o.on("--verbose", "Enable verbose output for plugin installation") do |v| + options[:verbose] = v + end end # Parse the options @@ -28,7 +32,8 @@ module VagrantPlugins :plugin_entry_point => options[:entry_point], :plugin_version => options[:plugin_version], :plugin_sources => options[:plugin_sources], - :plugin_name => argv[0] + :plugin_name => argv[0], + :plugin_verbose => options[:verbose] }) # Success, exit status 0