ruby/spec/bundler/install/gemfile/platform_spec.rb
David Rodríguez e67f595e8f [rubygems/rubygems] Build bundler gem just once for specs
When we need to reset system gems during specs, there's no need to
rebuild bundler, we can copy over the original gem home.

7b4f80747b
2025-07-25 11:10:37 +09:00

638 lines
15 KiB
Ruby

# frozen_string_literal: true
RSpec.describe "bundle install across platforms" do
it "maintains the same lockfile if all gems are compatible across platforms" do
lockfile <<-G
GEM
remote: https://gem.repo1/
specs:
myrack (0.9.1)
PLATFORMS
#{not_local}
DEPENDENCIES
myrack
G
install_gemfile <<-G
source "https://gem.repo1"
gem "myrack"
G
expect(the_bundle).to include_gems "myrack 0.9.1"
end
it "pulls in the correct platform specific gem" do
lockfile <<-G
GEM
remote: https://gem.repo1
specs:
platform_specific (1.0)
platform_specific (1.0-java)
platform_specific (1.0-x86-mswin32)
PLATFORMS
ruby
DEPENDENCIES
platform_specific
G
simulate_platform "java" do
install_gemfile <<-G
source "https://gem.repo1"
gem "platform_specific"
G
expect(the_bundle).to include_gems "platform_specific 1.0 java"
end
end
it "pulls the pure ruby version on jruby if the java platform is not present in the lockfile and bundler is run in frozen mode", :jruby_only do
lockfile <<-G
GEM
remote: https://gem.repo1
specs:
platform_specific (1.0)
PLATFORMS
ruby
DEPENDENCIES
platform_specific
G
bundle "config set --local frozen true"
install_gemfile <<-G
source "https://gem.repo1"
gem "platform_specific"
G
expect(the_bundle).to include_gems "platform_specific 1.0 ruby"
expect(err).to be_empty
end
context "on universal Rubies" do
before do
build_repo4 do
build_gem "darwin_single_arch" do |s|
s.platform = "ruby"
end
build_gem "darwin_single_arch" do |s|
s.platform = "arm64-darwin"
end
build_gem "darwin_single_arch" do |s|
s.platform = "x86_64-darwin"
end
end
end
it "pulls in the correct architecture gem" do
lockfile <<-G
GEM
remote: https://gem.repo4
specs:
darwin_single_arch (1.0)
darwin_single_arch (1.0-arm64-darwin)
darwin_single_arch (1.0-x86_64-darwin)
PLATFORMS
ruby
DEPENDENCIES
darwin_single_arch
G
simulate_platform "universal-darwin-21" do
simulate_ruby_platform "universal.x86_64-darwin21" do
install_gemfile <<-G
source "https://gem.repo4"
gem "darwin_single_arch"
G
expect(the_bundle).to include_gems "darwin_single_arch 1.0 x86_64-darwin"
end
end
end
it "pulls in the correct architecture gem on arm64e macOS Ruby" do
lockfile <<-G
GEM
remote: https://gem.repo4
specs:
darwin_single_arch (1.0)
darwin_single_arch (1.0-arm64-darwin)
darwin_single_arch (1.0-x86_64-darwin)
PLATFORMS
ruby
DEPENDENCIES
darwin_single_arch
G
simulate_platform "universal-darwin-21" do
simulate_ruby_platform "universal.arm64e-darwin21" do
install_gemfile <<-G
source "https://gem.repo4"
gem "darwin_single_arch"
G
expect(the_bundle).to include_gems "darwin_single_arch 1.0 arm64-darwin"
end
end
end
end
it "works with gems that have different dependencies" do
simulate_platform "java" do
install_gemfile <<-G
source "https://gem.repo1"
gem "nokogiri"
G
expect(the_bundle).to include_gems "nokogiri 1.4.2 java", "weakling 0.0.3"
pristine_system_gems
bundle "config set --local force_ruby_platform true"
bundle "install"
expect(the_bundle).to include_gems "nokogiri 1.4.2"
expect(the_bundle).not_to include_gems "weakling"
simulate_new_machine
bundle "install"
expect(the_bundle).to include_gems "nokogiri 1.4.2 java", "weakling 0.0.3"
end
end
it "does not keep unneeded platforms for gems that are used" do
build_repo4 do
build_gem "empyrean", "0.1.0"
build_gem "coderay", "1.1.2"
build_gem "method_source", "0.9.0"
build_gem("spoon", "0.0.6") {|s| s.add_dependency "ffi" }
build_gem "pry", "0.11.3" do |s|
s.platform = "java"
s.add_dependency "coderay", "~> 1.1.0"
s.add_dependency "method_source", "~> 0.9.0"
s.add_dependency "spoon", "~> 0.0"
end
build_gem "pry", "0.11.3" do |s|
s.add_dependency "coderay", "~> 1.1.0"
s.add_dependency "method_source", "~> 0.9.0"
end
build_gem("ffi", "1.9.23") {|s| s.platform = "java" }
build_gem("ffi", "1.9.23")
end
simulate_platform "java" do
install_gemfile <<-G
source "https://gem.repo4"
gem "empyrean", "0.1.0"
gem "pry"
G
checksums = checksums_section_when_enabled do |c|
c.checksum gem_repo4, "coderay", "1.1.2"
c.checksum gem_repo4, "empyrean", "0.1.0"
c.checksum gem_repo4, "ffi", "1.9.23", "java"
c.checksum gem_repo4, "method_source", "0.9.0"
c.checksum gem_repo4, "pry", "0.11.3", "java"
c.checksum gem_repo4, "spoon", "0.0.6"
end
expect(lockfile).to eq <<~L
GEM
remote: https://gem.repo4/
specs:
coderay (1.1.2)
empyrean (0.1.0)
ffi (1.9.23-java)
method_source (0.9.0)
pry (0.11.3-java)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
spoon (~> 0.0)
spoon (0.0.6)
ffi
PLATFORMS
java
DEPENDENCIES
empyrean (= 0.1.0)
pry
#{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
bundle "lock --add-platform ruby"
checksums.checksum gem_repo4, "pry", "0.11.3"
good_lockfile = <<~L
GEM
remote: https://gem.repo4/
specs:
coderay (1.1.2)
empyrean (0.1.0)
ffi (1.9.23-java)
method_source (0.9.0)
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
pry (0.11.3-java)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
spoon (~> 0.0)
spoon (0.0.6)
ffi
PLATFORMS
java
ruby
DEPENDENCIES
empyrean (= 0.1.0)
pry
#{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
expect(lockfile).to eq good_lockfile
bad_lockfile = <<~L
GEM
remote: https://gem.repo4/
specs:
coderay (1.1.2)
empyrean (0.1.0)
ffi (1.9.23)
ffi (1.9.23-java)
method_source (0.9.0)
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
pry (0.11.3-java)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
spoon (~> 0.0)
spoon (0.0.6)
ffi
PLATFORMS
java
ruby
DEPENDENCIES
empyrean (= 0.1.0)
pry
#{checksums}
BUNDLED WITH
1.16.1
L
aggregate_failures do
lockfile bad_lockfile
bundle :install, env: { "BUNDLER_VERSION" => Bundler::VERSION }
expect(lockfile).to eq good_lockfile
lockfile bad_lockfile
bundle :update, all: true, env: { "BUNDLER_VERSION" => Bundler::VERSION }
expect(lockfile).to eq good_lockfile
lockfile bad_lockfile
bundle "update ffi", env: { "BUNDLER_VERSION" => Bundler::VERSION }
expect(lockfile).to eq good_lockfile
lockfile bad_lockfile
bundle "update empyrean", env: { "BUNDLER_VERSION" => Bundler::VERSION }
expect(lockfile).to eq good_lockfile
lockfile bad_lockfile
bundle :lock, env: { "BUNDLER_VERSION" => Bundler::VERSION }
expect(lockfile).to eq good_lockfile
end
end
end
it "works with gems with platform-specific dependency having different requirements order" do
simulate_platform "x86_64-darwin-15" do
update_repo2 do
build_gem "fspath", "3"
build_gem "image_optim_pack", "1.2.3" do |s|
s.add_dependency "fspath", ">= 2.1", "< 4"
end
build_gem "image_optim_pack", "1.2.3" do |s|
s.platform = "universal-darwin"
s.add_dependency "fspath", "< 4", ">= 2.1"
end
end
install_gemfile <<-G
source "https://gem.repo2"
G
install_gemfile <<-G
source "https://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
end
it "fetches gems again after changing the version of Ruby" do
gemfile <<-G
source "https://gem.repo1"
gem "myrack", "1.0.0"
G
bundle "config set --local path vendor/bundle"
bundle :install
FileUtils.mv(vendored_gems, bundled_app("vendor/bundle", Gem.ruby_engine, "1.8"))
bundle :install
expect(vendored_gems("gems/myrack-1.0.0")).to exist
end
it "keeps existing platforms when installing with force_ruby_platform" do
checksums = checksums_section_when_enabled do |c|
c.checksum gem_repo1, "platform_specific", "1.0"
c.checksum gem_repo1, "platform_specific", "1.0", "java"
end
lockfile <<-G
GEM
remote: https://gem.repo1/
specs:
platform_specific (1.0-java)
PLATFORMS
java
DEPENDENCIES
platform_specific
#{checksums}
G
bundle "config set --local force_ruby_platform true"
install_gemfile <<-G
source "https://gem.repo1"
gem "platform_specific"
G
checksums.checksum gem_repo1, "platform_specific", "1.0"
expect(the_bundle).to include_gem "platform_specific 1.0 ruby"
expect(lockfile).to eq <<~G
GEM
remote: https://gem.repo1/
specs:
platform_specific (1.0)
platform_specific (1.0-java)
PLATFORMS
java
ruby
DEPENDENCIES
platform_specific
#{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
end
RSpec.describe "bundle install with platform conditionals" do
it "installs gems tagged w/ the current platforms" do
install_gemfile <<-G
source "https://gem.repo1"
platforms :#{local_tag} do
gem "nokogiri"
end
G
expect(the_bundle).to include_gems "nokogiri 1.4.2"
end
it "does not install gems tagged w/ another platforms" do
install_gemfile <<-G
source "https://gem.repo1"
gem "myrack"
platforms :#{not_local_tag} do
gem "nokogiri"
end
G
expect(the_bundle).to include_gems "myrack 1.0"
expect(the_bundle).not_to include_gems "nokogiri 1.4.2"
end
it "installs gems tagged w/ another platform but also dependent on the current one transitively" do
build_repo4 do
build_gem "activesupport", "6.1.4.1" do |s|
s.add_dependency "tzinfo", "~> 2.0"
end
build_gem "tzinfo", "2.0.4"
end
gemfile <<~G
source "https://gem.repo4"
gem "activesupport"
platforms :#{not_local_tag} do
gem "tzinfo", "~> 1.2"
end
G
lockfile <<~L
GEM
remote: https://gem.repo4/
specs:
activesupport (6.1.4.1)
tzinfo (~> 2.0)
tzinfo (2.0.4)
PLATFORMS
#{local_platform}
DEPENDENCIES
activesupport
tzinfo (~> 1.2)
BUNDLED WITH
#{Bundler::VERSION}
L
bundle "install --verbose"
expect(the_bundle).to include_gems "tzinfo 2.0.4"
end
it "installs gems tagged w/ the current platforms inline" do
install_gemfile <<-G
source "https://gem.repo1"
gem "nokogiri", :platforms => :#{local_tag}
G
expect(the_bundle).to include_gems "nokogiri 1.4.2"
end
it "does not install gems tagged w/ another platforms inline" do
install_gemfile <<-G
source "https://gem.repo1"
gem "myrack"
gem "nokogiri", :platforms => :#{not_local_tag}
G
expect(the_bundle).to include_gems "myrack 1.0"
expect(the_bundle).not_to include_gems "nokogiri 1.4.2"
end
it "installs gems tagged w/ the current platform inline" do
install_gemfile <<-G
source "https://gem.repo1"
gem "nokogiri", :platform => :#{local_tag}
G
expect(the_bundle).to include_gems "nokogiri 1.4.2"
end
it "doesn't install gems tagged w/ another platform inline" do
install_gemfile <<-G
source "https://gem.repo1"
gem "nokogiri", :platform => :#{not_local_tag}
G
expect(the_bundle).not_to include_gems "nokogiri 1.4.2"
end
it "does not blow up on sources with all platform-excluded specs" do
build_git "foo"
install_gemfile <<-G
source "https://gem.repo1"
platform :#{not_local_tag} do
gem "foo", :git => "#{lib_path("foo-1.0")}"
end
G
bundle :list
end
it "does not attempt to install gems from :rbx when using --local" do
bundle "config set --local force_ruby_platform true"
gemfile <<-G
source "https://gem.repo1"
gem "some_gem", :platform => :rbx
G
bundle "install --local"
expect(out).not_to match(/Could not find gem 'some_gem/)
end
it "does not attempt to install gems from other rubies when using --local" do
bundle "config set --local force_ruby_platform true"
gemfile <<-G
source "https://gem.repo1"
gem "some_gem", platform: :ruby_22
G
bundle "install --local"
expect(out).not_to match(/Could not find gem 'some_gem/)
end
it "does not print a warning when a dependency is unused on a platform different from the current one" do
bundle "config set --local force_ruby_platform true"
gemfile <<-G
source "https://gem.repo1"
gem "myrack", :platform => [:windows, :jruby]
G
bundle "install"
expect(err).to be_empty
expect(lockfile).to eq <<~L
GEM
remote: https://gem.repo1/
specs:
PLATFORMS
ruby
DEPENDENCIES
myrack
#{checksums_section_when_enabled}
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "resolves fine when a dependency is unused on a platform different from the current one, but reintroduced transitively" do
bundle "config set --local force_ruby_platform true"
build_repo4 do
build_gem "listen", "3.7.1" do |s|
s.add_dependency "ffi"
end
build_gem "ffi", "1.15.5"
end
install_gemfile <<~G
source "https://gem.repo4"
gem "listen"
gem "ffi", :platform => :windows
G
expect(err).to be_empty
end
end
RSpec.describe "when a gem has no architecture" do
it "still installs correctly" do
simulate_platform "x86-mswin32" do
build_repo2 do
# The rcov gem is platform mswin32, but has no arch
build_gem "rcov" do |s|
s.platform = Gem::Platform.new([nil, "mswin32", nil])
s.write "lib/rcov.rb", "RCOV = '1.0.0'"
end
end
gemfile <<-G
# Try to install gem with nil arch
source "http://localgemserver.test/"
gem "rcov"
G
bundle :install, artifice: "windows", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(the_bundle).to include_gems "rcov 1.0.0"
end
end
end