Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sort requirements in Gem::Requirement to succeed comparison with different order #3889

Merged
merged 8 commits into from Sep 8, 2020
29 changes: 29 additions & 0 deletions bundler/lib/bundler/rubygems_ext.rb
Expand Up @@ -129,6 +129,35 @@ def to_lock
end
end

# comparison is done order independently since rubygems 3.2.0.rc.2
unless Gem::Requirement.new("> 1", "< 2") == Gem::Requirement.new("< 2", "> 1")
deivid-rodriguez marked this conversation as resolved.
Show resolved Hide resolved
class Requirement
module OrderIndependentComparison
def ==(other)
if _requirements_sorted? && other._requirements_sorted?
super
else
_with_sorted_requirements == other._with_sorted_requirements
end
end

protected

def _requirements_sorted?
return @_are_requirements_sorted if defined?(@_are_requirements_sorted)
strings = as_list
@_are_requirements_sorted = strings == strings.sort
end

def _with_sorted_requirements
@_with_sorted_requirements ||= _requirements_sorted? ? self : self.class.new(as_list.sort)
end
end

prepend OrderIndependentComparison
end
end

class Platform
JAVA = Gem::Platform.new("java") unless defined?(JAVA)
MSWIN = Gem::Platform.new("mswin32") unless defined?(MSWIN)
Expand Down
29 changes: 29 additions & 0 deletions bundler/spec/install/gemfile/platform_spec.rb
Expand Up @@ -256,6 +256,35 @@
expect(the_bundle).not_to include_gem "CFPropertyList"
end

it "works with gems with platform-specific dependency having different requirements order" do
simulate_platform x64_mac

update_repo2 do
build_gem "fspath", "3"
build_gem "image_optim_pack", "1.2.3" do |s|
s.add_runtime_dependency "fspath", ">= 2.1", "< 4"
end
build_gem "image_optim_pack", "1.2.3" do |s|
s.platform = "universal-darwin"
s.add_runtime_dependency "fspath", "< 4", ">= 2.1"
end
end

install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
G

install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"

gem "image_optim_pack"
G

expect(err).not_to include "Unable to use the platform-specific"

expect(the_bundle).to include_gem "image_optim_pack 1.2.3 universal-darwin"
end

it "fetches gems again after changing the version of Ruby" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
Expand Down
8 changes: 6 additions & 2 deletions lib/rubygems/requirement.rb
Expand Up @@ -270,7 +270,7 @@ def ==(other) # :nodoc:
return unless Gem::Requirement === other

# An == check is always necessary
return false unless requirements == other.requirements
return false unless _sorted_requirements == other._sorted_requirements

# An == check is sufficient unless any requirements use ~>
return true unless _tilde_requirements.any?
Expand All @@ -282,8 +282,12 @@ def ==(other) # :nodoc:

protected

def _sorted_requirements
@_sorted_requirements ||= requirements.sort_by(&:to_s)
end

def _tilde_requirements
requirements.select {|r| r.first == "~>" }
@_tilde_requirements ||= _sorted_requirements.select {|r| r.first == "~>" }
end

private
Expand Down
2 changes: 2 additions & 0 deletions test/rubygems/test_gem_requirement.rb
Expand Up @@ -22,6 +22,8 @@ def test_equals2
refute_requirement_equal "~> 1.3", "~> 1.3.0"
refute_requirement_equal "~> 1.3.0", "~> 1.3"

assert_requirement_equal ["> 2", "~> 1.3", "~> 1.3.1"], ["~> 1.3.1", "~> 1.3", "> 2"]

assert_requirement_equal ["> 2", "~> 1.3"], ["> 2.0", "~> 1.3"]
assert_requirement_equal ["> 2.0", "~> 1.3"], ["> 2", "~> 1.3"]

Expand Down