diff options
Diffstat (limited to 'lib/bundler/resolver.rb')
-rw-r--r-- | lib/bundler/resolver.rb | 75 |
1 files changed, 47 insertions, 28 deletions
diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index 8812ba5ede..0f17ba3afb 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -5,6 +5,8 @@ module Bundler require_relative "vendored_molinillo" require_relative "resolver/spec_group" + include GemHelpers + # Figures out the best possible configuration of gems that satisfies # the list of passed dependencies and any child dependencies without # causing any gem activation errors. @@ -16,7 +18,6 @@ module Bundler # <GemBundle>,nil:: If the list of dependencies can be resolved, a # collection of gemspecs is returned. Otherwise, nil is returned. def self.resolve(requirements, index, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil) - platforms = Set.new(platforms) if platforms base = SpecSet.new(base) unless base.is_a?(SpecSet) resolver = new(index, source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) result = resolver.start(requirements) @@ -36,9 +37,13 @@ module Bundler end additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) } @platforms = platforms + @resolving_only_for_ruby = platforms == [Gem::Platform::RUBY] @gem_version_promoter = gem_version_promoter @use_gvp = Bundler.feature_flag.use_gem_version_promoter_for_major_updates? || !@gem_version_promoter.major? @lockfile_uses_separate_rubygems_sources = Bundler.feature_flag.disable_multisource? + + @variant_specific_names = [] + @generic_names = [] end def start(requirements) @@ -102,14 +107,24 @@ module Bundler include Molinillo::SpecificationProvider def dependencies_for(specification) - specification.dependencies_for_activated_platforms + all_dependencies = specification.dependencies_for_activated_platforms + + if @variant_specific_names.include?(specification.name) + @variant_specific_names |= all_dependencies.map(&:name) - @generic_names + else + generic_names, variant_specific_names = specification.partitioned_dependency_names_for_activated_platforms + @variant_specific_names |= variant_specific_names - @generic_names + @generic_names |= generic_names + end + + all_dependencies end def search_for(dependency_proxy) platform = dependency_proxy.__platform dependency = dependency_proxy.dep - @search_for[dependency_proxy] ||= begin - name = dependency.name + name = dependency.name + search_result = @search_for[dependency_proxy] ||= begin index = index_for(dependency) results = index.search(dependency, @base[name]) @@ -136,37 +151,48 @@ module Bundler end nested.reduce([]) do |groups, (version, specs)| next groups if locked_requirement && !locked_requirement.satisfied_by?(version) - spec_group = SpecGroup.new(specs) - groups << spec_group + + specs_by_platform = Hash.new do |current_specs, current_platform| + current_specs[current_platform] = select_best_platform_match(specs, current_platform) + end + + spec_group_ruby = SpecGroup.create_for(specs_by_platform, [Gem::Platform::RUBY], Gem::Platform::RUBY) + groups << spec_group_ruby if spec_group_ruby + + next groups if @resolving_only_for_ruby + + spec_group = SpecGroup.create_for(specs_by_platform, @platforms, platform) + groups << spec_group if spec_group + + groups end else [] end # GVP handles major itself, but it's still a bit risky to trust it with it # until we get it settled with new behavior. For 2.x it can take over all cases. - search = if !@use_gvp + if !@use_gvp spec_groups else @gem_version_promoter.sort_versions(dependency, spec_groups) end - selected_sgs = [] - search.each do |sg| - next unless sg.for?(platform) - sg_all_platforms = sg.copy_for(self.class.sort_platforms(@platforms).reverse) - next unless sg_all_platforms - - selected_sgs << sg_all_platforms + end - next if sg_all_platforms.activated_platforms == [Gem::Platform::RUBY] - # Add a spec group for "non platform specific spec" as the fallback - # spec group. - sg_ruby = sg.copy_for([Gem::Platform::RUBY]) - next unless sg_ruby + unless search_result.empty? + specific_dependency = @variant_specific_names.include?(name) + return search_result unless specific_dependency - selected_sgs.insert(-2, sg_ruby) + search_result.each do |sg| + if @generic_names.include?(name) + @variant_specific_names -= [name] + sg.activate_all_platforms! + else + sg.activate_platform!(platform) + end end - selected_sgs end + + search_result end def index_for(dependency) @@ -237,13 +263,6 @@ module Bundler end end - # Sort platforms from most general to most specific - def self.sort_platforms(platforms) - platforms.sort_by do |platform| - platform_sort_key(platform) - end - end - def self.platform_sort_key(platform) # Prefer specific platform to not specific platform return ["99-LAST", "", "", ""] if Gem::Platform::RUBY == platform |