Skip to content
Merged
14 changes: 4 additions & 10 deletions bundler/lib/bundler/gem_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,14 @@ module Bundler
module GemHelpers
GENERIC_CACHE = { Gem::Platform::RUBY => Gem::Platform::RUBY } # rubocop:disable Style/MutableConstant
GENERICS = [
[Gem::Platform.new("java"), Gem::Platform.new("java")],
[Gem::Platform.new("mswin32"), Gem::Platform.new("mswin32")],
[Gem::Platform.new("mswin64"), Gem::Platform.new("mswin64")],
[Gem::Platform.new("universal-mingw32"), Gem::Platform.new("universal-mingw32")],
[Gem::Platform.new("x64-mingw32"), Gem::Platform.new("x64-mingw32")],
[Gem::Platform.new("x86_64-mingw32"), Gem::Platform.new("x64-mingw32")],
[Gem::Platform.new("x64-mingw-ucrt"), Gem::Platform.new("x64-mingw-ucrt")],
[Gem::Platform.new("mingw32"), Gem::Platform.new("x86-mingw32")],
Gem::Platform::JAVA,
*Gem::Platform::WINDOWS,
].freeze

def generic(p)
GENERIC_CACHE[p] ||= begin
_, found = GENERICS.find do |match, _generic|
p.os == match.os && (!match.cpu || p.cpu == match.cpu)
found = GENERICS.find do |match|
p === match
end
found || Gem::Platform::RUBY
end
Expand Down
161 changes: 81 additions & 80 deletions bundler/lib/bundler/rubygems_ext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,87 @@ def open_file_with_lock(path, &block)
end
end

require "rubygems/platform"

class Platform
JAVA = Gem::Platform.new("java")
MSWIN = Gem::Platform.new("mswin32")
MSWIN64 = Gem::Platform.new("mswin64")
MINGW = Gem::Platform.new("x86-mingw32")
X64_MINGW = [Gem::Platform.new("x64-mingw32"),
Gem::Platform.new("x64-mingw-ucrt")].freeze
UNIVERSAL_MINGW = Gem::Platform.new("universal-mingw")
WINDOWS = [MSWIN, MSWIN64, UNIVERSAL_MINGW].flatten.freeze
X64_LINUX = Gem::Platform.new("x86_64-linux")
X64_LINUX_MUSL = Gem::Platform.new("x86_64-linux-musl")

if X64_LINUX === X64_LINUX_MUSL
remove_method :===

def ===(other)
return nil unless Gem::Platform === other

# universal-mingw32 matches x64-mingw-ucrt
return true if (@cpu == "universal" || other.cpu == "universal") &&
@os.start_with?("mingw") && other.os.start_with?("mingw")

# cpu
([nil,"universal"].include?(@cpu) || [nil, "universal"].include?(other.cpu) || @cpu == other.cpu ||
(@cpu == "arm" && other.cpu.start_with?("armv"))) &&

# os
@os == other.os &&

# version
(
(@os != "linux" && (@version.nil? || other.version.nil?)) ||
(@os == "linux" && (normalized_linux_version_ext == other.normalized_linux_version_ext || ["musl#{@version}", "musleabi#{@version}", "musleabihf#{@version}"].include?(other.version))) ||
@version == other.version
)
end

# This is a copy of RubyGems 3.3.23 or higher `normalized_linux_method`.
# Once only 3.3.23 is supported, we can use the method in RubyGems.
def normalized_linux_version_ext
return nil unless @version

without_gnu_nor_abi_modifiers = @version.sub(/\Agnu/, "").sub(/eabi(hf)?\Z/, "")
return nil if without_gnu_nor_abi_modifiers.empty?

without_gnu_nor_abi_modifiers
end
end
end

Platform.singleton_class.module_eval do
unless Platform.singleton_methods.include?(:match_spec?)
def match_spec?(spec)
match_gem?(spec.platform, spec.name)
end

def match_gem?(platform, gem_name)
match_platforms?(platform, Gem.platforms)
end
end

match_platforms_defined = Gem::Platform.respond_to?(:match_platforms?, true)

if !match_platforms_defined || Gem::Platform.send(:match_platforms?, Gem::Platform::X64_LINUX_MUSL, [Gem::Platform::X64_LINUX])

private

remove_method :match_platforms? if match_platforms_defined

def match_platforms?(platform, platforms)
platforms.any? do |local_platform|
platform.nil? ||
local_platform == platform ||
(local_platform != Gem::Platform::RUBY && platform =~ local_platform)
end
end
end
end

require "rubygems/specification"

# Can be removed once RubyGems 3.5.14 support is dropped
Expand Down Expand Up @@ -288,86 +369,6 @@ def matching_specs(platform_only = false)
end
end

require "rubygems/platform"

