Merge pull request #8000 from chrisroberts/plugins/updates
Plugin handling updates
This commit is contained in:
commit
ac74774fcb
|
@ -308,7 +308,29 @@ end
|
||||||
if Vagrant.plugins_enabled?
|
if Vagrant.plugins_enabled?
|
||||||
begin
|
begin
|
||||||
global_logger.info("Loading plugins!")
|
global_logger.info("Loading plugins!")
|
||||||
$vagrant_bundler_runtime.require(:plugins)
|
plugins.each do |plugin_name, plugin_info|
|
||||||
|
if plugin_info["require"].to_s.empty?
|
||||||
|
begin
|
||||||
|
global_logger.debug("Loading plugin `#{plugin_name}` with default require: `#{plugin_name}`")
|
||||||
|
require plugin_name
|
||||||
|
rescue LoadError, Gem::LoadError => load_error
|
||||||
|
if plugin_name.include?("-")
|
||||||
|
begin
|
||||||
|
plugin_slash = plugin_name.gsub("-", "/")
|
||||||
|
global_logger.debug("Failed to load plugin `#{plugin_name}` with default require.")
|
||||||
|
global_logger.debug("Loading plugin `#{plugin_name}` with slash require: `#{plugin_slash}`")
|
||||||
|
require plugin_slash
|
||||||
|
rescue LoadError, Gem::LoadError
|
||||||
|
raise load_error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
global_logger.debug("Loading plugin `#{plugin_name}` with custom require: `#{plugin_info["require"]}`")
|
||||||
|
require plugin_info["require"]
|
||||||
|
end
|
||||||
|
global_logger.debug("Successfully loaded plugin `#{plugin_name}`.")
|
||||||
|
end
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
raise Vagrant::Errors::PluginLoadError, message: e.to_s
|
raise Vagrant::Errors::PluginLoadError, message: e.to_s
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,6 +27,7 @@ module Vagrant
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@plugin_gem_path = Vagrant.user_data_path.join("gems", RUBY_VERSION).freeze
|
@plugin_gem_path = Vagrant.user_data_path.join("gems", RUBY_VERSION).freeze
|
||||||
|
@logger = Log4r::Logger.new("vagrant::bundler")
|
||||||
end
|
end
|
||||||
|
|
||||||
# Initializes Bundler and the various gem paths so that we can begin
|
# Initializes Bundler and the various gem paths so that we can begin
|
||||||
|
@ -40,6 +41,8 @@ module Vagrant
|
||||||
Gem::Dependency.new(name, info['gem_version'].to_s.empty? ? '> 0' : info['gem_version'])
|
Gem::Dependency.new(name, info['gem_version'].to_s.empty? ? '> 0' : info['gem_version'])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@logger.debug("Current generated plugin dependency list: #{plugin_deps}")
|
||||||
|
|
||||||
# Load dependencies into a request set for resolution
|
# Load dependencies into a request set for resolution
|
||||||
request_set = Gem::RequestSet.new(*plugin_deps)
|
request_set = Gem::RequestSet.new(*plugin_deps)
|
||||||
# Never allow dependencies to be remotely satisfied during init
|
# Never allow dependencies to be remotely satisfied during init
|
||||||
|
@ -65,15 +68,19 @@ module Vagrant
|
||||||
# Compose set for resolution
|
# Compose set for resolution
|
||||||
composed_set = Gem::Resolver.compose_sets(current_set, plugin_set)
|
composed_set = Gem::Resolver.compose_sets(current_set, plugin_set)
|
||||||
|
|
||||||
|
@logger.debug("Composed local RubyGems set for plugin init resolution: #{composed_set}")
|
||||||
|
|
||||||
# Resolve the request set to ensure proper activation order
|
# Resolve the request set to ensure proper activation order
|
||||||
solution = request_set.resolve(composed_set)
|
solution = request_set.resolve(composed_set)
|
||||||
rescue Gem::UnsatisfiableDependencyError => failure
|
rescue Gem::UnsatisfiableDependencyError => failure
|
||||||
if repair
|
if repair
|
||||||
raise failure if @init_retried
|
raise failure if @init_retried
|
||||||
|
@logger.debug("Resolution failed but attempting to repair. Failure: #{failure}")
|
||||||
install(plugins)
|
install(plugins)
|
||||||
@init_retried = true
|
@init_retried = true
|
||||||
retry
|
retry
|
||||||
else
|
else
|
||||||
|
@logger.debug("#{failure.class}: #{failure}")
|
||||||
$stderr.puts "Vagrant failed to properly initialize due to an error while"
|
$stderr.puts "Vagrant failed to properly initialize due to an error while"
|
||||||
$stderr.puts "while attempting to load configured plugins. This can be caused"
|
$stderr.puts "while attempting to load configured plugins. This can be caused"
|
||||||
$stderr.puts "by manually tampering with the 'plugins.json' file, or by a"
|
$stderr.puts "by manually tampering with the 'plugins.json' file, or by a"
|
||||||
|
@ -85,13 +92,17 @@ module Vagrant
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@logger.debug("Initialization solution set: #{solution.map(&:full_name)}")
|
||||||
|
|
||||||
# Activate the gems
|
# Activate the gems
|
||||||
begin
|
begin
|
||||||
retried = false
|
retried = false
|
||||||
solution.each do |activation_request|
|
solution.each do |activation_request|
|
||||||
unless activation_request.full_spec.activated?
|
unless activation_request.full_spec.activated?
|
||||||
|
@logger.debug("Activating gem #{activation_request.full_spec.full_name}")
|
||||||
activation_request.full_spec.activate
|
activation_request.full_spec.activate
|
||||||
if(defined?(::Bundler))
|
if(defined?(::Bundler))
|
||||||
|
@logger.debug("Marking gem #{activation_request.full_spec.full_name} loaded within Bundler.")
|
||||||
::Bundler.rubygems.mark_loaded activation_request.full_spec
|
::Bundler.rubygems.mark_loaded activation_request.full_spec
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -114,6 +125,7 @@ module Vagrant
|
||||||
solution.map(&:full_spec)
|
solution.map(&:full_spec)
|
||||||
|
|
||||||
if(defined?(::Bundler))
|
if(defined?(::Bundler))
|
||||||
|
@logger.debug("Updating Bundler with full specification list")
|
||||||
::Bundler.rubygems.replace_entrypoints(full_vagrant_spec_list)
|
::Bundler.rubygems.replace_entrypoints(full_vagrant_spec_list)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -139,20 +151,17 @@ module Vagrant
|
||||||
#
|
#
|
||||||
# @param [String] path Path to a local gem file.
|
# @param [String] path Path to a local gem file.
|
||||||
# @return [Gem::Specification]
|
# @return [Gem::Specification]
|
||||||
def install_local(path)
|
def install_local(path, opts={})
|
||||||
installer = Gem::Installer.at(path,
|
plugin_source = Gem::Source::SpecificFile.new(path)
|
||||||
ignore_dependencies: true,
|
|
||||||
install_dir: plugin_gem_path.to_s
|
|
||||||
)
|
|
||||||
installer.install
|
|
||||||
new_spec = installer.spec
|
|
||||||
plugin_info = {
|
plugin_info = {
|
||||||
new_spec.name => {
|
plugin_source.spec.name => {
|
||||||
'gem_version' => new_spec.version.to_s
|
"local_source" => plugin_source,
|
||||||
|
"sources" => opts.fetch(:sources, Gem.sources.map(&:to_s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@logger.debug("Installing local plugin - #{plugin_info}")
|
||||||
internal_install(plugin_info, {})
|
internal_install(plugin_info, {})
|
||||||
new_spec
|
plugin_source.spec
|
||||||
end
|
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.
|
||||||
|
@ -228,8 +237,11 @@ module Vagrant
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def internal_install(plugins, update, **extra)
|
def internal_install(plugins, update, **extra)
|
||||||
|
# Only allow defined Gem sources
|
||||||
|
Gem.sources.clear
|
||||||
|
|
||||||
update = {} unless update.is_a?(Hash)
|
update = {} unless update.is_a?(Hash)
|
||||||
|
installer_set = Gem::Resolver::InstallerSet.new(:both)
|
||||||
|
|
||||||
# Generate all required plugin deps
|
# Generate all required plugin deps
|
||||||
plugin_deps = plugins.map do |name, info|
|
plugin_deps = plugins.map do |name, info|
|
||||||
|
@ -238,9 +250,20 @@ module Vagrant
|
||||||
else
|
else
|
||||||
gem_version = info['gem_version'].to_s.empty? ? '> 0' : info['gem_version']
|
gem_version = info['gem_version'].to_s.empty? ? '> 0' : info['gem_version']
|
||||||
end
|
end
|
||||||
|
if plugin_source = info.delete("local_source")
|
||||||
|
installer_set.add_local(plugin_source.spec.name, plugin_source.spec, plugin_source)
|
||||||
|
end
|
||||||
|
Array(info["sources"]).each do |source|
|
||||||
|
if !Gem.sources.include?(source)
|
||||||
|
@logger.debug("Adding RubyGems source for plugin install: #{source}")
|
||||||
|
Gem.sources << source
|
||||||
|
end
|
||||||
|
end
|
||||||
Gem::Dependency.new(name, gem_version)
|
Gem::Dependency.new(name, gem_version)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@logger.debug("Dependency list for installation: #{plugin_deps}")
|
||||||
|
|
||||||
# Create the request set for the new plugins
|
# Create the request set for the new plugins
|
||||||
request_set = Gem::RequestSet.new(*plugin_deps)
|
request_set = Gem::RequestSet.new(*plugin_deps)
|
||||||
|
|
||||||
|
@ -254,11 +277,14 @@ module Vagrant
|
||||||
request_set.import(existing_deps)
|
request_set.import(existing_deps)
|
||||||
|
|
||||||
# Generate the required solution set for new plugins
|
# Generate the required solution set for new plugins
|
||||||
solution = request_set.resolve(Gem::Resolver::InstallerSet.new(:both))
|
solution = request_set.resolve(installer_set)
|
||||||
|
|
||||||
|
@logger.debug("Generated solution set: #{solution.map(&:full_name)}")
|
||||||
|
|
||||||
# If any items in the solution set are local but not activated, turn them on
|
# If any items in the solution set are local but not activated, turn them on
|
||||||
solution.each do |activation_request|
|
solution.each do |activation_request|
|
||||||
if activation_request.installed? && !activation_request.full_spec.activated?
|
if activation_request.installed? && !activation_request.full_spec.activated?
|
||||||
|
@logger.debug("Activating gem specification: #{activation_request.full_spec.full_name}")
|
||||||
activation_request.full_spec.activate
|
activation_request.full_spec.activate
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,10 +44,9 @@ module Vagrant
|
||||||
local = false
|
local = false
|
||||||
if name =~ /\.gem$/
|
if name =~ /\.gem$/
|
||||||
# If this is a gem file, then we install that gem locally.
|
# If this is a gem file, then we install that gem locally.
|
||||||
local_spec = Vagrant::Bundler.instance.install_local(name)
|
local_spec = Vagrant::Bundler.instance.install_local(name, opts)
|
||||||
name = local_spec.name
|
name = local_spec.name
|
||||||
opts[:version] = local_spec.version.to_s
|
opts[:version] = local_spec.version.to_s
|
||||||
local = true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
plugins = installed_plugins
|
plugins = installed_plugins
|
||||||
|
@ -57,21 +56,24 @@ module Vagrant
|
||||||
"sources" => opts[:sources],
|
"sources" => opts[:sources],
|
||||||
}
|
}
|
||||||
|
|
||||||
result = nil
|
if local_spec.nil?
|
||||||
install_lambda = lambda do
|
result = nil
|
||||||
Vagrant::Bundler.instance.install(plugins, local).each do |spec|
|
install_lambda = lambda do
|
||||||
next if spec.name != name
|
Vagrant::Bundler.instance.install(plugins, local).each do |spec|
|
||||||
next if result && result.version >= spec.version
|
next if spec.name != name
|
||||||
result = spec
|
next if result && result.version >= spec.version
|
||||||
|
result = spec
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
if opts[:verbose]
|
if opts[:verbose]
|
||||||
Vagrant::Bundler.instance.verbose(&install_lambda)
|
Vagrant::Bundler.instance.verbose(&install_lambda)
|
||||||
|
else
|
||||||
|
install_lambda.call
|
||||||
|
end
|
||||||
else
|
else
|
||||||
install_lambda.call
|
result = local_spec
|
||||||
end
|
end
|
||||||
|
|
||||||
# Add the plugin to the state file
|
# Add the plugin to the state file
|
||||||
@user_file.add_plugin(
|
@user_file.add_plugin(
|
||||||
result.name,
|
result.name,
|
||||||
|
@ -124,8 +126,14 @@ module Vagrant
|
||||||
system[k] = v.merge("system" => true)
|
system[k] = v.merge("system" => true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
plugin_list = system.merge(@user_file.installed_plugins)
|
||||||
|
|
||||||
system.merge(@user_file.installed_plugins)
|
# Sort plugins by name
|
||||||
|
Hash[
|
||||||
|
plugin_list.map{|plugin_name, plugin_info|
|
||||||
|
[plugin_name, plugin_info]
|
||||||
|
}.sort_by(&:first)
|
||||||
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
# This returns the list of plugins that are installed as
|
# This returns the list of plugins that are installed as
|
||||||
|
|
|
@ -49,7 +49,7 @@ module Vagrant
|
||||||
#
|
#
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
def self.plugins_enabled?
|
def self.plugins_enabled?
|
||||||
!ENV["VAGRANT_NO_PLUGINS"] && $vagrant_bundler_runtime
|
!ENV["VAGRANT_NO_PLUGINS"]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Whether or not super quiet mode is enabled. This is ill-advised.
|
# Whether or not super quiet mode is enabled. This is ill-advised.
|
||||||
|
|
|
@ -13,15 +13,6 @@ module VagrantPlugins
|
||||||
options[:entry_point] = entry_point
|
options[:entry_point] = entry_point
|
||||||
end
|
end
|
||||||
|
|
||||||
# @deprecated
|
|
||||||
o.on("--plugin-prerelease",
|
|
||||||
"Allow prerelease versions of this plugin.") do |plugin_prerelease|
|
|
||||||
puts "--plugin-prelease is deprecated and will be removed in the next"
|
|
||||||
puts "version of Vagrant. It has no effect now. Use the '--plugin-version'"
|
|
||||||
puts "flag to get a specific pre-release version."
|
|
||||||
puts
|
|
||||||
end
|
|
||||||
|
|
||||||
o.on("--plugin-clean-sources",
|
o.on("--plugin-clean-sources",
|
||||||
"Remove all plugin sources defined so far (including defaults)") do |clean|
|
"Remove all plugin sources defined so far (including defaults)") do |clean|
|
||||||
options[:plugin_sources] = [] if clean
|
options[:plugin_sources] = [] if clean
|
||||||
|
|
|
@ -66,14 +66,10 @@ describe Vagrant::Plugin::Manager do
|
||||||
local_spec.name = "bar"
|
local_spec.name = "bar"
|
||||||
local_spec.version = version
|
local_spec.version = version
|
||||||
|
|
||||||
expect(bundler).to receive(:install_local).with(name).
|
expect(bundler).to receive(:install_local).with(name, {}).
|
||||||
ordered.and_return(local_spec)
|
ordered.and_return(local_spec)
|
||||||
|
|
||||||
expect(bundler).to receive(:install).once.with { |plugins, local|
|
expect(bundler).not_to receive(:install)
|
||||||
expect(plugins).to have_key("bar")
|
|
||||||
expect(plugins["bar"]["gem_version"]).to eql("#{version}")
|
|
||||||
expect(local).to be_true
|
|
||||||
}.ordered.and_return([local_spec])
|
|
||||||
|
|
||||||
subject.install_plugin(name)
|
subject.install_plugin(name)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue