diff options
| -rw-r--r-- | lib/bundler/spec_set.rb | 16 | ||||
| -rw-r--r-- | spec/bundler/bundler/spec_set_spec.rb | 52 |
2 files changed, 66 insertions, 2 deletions
diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index e8d990d207..ae5e5cbaa9 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -274,13 +274,25 @@ module Bundler valid_platform = lookup.all? do |_, specs| spec = specs.first + # The matching candidates returned by source.specs.search are remote + # specs that do not carry the override list themselves. Borrow it from + # the LazySpec we are validating so platform-variant validation honors + # the same overrides the install/resolve path already applies. + overrides = spec.is_a?(LazySpecification) ? Array(spec.overrides) : [] matching_specs = spec.source.specs.search([spec.name, spec.version]) platform_spec = MatchPlatform.select_best_platform_match(matching_specs, platform).find do |s| - valid?(s) + s.matches_current_metadata_with_overrides?(overrides) && valid_dependencies?(s) end if platform_spec - new_specs << LazySpecification.from_spec(platform_spec) unless specs.include?(platform_spec) + unless specs.include?(platform_spec) + new_lazy = LazySpecification.from_spec(platform_spec) + # Carry the overrides forward so a follow-up complete_platform + # call that picks this synthesized variant as its exemplar still + # honors the user's override list. + new_lazy.overrides = overrides if overrides.any? + new_specs << new_lazy + end true else false diff --git a/spec/bundler/bundler/spec_set_spec.rb b/spec/bundler/bundler/spec_set_spec.rb index 3e630555e6..1e1ceadf26 100644 --- a/spec/bundler/bundler/spec_set_spec.rb +++ b/spec/bundler/bundler/spec_set_spec.rb @@ -93,4 +93,56 @@ RSpec.describe Bundler::SpecSet do end end + describe "#complete_platform" do + let(:platform) { Gem::Platform.new("x86_64-linux") } + + let(:platform_variant) do + build_spec("needs_old_ruby", "1.0", platform).first.tap do |s| + s.required_ruby_version = Gem::Requirement.new("< #{Gem.ruby_version}") + end + end + + let(:lazy_spec) do + lazy = Bundler::LazySpecification.new("needs_old_ruby", Gem::Version.new("1.0"), Gem::Platform::RUBY) + lazy.required_ruby_version = Gem::Requirement.new("< #{Gem.ruby_version}") + source = double("source") + source_specs = double("source_specs") + allow(source).to receive(:specs).and_return(source_specs) + allow(source_specs).to receive(:search). + with(["needs_old_ruby", Gem::Version.new("1.0")]).and_return([platform_variant]) + lazy.source = source + lazy + end + + it "rejects a platform variant whose strict metadata is incompatible when no override is attached" do + set = described_class.new([lazy_spec]) + expect(set.send(:complete_platform, platform)).to be(false) + end + + it "accepts a platform variant when the LazySpec carries an override that allows it" do + lazy_spec.overrides = [Bundler::Override.new("needs_old_ruby", :required_ruby_version, :ignore_upper)] + set = described_class.new([lazy_spec]) + expect(set.send(:complete_platform, platform)).to be(true) + end + + it "carries overrides onto a synthesized LazySpec so a follow-up complete_platform still honors them" do + override = Bundler::Override.new("needs_old_ruby", :required_ruby_version, :ignore_upper) + lazy_spec.overrides = [override] + second_platform = Gem::Platform.new("aarch64-linux") + second_variant = build_spec("needs_old_ruby", "1.0", second_platform).first.tap do |s| + s.required_ruby_version = Gem::Requirement.new("< #{Gem.ruby_version}") + end + allow(lazy_spec.source.specs).to receive(:search). + with(["needs_old_ruby", Gem::Version.new("1.0")]).and_return([platform_variant, second_variant]) + + set = described_class.new([lazy_spec]) + expect(set.send(:complete_platform, platform)).to be(true) + # The synthesized x86_64-linux variant is now in the set. If lookup + # picks it as exemplar for the next platform check, the override list + # must still be reachable via its overrides accessor. + synthesized = set.to_a.find {|s| s.platform == platform } + expect(synthesized.overrides).to eq([override]) + expect(set.send(:complete_platform, second_platform)).to be(true) + end + end end |