class Platform
JAVA = Gem::Platform.new("java")
MSWIN = Gem::Platform.new("mswin32")
MSWIN64 = Gem::Platform.new("mswin64")
MINGW = Gem::Platform.new("x86-mingw32")
X64_MINGW = [Gem::Platform.new("x64-mingw32"),
Gem::Platform.new("x64-mingw-ucrt")].freeze
WINDOWS = [MSWIN, MSWIN64, MINGW, X64_MINGW].flatten.freeze
X64_LINUX = Gem::Platform.new("x86_64-linux")
X64_LINUX_MUSL = Gem::Platform.new("x86_64-linux-musl")

if X64_LINUX === X64_LINUX_MUSL
remove_method :===

def ===(other)
return nil unless Gem::Platform === other

# universal-mingw32 matches x64-mingw-ucrt
return true if (@cpu == "universal" || other.cpu == "universal") &&
@os.start_with?("mingw") && other.os.start_with?("mingw")

# cpu
([nil,"universal"].include?(@cpu) || [nil, "universal"].include?(other.cpu) || @cpu == other.cpu ||
(@cpu == "arm" && other.cpu.start_with?("armv"))) &&

# os
@os == other.os &&

# version
(
(@os != "linux" && (@version.nil? || other.version.nil?)) ||
(@os == "linux" && (normalized_linux_version_ext == other.normalized_linux_version_ext || ["musl#{@version}", "musleabi#{@version}", "musleabihf#{@version}"].include?(other.version))) ||
@version == other.version
)
end

# This is a copy of RubyGems 3.3.23 or higher `normalized_linux_method`.
# Once only 3.3.23 is supported, we can use the method in RubyGems.
def normalized_linux_version_ext
return nil unless @version

without_gnu_nor_abi_modifiers = @version.sub(/\Agnu/, "").sub(/eabi(hf)?\Z/, "")
return nil if without_gnu_nor_abi_modifiers.empty?

without_gnu_nor_abi_modifiers
end
end
end

Platform.singleton_class.module_eval do
unless Platform.singleton_methods.include?(:match_spec?)
def match_spec?(spec)
match_gem?(spec.platform, spec.name)
end

def match_gem?(platform, gem_name)
match_platforms?(platform, Gem.platforms)
end
end

match_platforms_defined = Gem::Platform.respond_to?(:match_platforms?, true)

if !match_platforms_defined || Gem::Platform.send(:match_platforms?, Gem::Platform::X64_LINUX_MUSL, [Gem::Platform::X64_LINUX])

private

remove_method :match_platforms? if match_platforms_defined

def match_platforms?(platform, platforms)
platforms.any? do |local_platform|
platform.nil? ||
local_platform == platform ||
(local_platform != Gem::Platform::RUBY && platform =~ local_platform)
end
end
end
end

# On universal Rubies, resolve the "universal" arch to the real CPU arch, without changing the extension directory.
class BasicSpecification
if /^universal\.(?<arch>.*?)-/ =~ (CROSS_COMPILING || RUBY_PLATFORM)
Expand Down
4 changes: 4 additions & 0 deletions bundler/lib/bundler/spec_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,10 @@ def valid?(s)
s.matches_current_metadata? && valid_dependencies?(s)
end

def to_s
map(&:full_name).to_s
end

private

def materialize_dependencies(dependencies, platforms = [nil], skips: [])
Expand Down
6 changes: 3 additions & 3 deletions bundler/spec/bundler/lockfile_parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@
end
let(:specs) do
[
Bundler::LazySpecification.new("peiji-san", v("1.2.0"), rb),
Bundler::LazySpecification.new("rake", v("10.3.2"), rb),
Bundler::LazySpecification.new("peiji-san", v("1.2.0"), Gem::Platform::RUBY),
Bundler::LazySpecification.new("rake", v("10.3.2"), Gem::Platform::RUBY),
]
end
let(:platforms) { [rb] }
let(:platforms) { [Gem::Platform::RUBY] }
let(:bundler_version) { Gem::Version.new("1.12.0.rc.2") }
let(:ruby_version) { "ruby 2.1.3p242" }
let(:lockfile_path) { Bundler.default_lockfile.relative_path_from(Dir.pwd) }
Expand Down
6 changes: 3 additions & 3 deletions bundler/spec/bundler/source_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class ExampleSource < Bundler::Source
end

describe "#version_message" do
let(:spec) { double(:spec, name: "nokogiri", version: ">= 1.6", platform: rb) }
let(:spec) { double(:spec, name: "nokogiri", version: ">= 1.6", platform: Gem::Platform::RUBY) }

shared_examples_for "the lockfile specs are not relevant" do
it "should return a string with the spec name and version" do
Expand Down Expand Up @@ -70,7 +70,7 @@ class ExampleSource < Bundler::Source
end

