Merge pull request #8031 from chrisroberts/internal-and-bundler

Always apply builtin constraints within dependency restrictions
This commit is contained in:
Chris Roberts 2016-11-22 08:14:53 -08:00 committed by GitHub
commit 3a1ea7a8e0
2 changed files with 68 additions and 10 deletions

View File

@ -4,18 +4,14 @@ sudo: false
cache: bundler
before_install:
- gem uninstall bundler -aIxq --force
- gem uninstall -Ixq --force -i /home/travis/.rvm/gems/ruby-2.2.3@global bundler
- gem install bundler -v '1.12.5'
addons:
apt:
packages:
- bsdtar
rvm:
- 2.2.3
- 2.2.5
- 2.3.3
branches:
only:

View File

@ -52,7 +52,6 @@ module Vagrant
begin
# Compose set for resolution
composed_set = generate_vagrant_set
@logger.debug("Composed local RubyGems set for plugin init resolution: #{composed_set}")
# Resolve the request set to ensure proper activation order
solution = request_set.resolve(composed_set)
rescue Gem::UnsatisfiableDependencyError => failure
@ -128,6 +127,7 @@ module Vagrant
# Clean removes any unused gems.
def clean(plugins)
@logger.debug("Cleaning Vagrant plugins of stale gems.")
# Generate dependencies for all registered plugins
plugin_deps = plugins.map do |name, info|
gem_version = info['installed_gem_version']
@ -136,6 +136,8 @@ module Vagrant
Gem::Dependency.new(name, gem_version)
end
@logger.debug("Current plugin dependency list: #{plugin_deps}")
# Load dependencies into a request set for resolution
request_set = Gem::RequestSet.new(*plugin_deps)
# Never allow dependencies to be remotely satisfied during cleaning
@ -151,6 +153,8 @@ module Vagrant
Gem::Specification.load(spec_path)
end
@logger.debug("Generating current plugin state solution set.")
# Resolve the request set to ensure proper activation order
solution = request_set.resolve(current_set)
solution_specs = solution.map(&:full_spec)
@ -228,20 +232,31 @@ module Vagrant
request_set = Gem::RequestSet.new(*plugin_deps)
# Generate all existing deps within the "vagrant system"
existing_deps = Gem::Specification.find_all{true}.map do |item|
existing_deps = vagrant_internal_specs.map do |item|
@logger.debug("Activating builtin specification: #{item.full_name}")
Gem::Dependency.new(item.name, item.version)
end
@logger.debug("Required constraints from builtin gems: #{existing_deps}")
# Import constraints into the request set to prevent installing
# gems that are incompatible with the core system
request_set.import(existing_deps)
installer_set = Gem::Resolver.compose_sets(installer_set, generate_plugin_set(skips))
installer_set = Gem::Resolver.compose_sets(
installer_set,
generate_builtin_set,
generate_plugin_set(skips)
)
@logger.debug("Generating solution set for installation.")
# Generate the required solution set for new plugins
solution = request_set.resolve(installer_set)
activate_solution(solution)
@logger.debug("Installing required gems.")
# Install all remote gems into plugin path. Set the installer to ignore dependencies
# as we know the dependencies are satisfied and it will attempt to validate a gem's
# dependencies are satisified by gems in the install directory (which will likely not
@ -256,9 +271,32 @@ module Vagrant
Gem::Resolver.compose_sets(generate_builtin_set, generate_plugin_set)
end
# @return [Array<[Gem::Specification, String]>] spec and directory pairs
def vagrant_internal_specs
list = {}
directories = [Gem::Specification.default_specifications_dir]
Gem::Specification.find_all{true}.each do |spec|
list[spec.full_name] = spec
end
directories += Gem::Specification.dirs.find_all do |path|
!path.start_with?(Gem.user_dir)
end
Gem::Specification.each_spec(directories) do |spec|
if !list[spec.full_name]
list[spec.full_name] = spec
end
end
list.values
end
# Generate the builtin resolver set
def generate_builtin_set
Gem::Resolver::CurrentSet.new
builtin_set = BuiltinSet.new
@logger.debug("Generating new builtin set instance.")
vagrant_internal_specs.each do |spec|
builtin_set.add_builtin_spec(spec)
end
builtin_set
end
# Generate the plugin resolver set. Optionally provide specification names (short or
@ -312,6 +350,30 @@ module Vagrant
end
end
# This is a custom Gem::Resolver::Set for use with vagrant "system" gems. It
# allows the installed set of gems to be used for providing a solution while
# enforcing strict constraints. This ensures that plugins cannot "upgrade"
# gems that are builtin to vagrant itself.
class BuiltinSet < Gem::Resolver::Set
def initialize
super
@remote = false
@specs = []
end
def add_builtin_spec(spec)
@specs.push(spec).uniq!
end
def find_all(req)
@specs.select do |spec|
req.match?(spec)
end.map do |spec|
Gem::Resolver::InstalledSpecification.new(self, spec)
end
end
end
# This is a custom Gem::Resolver::Set for use with Vagrant plugins. It is
# a modified Gem::Resolver::VendorSet that supports multiple versions of
# a specific gem