mirror of
https://github.com/ruby/ruby.git
synced 2025-08-24 05:25:34 +02:00

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
427 lines
12 KiB
Ruby
427 lines
12 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
RSpec.describe "bundle cache" do
|
|
shared_examples_for "when there are only gemsources" do
|
|
before :each do
|
|
gemfile <<-G
|
|
source "https://gem.repo1"
|
|
gem 'myrack'
|
|
G
|
|
|
|
system_gems "myrack-1.0.0", path: path
|
|
bundle :cache
|
|
end
|
|
|
|
it "copies the .gem file to vendor/cache" do
|
|
expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
|
|
end
|
|
|
|
it "uses the cache as a source when installing gems" do
|
|
build_gem "omg", path: bundled_app("vendor/cache")
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
gem "omg"
|
|
G
|
|
|
|
expect(the_bundle).to include_gems "omg 1.0.0"
|
|
end
|
|
|
|
it "uses the cache as a source when installing gems with --local" do
|
|
system_gems [], path: default_bundle_path
|
|
bundle "install --local"
|
|
|
|
expect(the_bundle).to include_gems("myrack 1.0.0")
|
|
end
|
|
|
|
it "does not reinstall gems from the cache if they exist on the system" do
|
|
build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache") do |s|
|
|
s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
|
|
end
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
gem "myrack"
|
|
G
|
|
|
|
expect(the_bundle).to include_gems("myrack 1.0.0")
|
|
end
|
|
|
|
it "does not reinstall gems from the cache if they exist in the bundle" do
|
|
system_gems "myrack-1.0.0", path: default_bundle_path
|
|
|
|
gemfile <<-G
|
|
source "https://gem.repo1"
|
|
gem "myrack"
|
|
G
|
|
|
|
build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache") do |s|
|
|
s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
|
|
end
|
|
|
|
bundle :install, local: true
|
|
expect(the_bundle).to include_gems("myrack 1.0.0")
|
|
end
|
|
|
|
it "creates a lockfile" do
|
|
cache_gems "myrack-1.0.0"
|
|
|
|
gemfile <<-G
|
|
source "https://gem.repo1"
|
|
gem "myrack"
|
|
G
|
|
|
|
bundle "cache"
|
|
|
|
expect(bundled_app_lock).to exist
|
|
end
|
|
end
|
|
|
|
context "using system gems" do
|
|
before { bundle "config set path.system true" }
|
|
let(:path) { system_gem_path }
|
|
it_behaves_like "when there are only gemsources"
|
|
end
|
|
|
|
context "installing into a local path" do
|
|
before { bundle "config set path ./.bundle" }
|
|
let(:path) { local_gem_path }
|
|
it_behaves_like "when there are only gemsources"
|
|
end
|
|
|
|
describe "when there is a built-in gem", :ruby_repo do
|
|
let(:default_json_version) { ruby "gem 'json'; require 'json'; puts JSON::VERSION" }
|
|
|
|
before :each do
|
|
build_gem "json", default_json_version, to_system: true, default: true
|
|
end
|
|
|
|
context "when a remote gem is available for caching" do
|
|
before do
|
|
build_repo2 do
|
|
build_gem "json", default_json_version
|
|
end
|
|
end
|
|
|
|
it "uses remote gems when installing" do
|
|
install_gemfile %(source "https://gem.repo2"; gem 'json', '#{default_json_version}'), verbose: true
|
|
expect(out).to include("Installing json #{default_json_version}")
|
|
end
|
|
|
|
it "does not use remote gems when installing with --local flag" do
|
|
install_gemfile %(source "https://gem.repo2"; gem 'json', '#{default_json_version}'), verbose: true, local: true
|
|
expect(out).to include("Using json #{default_json_version}")
|
|
end
|
|
|
|
it "does not use remote gems when installing with --prefer-local flag" do
|
|
install_gemfile %(source "https://gem.repo2"; gem 'json', '#{default_json_version}'), verbose: true, "prefer-local": true
|
|
expect(out).to include("Using json #{default_json_version}")
|
|
end
|
|
|
|
it "caches remote and builtin gems" do
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2"
|
|
gem 'json', '#{default_json_version}'
|
|
gem 'myrack', '1.0.0'
|
|
G
|
|
|
|
bundle :cache
|
|
expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
|
|
expect(bundled_app("vendor/cache/json-#{default_json_version}.gem")).to exist
|
|
end
|
|
|
|
it "caches builtin gems when cache_all_platforms is set" do
|
|
gemfile <<-G
|
|
source "https://gem.repo2"
|
|
gem "json"
|
|
G
|
|
|
|
bundle "config set cache_all_platforms true"
|
|
|
|
bundle :cache
|
|
expect(bundled_app("vendor/cache/json-#{default_json_version}.gem")).to exist
|
|
end
|
|
|
|
it "doesn't make remote request after caching the gem" do
|
|
build_gem "builtin_gem_2", "1.0.2", path: bundled_app("vendor/cache"), default: true
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2"
|
|
gem 'builtin_gem_2', '1.0.2'
|
|
G
|
|
|
|
bundle "install --local"
|
|
expect(the_bundle).to include_gems("builtin_gem_2 1.0.2")
|
|
end
|
|
end
|
|
|
|
context "when a remote gem is not available for caching" do
|
|
it "warns, but uses builtin gems when installing to system gems" do
|
|
bundle "config set path.system true"
|
|
install_gemfile %(source "https://gem.repo1"; gem 'json', '#{default_json_version}'), verbose: true
|
|
expect(err).to include("json-#{default_json_version} is built in to Ruby, and can't be cached")
|
|
expect(out).to include("Using json #{default_json_version}")
|
|
end
|
|
|
|
it "errors when explicitly caching" do
|
|
bundle "config set path.system true"
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
gem 'json', '#{default_json_version}'
|
|
G
|
|
|
|
bundle :cache, raise_on_error: false
|
|
expect(last_command).to be_failure
|
|
expect(err).to include("json-#{default_json_version} is built in to Ruby, and can't be cached")
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "when there are also git sources" do
|
|
before do
|
|
build_git "foo"
|
|
system_gems "myrack-1.0.0"
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
git "#{lib_path("foo-1.0")}" do
|
|
gem 'foo'
|
|
end
|
|
gem 'myrack'
|
|
G
|
|
end
|
|
|
|
it "still works" do
|
|
bundle :cache
|
|
|
|
system_gems []
|
|
bundle "install --local"
|
|
|
|
expect(the_bundle).to include_gems("myrack 1.0.0", "foo 1.0")
|
|
end
|
|
|
|
it "should not explode if the lockfile is not present" do
|
|
FileUtils.rm(bundled_app_lock)
|
|
|
|
bundle :cache
|
|
|
|
expect(bundled_app_lock).to exist
|
|
end
|
|
end
|
|
|
|
describe "when previously cached" do
|
|
let :setup_main_repo do
|
|
build_repo2
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2"
|
|
gem "myrack"
|
|
gem "actionpack"
|
|
G
|
|
bundle :cache
|
|
expect(cached_gem("myrack-1.0.0")).to exist
|
|
expect(cached_gem("actionpack-2.3.2")).to exist
|
|
expect(cached_gem("activesupport-2.3.2")).to exist
|
|
end
|
|
|
|
it "re-caches during install" do
|
|
setup_main_repo
|
|
cached_gem("myrack-1.0.0").rmtree
|
|
bundle :install
|
|
expect(out).to include("Updating files in vendor/cache")
|
|
expect(cached_gem("myrack-1.0.0")).to exist
|
|
end
|
|
|
|
it "adds and removes when gems are updated" do
|
|
setup_main_repo
|
|
update_repo2 do
|
|
build_gem "myrack", "1.2" do |s|
|
|
s.executables = "myrackup"
|
|
end
|
|
end
|
|
|
|
bundle "update", all: true
|
|
expect(cached_gem("myrack-1.2")).to exist
|
|
expect(cached_gem("myrack-1.0.0")).not_to exist
|
|
end
|
|
|
|
it "adds new gems and dependencies" do
|
|
setup_main_repo
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2"
|
|
gem "rails"
|
|
G
|
|
expect(cached_gem("rails-2.3.2")).to exist
|
|
expect(cached_gem("activerecord-2.3.2")).to exist
|
|
end
|
|
|
|
it "removes .gems for removed gems and dependencies" do
|
|
setup_main_repo
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2"
|
|
gem "myrack"
|
|
G
|
|
expect(cached_gem("myrack-1.0.0")).to exist
|
|
expect(cached_gem("actionpack-2.3.2")).not_to exist
|
|
expect(cached_gem("activesupport-2.3.2")).not_to exist
|
|
end
|
|
|
|
it "removes .gems when gem changes to git source" do
|
|
setup_main_repo
|
|
build_git "myrack"
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2"
|
|
gem "myrack", :git => "#{lib_path("myrack-1.0")}"
|
|
gem "actionpack"
|
|
G
|
|
expect(cached_gem("myrack-1.0.0")).not_to exist
|
|
expect(cached_gem("actionpack-2.3.2")).to exist
|
|
expect(cached_gem("activesupport-2.3.2")).to exist
|
|
end
|
|
|
|
it "doesn't remove gems that are for another platform" do
|
|
simulate_platform "java" do
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
gem "platform_specific"
|
|
G
|
|
|
|
bundle :cache
|
|
expect(cached_gem("platform_specific-1.0-java")).to exist
|
|
end
|
|
|
|
pristine_system_gems
|
|
|
|
simulate_platform "x86-darwin-100" do
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
gem "platform_specific"
|
|
G
|
|
|
|
expect(cached_gem("platform_specific-1.0-x86-darwin-100")).to exist
|
|
expect(cached_gem("platform_specific-1.0-java")).to exist
|
|
end
|
|
end
|
|
|
|
it "doesn't remove gems cached gems that don't match their remote counterparts, but also refuses to install and prints an error" do
|
|
setup_main_repo
|
|
cached_myrack = cached_gem("myrack-1.0.0")
|
|
cached_myrack.rmtree
|
|
build_gem "myrack", "1.0.0",
|
|
path: cached_myrack.parent,
|
|
rubygems_version: "1.3.2"
|
|
|
|
FileUtils.rm_r default_bundle_path
|
|
default_system_gems
|
|
|
|
FileUtils.rm bundled_app_lock
|
|
bundle :install, raise_on_error: false
|
|
|
|
expect(err).to eq <<~E.strip
|
|
Bundler found mismatched checksums. This is a potential security risk.
|
|
#{checksum_to_lock(gem_repo2, "myrack", "1.0.0")}
|
|
from the API at https://gem.repo2/
|
|
#{checksum_from_package(cached_myrack, "myrack", "1.0.0")}
|
|
from the gem at #{cached_myrack}
|
|
|
|
If you trust the API at https://gem.repo2/, to resolve this issue you can:
|
|
1. remove the gem at #{cached_myrack}
|
|
2. run `bundle install`
|
|
|
|
To ignore checksum security warnings, disable checksum validation with
|
|
`bundle config set --local disable_checksum_validation true`
|
|
E
|
|
|
|
expect(cached_gem("myrack-1.0.0")).to exist
|
|
end
|
|
|
|
it "raises an error when a cached gem is altered and produces a different checksum than the remote gem" do
|
|
setup_main_repo
|
|
cached_gem("myrack-1.0.0").rmtree
|
|
build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache")
|
|
|
|
checksums = checksums_section do |c|
|
|
c.checksum gem_repo1, "myrack", "1.0.0"
|
|
end
|
|
|
|
FileUtils.rm_r default_bundle_path
|
|
default_system_gems
|
|
|
|
lockfile <<-L
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
#{checksums}
|
|
L
|
|
|
|
bundle :install, raise_on_error: false
|
|
expect(exitstatus).to eq(37)
|
|
expect(err).to include("Bundler found mismatched checksums.")
|
|
expect(err).to include("1. remove the gem at #{cached_gem("myrack-1.0.0")}")
|
|
|
|
expect(cached_gem("myrack-1.0.0")).to exist
|
|
cached_gem("myrack-1.0.0").rmtree
|
|
bundle :install
|
|
expect(cached_gem("myrack-1.0.0")).to exist
|
|
end
|
|
|
|
it "installs a modified gem with a non-matching checksum when the API implementation does not provide checksums" do
|
|
setup_main_repo
|
|
cached_gem("myrack-1.0.0").rmtree
|
|
build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache")
|
|
pristine_system_gems
|
|
|
|
lockfile <<-L
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
L
|
|
|
|
bundle :install, artifice: "endpoint", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
|
|
expect(cached_gem("myrack-1.0.0")).to exist
|
|
end
|
|
|
|
it "handles directories and non .gem files in the cache" do
|
|
setup_main_repo
|
|
bundled_app("vendor/cache/foo").mkdir
|
|
File.open(bundled_app("vendor/cache/bar"), "w") {|f| f.write("not a gem") }
|
|
bundle :cache
|
|
end
|
|
|
|
it "does not say that it is removing gems when it isn't actually doing so" do
|
|
setup_main_repo
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
gem "myrack"
|
|
G
|
|
bundle "cache"
|
|
bundle "install"
|
|
expect(out).not_to match(/removing/i)
|
|
end
|
|
|
|
it "does not warn about all if it doesn't have any git/path dependency" do
|
|
setup_main_repo
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
gem "myrack"
|
|
G
|
|
bundle "cache"
|
|
expect(out).not_to match(/\-\-all/)
|
|
end
|
|
|
|
it "should install gems with the name bundler in them (that aren't bundler)" do
|
|
build_gem "foo-bundler", "1.0",
|
|
path: bundled_app("vendor/cache")
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
gem "foo-bundler"
|
|
G
|
|
|
|
expect(the_bundle).to include_gems "foo-bundler 1.0"
|
|
end
|
|
end
|
|
end
|