Skip to content

Commit

Permalink
Improve platform specific gem resolution
Browse files Browse the repository at this point in the history
It resolves rubygems#6247. This changes includes the patches that add (RSpec)
specs for this situation in rubygems#6247.

If there is a platform specific gem but it can't be resolved available
version, Bundler reports an error.

For example,

    @Index = build_index do
      gem "bar", "1.0.0"
      gem "foo", "1.0.0"
      gem "foo", "1.0.0", "x64-mingw32" do
        dep "bar", "< 1"
      end
    end
    dep "foo"
    platforms "x64-mingw32"

raises an error because foo-1.0.0-x64-mingw32 requires bar<1 but there
isn't bar<1.

With this change, foo-1.0.0 (no x64-mingw32) is used as
fallback. Because foo-1.0.0 doesn't depend on bar<1.
  • Loading branch information
kou committed Jan 7, 2020
1 parent ecb9800 commit 0f8fd0a
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 6 deletions.
20 changes: 16 additions & 4 deletions lib/bundler/resolver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,21 @@ def search_for(dependency)
@gem_version_promoter.sort_versions(dependency, spec_groups)
end
end
search.select {|sg| sg.for?(platform) }.each {|sg| sg.activate_platform!(platform) }
selected_sgs = []
search.each do |sg|
next unless sg.for?(platform)
sg.activate_platform!(platform)
if sg.spec(platform).platform != Gem::Platform::RUBY
sg_ruby = SpecGroup.new(sg.all_specs)
sg_ruby.ignores_bundler_dependencies = sg.ignores_bundler_dependencies
if sg_ruby.for?(Gem::Platform::RUBY)
sg_ruby.activate_platform!(Gem::Platform::RUBY)
selected_sgs << sg_ruby
end
end
selected_sgs << sg
end
selected_sgs
end

def index_for(dependency)
Expand Down Expand Up @@ -183,9 +197,7 @@ def name_for_locking_dependency_source
end

def requirement_satisfied_by?(requirement, activated, spec)
return false unless requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec)
spec.activate_platform!(requirement.__platform) if !@platforms || @platforms.include?(requirement.__platform)
true
requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec)
end

def relevant_sources_for_vertex(vertex)
Expand Down
9 changes: 7 additions & 2 deletions lib/bundler/resolver/spec_group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ class Resolver
class SpecGroup
include GemHelpers

attr_reader :all_specs
attr_accessor :name, :version, :source
attr_accessor :ignores_bundler_dependencies

def initialize(all_specs)
@all_specs = all_specs
raise ArgumentError, "cannot initialize with an empty value" unless exemplary_spec = all_specs.first
@name = exemplary_spec.name
@version = exemplary_spec.version
Expand Down Expand Up @@ -37,9 +39,12 @@ def activate_platform!(platform)
@activated_platforms << platform
end

def spec(platform)
@specs[platform]
end

def for?(platform)
spec = @specs[platform]
!spec.nil?
!spec(platform).nil?
end

def to_s
Expand Down
11 changes: 11 additions & 0 deletions spec/resolver/platform_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@
should_resolve_as %w[foo-1.0.0]
end

it "prefers the platform specific gem to the ruby version" do
@index = build_index do
gem "foo", "1.0.0"
gem "foo", "1.0.0", "x64-mingw32"
end
dep "foo"
platforms "x64-mingw32"

should_resolve_as %w[foo-1.0.0-x64-mingw32]
end

it "takes the latest ruby gem if the platform specific gem doesn't match the required_ruby_version" do
@index = build_index do
gem "foo", "1.0.0"
Expand Down

0 comments on commit 0f8fd0a

Please sign in to comment.