context "with a more recent version" do
let(:spec) { double(:spec, name: "nokogiri", version: "1.6.1", platform: rb) }
let(:spec) { double(:spec, name: "nokogiri", version: "1.6.1", platform: Gem::Platform::RUBY) }
let(:locked_gem) { double(:locked_gem, name: "nokogiri", version: "1.7.0") }

context "with color", :no_color_tty do
Expand All @@ -97,7 +97,7 @@ class ExampleSource < Bundler::Source
end

context "with an older version" do
let(:spec) { double(:spec, name: "nokogiri", version: "1.7.1", platform: rb) }
let(:spec) { double(:spec, name: "nokogiri", version: "1.7.1", platform: Gem::Platform::RUBY) }
let(:locked_gem) { double(:locked_gem, name: "nokogiri", version: "1.7.0") }

context "with color", :no_color_tty do
Expand Down
13 changes: 12 additions & 1 deletion bundler/spec/commands/install_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@
end

it "installs gems for windows" do
simulate_platform x86_mswin32 do
simulate_platform "x86-mswin32" do
install_gemfile <<-G
source "https://gem.repo1"
gem "platform_specific"
Expand All @@ -290,6 +290,17 @@
expect(the_bundle).to include_gems("platform_specific 1.0 x86-mswin32")
end
end

it "installs gems for aarch64-mingw-ucrt" do
simulate_platform "aarch64-mingw-ucrt" do
install_gemfile <<-G
source "https://gem.repo1"
gem "platform_specific"
G
end

expect(out).to include("Installing platform_specific 1.0 (aarch64-mingw-ucrt)")
end
end

describe "doing bundle install foo" do
Expand Down
19 changes: 7 additions & 12 deletions bundler/spec/commands/lock_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -765,8 +765,7 @@
bundle "lock --add-platform java x86-mingw32"

allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
lockfile = Bundler::LockfileParser.new(read_lockfile)
expect(lockfile.platforms).to match_array(default_platform_list(java, x86_mingw32))
expect(the_bundle.locked_platforms).to match_array(default_platform_list("java", "x86-mingw32"))
end

it "supports adding new platforms, when most specific locked platform is not the current platform, and current resolve is not compatible with the target platform" do
Expand Down Expand Up @@ -845,16 +844,14 @@
bundle "lock --add-platform java x86-mingw32"

allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
lockfile = Bundler::LockfileParser.new(read_lockfile)
expect(lockfile.platforms).to contain_exactly(rb, linux, java, x86_mingw32)
expect(the_bundle.locked_platforms).to contain_exactly(Gem::Platform::RUBY, "x86_64-linux", "java", "x86-mingw32")
end

it "supports adding the `ruby` platform" do
bundle "lock --add-platform ruby"

allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
lockfile = Bundler::LockfileParser.new(read_lockfile)
expect(lockfile.platforms).to match_array(default_platform_list("ruby"))
expect(the_bundle.locked_platforms).to match_array(default_platform_list("ruby"))
end

it "fails when adding an unknown platform" do
Expand All @@ -867,13 +864,11 @@
bundle "lock --add-platform java x86-mingw32"

allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
lockfile = Bundler::LockfileParser.new(read_lockfile)
expect(lockfile.platforms).to match_array(default_platform_list(java, x86_mingw32))
expect(the_bundle.locked_platforms).to match_array(default_platform_list("java", "x86-mingw32"))

bundle "lock --remove-platform java"

lockfile = Bundler::LockfileParser.new(read_lockfile)
expect(lockfile.platforms).to match_array(default_platform_list(x86_mingw32))
expect(the_bundle.locked_platforms).to match_array(default_platform_list("x86-mingw32"))
end

it "also cleans up redundant platform gems when removing platforms" do
Expand Down Expand Up @@ -948,7 +943,7 @@
build_repo4 do
build_gem "ffi", "1.9.14"
build_gem "ffi", "1.9.14" do |s|
s.platform = x86_mingw32
s.platform = "x86-mingw32"
end

build_gem "gssapi", "0.1"
Expand Down Expand Up @@ -980,7 +975,7 @@
gem "gssapi"
G

simulate_platform(x86_mingw32) { bundle :lock }
simulate_platform("x86-mingw32") { bundle :lock }

checksums = checksums_section_when_enabled do |c|
c.checksum gem_repo4, "ffi", "1.9.14", "x86-mingw32"
Expand Down
4 changes: 2 additions & 2 deletions bundler/spec/commands/update_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1132,7 +1132,7 @@
a
L

simulate_platform linux, &example
simulate_platform "x86_64-linux", &example
end

it "allows updating" do
Expand Down Expand Up @@ -1173,7 +1173,7 @@
end

it "is not updated because it is not actually included in the bundle" do
simulate_platform linux do
simulate_platform "x86_64-linux" do
bundle "update a"
expect(last_command.stdboth).to include "Bundler attempted to update a but it was not considered because it is for a different platform from the current one"
expect(the_bundle).to_not include_gem "a"
Expand Down
Loading
Loading