Skip to content

Commit

Permalink
commands/plugin: support installing from file
Browse files Browse the repository at this point in the history
  • Loading branch information
mitchellh committed Jan 6, 2014
1 parent 3f9fb2e commit 86cab61
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 34 deletions.
53 changes: 53 additions & 0 deletions lib/vagrant/bundler.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require "monitor"
require "pathname"
require "set"
require "tempfile"
Expand All @@ -17,6 +18,8 @@ def self.instance
end

def initialize
@monitor = Monitor.new

@gem_home = ENV["GEM_HOME"]
@gem_path = ENV["GEM_PATH"]

Expand Down Expand Up @@ -59,6 +62,41 @@ def install(plugins)
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
Expand All @@ -84,6 +122,21 @@ def clean(plugins)
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
Expand Down
23 changes: 19 additions & 4 deletions lib/vagrant/plugin/manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ def initialize(global_file)
# @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],
Expand All @@ -37,10 +44,18 @@ def install_plugin(name, **opts)
}

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
Expand Down
31 changes: 3 additions & 28 deletions plugins/commands/plugin/action/install_gem.rb
Original file line number Diff line number Diff line change
@@ -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"

Expand All @@ -27,24 +18,6 @@ def call(env)
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
Expand All @@ -56,7 +29,9 @@ def call(env)
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
Expand Down
9 changes: 7 additions & 2 deletions plugins/commands/plugin/command/install.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ class Install < Base
include MixinInstallOpts

def execute
options = {}
options = { verbose: false }

opts = OptionParser.new do |o|
o.banner = "Usage: vagrant plugin install <name> [-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
Expand All @@ -28,7 +32,8 @@ def execute
: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
Expand Down

0 comments on commit 86cab61

Please sign in to comment.