Merge pull request #8031 from chrisroberts/internal-and-bundler
Always apply builtin constraints within dependency restrictions
This commit is contained in:
commit
3a1ea7a8e0
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue