diff options
Diffstat (limited to 'spec/bundler/cache')
-rw-r--r-- | spec/bundler/cache/gems_spec.rb | 115 | ||||
-rw-r--r-- | spec/bundler/cache/git_spec.rb | 94 | ||||
-rw-r--r-- | spec/bundler/cache/path_spec.rb | 22 | ||||
-rw-r--r-- | spec/bundler/cache/platform_spec.rb | 2 |
4 files changed, 186 insertions, 47 deletions
diff --git a/spec/bundler/cache/gems_spec.rb b/spec/bundler/cache/gems_spec.rb index 161ec64218..abbc2c3cf2 100644 --- a/spec/bundler/cache/gems_spec.rb +++ b/spec/bundler/cache/gems_spec.rb @@ -4,10 +4,11 @@ RSpec.describe "bundle cache" do shared_examples_for "when there are only gemsources" do before :each do gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem 'rack' G - system_gems "rack-1.0.0", :path => path + system_gems "rack-1.0.0", path: path bundle :cache end @@ -16,7 +17,7 @@ RSpec.describe "bundle cache" do end it "uses the cache as a source when installing gems" do - build_gem "omg", :path => bundled_app("vendor/cache") + build_gem "omg", path: bundled_app("vendor/cache") install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" @@ -27,18 +28,19 @@ RSpec.describe "bundle cache" do end it "uses the cache as a source when installing gems with --local" do - system_gems [], :path => default_bundle_path + system_gems [], path: default_bundle_path bundle "install --local" expect(the_bundle).to include_gems("rack 1.0.0") end it "does not reinstall gems from the cache if they exist on the system" do - build_gem "rack", "1.0.0", :path => bundled_app("vendor/cache") do |s| + build_gem "rack", "1.0.0", path: bundled_app("vendor/cache") do |s| s.write "lib/rack.rb", "RACK = 'FAIL'" end install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "rack" G @@ -46,17 +48,18 @@ RSpec.describe "bundle cache" do end it "does not reinstall gems from the cache if they exist in the bundle" do - system_gems "rack-1.0.0", :path => default_bundle_path + system_gems "rack-1.0.0", path: default_bundle_path gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "rack" G - build_gem "rack", "1.0.0", :path => bundled_app("vendor/cache") do |s| + build_gem "rack", "1.0.0", path: bundled_app("vendor/cache") do |s| s.write "lib/rack.rb", "RACK = 'FAIL'" end - bundle :install, :local => true + bundle :install, local: true expect(the_bundle).to include_gems("rack 1.0.0") end @@ -64,6 +67,7 @@ RSpec.describe "bundle cache" do cache_gems "rack-1.0.0" gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "rack" G @@ -85,39 +89,49 @@ RSpec.describe "bundle cache" do it_behaves_like "when there are only gemsources" end - describe "when there is a built-in gem" do + 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_repo2 do - build_gem "builtin_gem", "1.0.2" + build_gem "json", default_json_version end - build_gem "builtin_gem", "1.0.2", :to_system => true do |s| - s.summary = "This builtin_gem is bundled with Ruby" - end - - FileUtils.rm("#{system_gem_path}/cache/builtin_gem-1.0.2.gem") + build_gem "json", default_json_version, to_system: true, default: true end it "uses builtin gems when installing to system gems" do bundle "config set path.system true" - install_gemfile %(gem 'builtin_gem', '1.0.2') - expect(the_bundle).to include_gems("builtin_gem 1.0.2") + install_gemfile %(source "#{file_uri_for(gem_repo1)}"; gem 'json', '#{default_json_version}'), verbose: true + expect(out).to include("Using json #{default_json_version}") end it "caches remote and builtin gems" do install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" - gem 'builtin_gem', '1.0.2' + gem 'json', '#{default_json_version}' gem 'rack', '1.0.0' G bundle :cache expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist - expect(bundled_app("vendor/cache/builtin_gem-1.0.2.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 "#{file_uri_for(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") do |s| + build_gem "builtin_gem_2", "1.0.2", path: bundled_app("vendor/cache") do |s| s.summary = "This builtin_gem is bundled with Ruby" end @@ -134,12 +148,13 @@ RSpec.describe "bundle cache" do bundle "config set path.system true" install_gemfile <<-G - gem 'builtin_gem', '1.0.2' + source "#{file_uri_for(gem_repo1)}" + gem 'json', '#{default_json_version}' G - bundle :cache, :raise_on_error => false + bundle :cache, raise_on_error: false expect(exitstatus).to_not eq(0) - expect(err).to include("builtin_gem-1.0.2 is built in to Ruby, and can't be cached") + expect(err).to include("json-#{default_json_version} is built in to Ruby, and can't be cached") end end @@ -203,7 +218,7 @@ RSpec.describe "bundle cache" do end end - bundle "update", :all => true + bundle "update", all: true expect(cached_gem("rack-1.2")).to exist expect(cached_gem("rack-1.0.0")).not_to exist end @@ -264,10 +279,57 @@ RSpec.describe "bundle cache" do it "doesn't remove gems with mismatched :rubygems_version or :date" do cached_gem("rack-1.0.0").rmtree build_gem "rack", "1.0.0", - :path => bundled_app("vendor/cache"), - :rubygems_version => "1.3.2" + path: bundled_app("vendor/cache"), + rubygems_version: "1.3.2" + # This test is only really valid if the checksum isn't saved. It otherwise can't be the same gem. Tested below. + bundled_app_lock.write remove_checksums_from_lockfile(bundled_app_lock.read, "rack (1.0.0)") + simulate_new_machine + + bundle :install + expect(cached_gem("rack-1.0.0")).to exist + end + + it "raises an error when the gem is altered and produces a different checksum" do + cached_gem("rack-1.0.0").rmtree + build_gem "rack", "1.0.0", path: bundled_app("vendor/cache") + + checksums = checksums_section do |c| + c.checksum gem_repo1, "rack", "1.0.0" + end + + simulate_new_machine + + lockfile <<-L + GEM + remote: #{file_uri_for(gem_repo2)}/ + specs: + rack (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("rack-1.0.0")}") + + expect(cached_gem("rack-1.0.0")).to exist + cached_gem("rack-1.0.0").rmtree + bundle :install + expect(cached_gem("rack-1.0.0")).to exist + end + + it "installs a modified gem with a non-matching checksum when checksums is not opted in" do + cached_gem("rack-1.0.0").rmtree + build_gem "rack", "1.0.0", path: bundled_app("vendor/cache") simulate_new_machine + lockfile <<-L + GEM + remote: #{file_uri_for(gem_repo2)}/ + specs: + rack (1.0.0) + L + bundle :install expect(cached_gem("rack-1.0.0")).to exist end @@ -299,9 +361,10 @@ RSpec.describe "bundle cache" do 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") + path: bundled_app("vendor/cache") install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo-bundler" G diff --git a/spec/bundler/cache/git_spec.rb b/spec/bundler/cache/git_spec.rb index 25f12a9e87..4b3cd4d2eb 100644 --- a/spec/bundler/cache/git_spec.rb +++ b/spec/bundler/cache/git_spec.rb @@ -15,9 +15,10 @@ end RSpec.describe "bundle cache with git" do it "copies repository to vendor cache and uses it" do git = build_git "foo" - ref = git.ref_for("master", 11) + ref = git.ref_for("main", 11) install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :git => '#{lib_path("foo-1.0")}' G @@ -33,9 +34,10 @@ RSpec.describe "bundle cache with git" do it "copies repository to vendor cache and uses it even when configured with `path`" do git = build_git "foo" - ref = git.ref_for("master", 11) + ref = git.ref_for("main", 11) install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :git => '#{lib_path("foo-1.0")}' G @@ -55,6 +57,7 @@ RSpec.describe "bundle cache with git" do build_git "foo" install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :git => '#{lib_path("foo-1.0")}' G @@ -69,9 +72,10 @@ RSpec.describe "bundle cache with git" do it "tracks updates" do git = build_git "foo" - old_ref = git.ref_for("master", 11) + old_ref = git.ref_for("main", 11) install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :git => '#{lib_path("foo-1.0")}' G @@ -82,11 +86,10 @@ RSpec.describe "bundle cache with git" do s.write "lib/foo.rb", "puts :CACHE" end - ref = git.ref_for("master", 11) + ref = git.ref_for("main", 11) expect(ref).not_to eq(old_ref) - bundle "update", :all => true - bundle "config set cache_all true" + bundle "update", all: true bundle :cache expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist @@ -99,9 +102,10 @@ RSpec.describe "bundle cache with git" do it "tracks updates when specifying the gem" do git = build_git "foo" - old_ref = git.ref_for("master", 11) + old_ref = git.ref_for("main", 11) install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :git => '#{lib_path("foo-1.0")}' G @@ -112,7 +116,7 @@ RSpec.describe "bundle cache with git" do s.write "lib/foo.rb", "puts :CACHE" end - ref = git.ref_for("master", 11) + ref = git.ref_for("main", 11) expect(ref).not_to eq(old_ref) bundle "update foo" @@ -127,10 +131,11 @@ RSpec.describe "bundle cache with git" do it "uses the local repository to generate the cache" do git = build_git "foo" - ref = git.ref_for("master", 11) + ref = git.ref_for("main", 11) gemfile <<-G - gem "foo", :git => '#{lib_path("foo-invalid")}', :branch => :master + source "#{file_uri_for(gem_repo1)}" + gem "foo", :git => '#{lib_path("foo-invalid")}', :branch => :main G bundle %(config set local.foo #{lib_path("foo-1.0")}) @@ -150,22 +155,26 @@ RSpec.describe "bundle cache with git" do end it "copies repository to vendor cache, including submodules" do + # CVE-2022-39253: https://lore.kernel.org/lkml/xmqq4jw1uku5.fsf@gitster.g/ + system(*%W[git config --global protocol.file.allow always]) + build_git "submodule", "1.0" git = build_git "has_submodule", "1.0" do |s| s.add_dependency "submodule" end - sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0") - sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0") + sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", dir: lib_path("has_submodule-1.0") + sys_exec "git commit -m \"submodulator\"", dir: lib_path("has_submodule-1.0") install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" git "#{lib_path("has_submodule-1.0")}", :submodules => true do gem "has_submodule" end G - ref = git.ref_for("master", 11) + ref = git.ref_for("main", 11) bundle "config set cache_all true" bundle :cache @@ -183,12 +192,13 @@ RSpec.describe "bundle cache with git" do update_git("foo") {|s| s.write "foo.gemspec", spec_lines.join("\n") } install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :git => '#{lib_path("foo-1.0")}' G bundle "config set cache_all true" bundle :cache - ref = git.ref_for("master", 11) + ref = git.ref_for("main", 11) gemspec = bundled_app("vendor/cache/foo-1.0-#{ref}/foo.gemspec").read expect(gemspec).to_not match("`echo bob`") end @@ -197,6 +207,7 @@ RSpec.describe "bundle cache with git" do build_git "foo" gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :git => '#{lib_path("foo-1.0")}' G bundle "config set cache_all true" @@ -205,8 +216,61 @@ RSpec.describe "bundle cache with git" do simulate_new_machine with_path_as "" do bundle "config set deployment true" - bundle :install, :local => true + bundle :install, local: true expect(the_bundle).to include_gem "foo 1.0" end end + + it "respects the --no-install flag" do + git = build_git "foo", &:add_c_extension + ref = git.ref_for("main", 11) + + gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + gem "foo", :git => '#{lib_path("foo-1.0")}' + G + bundle "config set cache_all true" + + # The algorithm for the cache location for a git checkout is + # in Bundle::Source::Git#cache_path + cache_path_name = "foo-1.0-#{Digest(:SHA1).hexdigest(lib_path("foo-1.0").to_s)}" + + # Run this test twice. This is because materially different codepaths + # will get hit the second time around. + # The first time, Bundler::Sources::Git#install_path is set to the system + # wide cache directory bundler/gems; the second time, it's set to the + # vendor/cache directory. We don't want the native extension to appear in + # either of these places, so run the `bundle cache` command twice. + 2.times do + bundle :cache, "all-platforms" => true, :install => false + + # it did _NOT_ actually install the gem - neither in $GEM_HOME (bundler 2 mode), + # nor in .bundle (bundler 3 mode) + expect(Pathname.new(File.join(default_bundle_path, "gems/foo-1.0-#{ref}"))).to_not exist + # it _did_ cache the gem in vendor/ + expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist + # it did _NOT_ build the gems extensions in the vendor/ dir + expect(Dir[bundled_app("vendor/cache/foo-1.0-#{ref}/lib/foo_c*")]).to be_empty + # it _did_ cache the git checkout + expect(default_cache_path("git", cache_path_name)).to exist + # And the checkout is a bare checkout + expect(default_cache_path("git", cache_path_name, "HEAD")).to exist + end + + # Subsequently installing the gem should compile it. + # _currently_, the gem gets compiled in vendor/cache, and vendor/cache is added + # to the $LOAD_PATH for git extensions, so it all kind of "works". However, in the + # future we would like to stop adding vendor/cache to the $LOAD_PATH for git extensions + # and instead treat them identically to normal gems (where the gem install location, + # not the cache location, is added to $LOAD_PATH). + # Verify that the compilation worked and the result is in $LOAD_PATH by simply attempting + # to require it; that should make sure this spec does not break if the load path behaviour + # is changed. + bundle :install, local: true + ruby <<~R, raise_on_error: false + require 'bundler/setup' + require 'foo_c' + R + expect(last_command).to_not be_failure + end end diff --git a/spec/bundler/cache/path_spec.rb b/spec/bundler/cache/path_spec.rb index c81dda7405..2c8a52617a 100644 --- a/spec/bundler/cache/path_spec.rb +++ b/spec/bundler/cache/path_spec.rb @@ -2,9 +2,10 @@ RSpec.describe "bundle cache with path" do it "is no-op when the path is within the bundle" do - build_lib "foo", :path => bundled_app("lib/foo") + build_lib "foo", path: bundled_app("lib/foo") install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :path => '#{bundled_app("lib/foo")}' G @@ -18,6 +19,7 @@ RSpec.describe "bundle cache with path" do build_lib "foo" install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :path => '#{lib_path("foo-1.0")}' G @@ -33,9 +35,10 @@ RSpec.describe "bundle cache with path" do libname = File.basename(bundled_app) + "_gem" libpath = File.join(File.dirname(bundled_app), libname) - build_lib libname, :path => libpath + build_lib libname, path: libpath install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "#{libname}", :path => '#{libpath}' G @@ -51,6 +54,7 @@ RSpec.describe "bundle cache with path" do build_lib "foo" install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :path => '#{lib_path("foo-1.0")}' G @@ -73,6 +77,7 @@ RSpec.describe "bundle cache with path" do build_lib "foo" install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :path => '#{lib_path("foo-1.0")}' G @@ -84,6 +89,7 @@ RSpec.describe "bundle cache with path" do build_lib "bar" install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "bar", :path => '#{lib_path("bar-1.0")}' G @@ -91,10 +97,11 @@ RSpec.describe "bundle cache with path" do expect(bundled_app("vendor/cache/foo-1.0")).not_to exist end - it "does not cache path gems by default", :bundler => "< 3" do + it "does not cache path gems by default", bundler: "< 3" do build_lib "foo" install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :path => '#{lib_path("foo-1.0")}' G @@ -103,10 +110,11 @@ RSpec.describe "bundle cache with path" do expect(bundled_app("vendor/cache/foo-1.0")).not_to exist end - it "caches path gems by default", :bundler => "3" do + it "caches path gems by default", bundler: "3" do build_lib "foo" install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :path => '#{lib_path("foo-1.0")}' G @@ -119,6 +127,7 @@ RSpec.describe "bundle cache with path" do build_lib "foo" install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :path => '#{lib_path("foo-1.0")}' G @@ -127,6 +136,7 @@ RSpec.describe "bundle cache with path" do build_lib "bar" install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :path => '#{lib_path("foo-1.0")}' gem "bar", :path => '#{lib_path("bar-1.0")}' G @@ -139,6 +149,7 @@ RSpec.describe "bundle cache with path" do build_lib "foo" install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :path => '#{lib_path("foo-1.0")}' G @@ -147,11 +158,12 @@ RSpec.describe "bundle cache with path" do build_lib "baz" gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :path => '#{lib_path("foo-1.0")}' gem "baz", :path => '#{lib_path("baz-1.0")}' G - bundle "cache --no-all", :raise_on_error => false + bundle "cache --no-all", raise_on_error: false expect(bundled_app("vendor/cache/baz-1.0")).not_to exist end end diff --git a/spec/bundler/cache/platform_spec.rb b/spec/bundler/cache/platform_spec.rb index 128278956c..36db954c79 100644 --- a/spec/bundler/cache/platform_spec.rb +++ b/spec/bundler/cache/platform_spec.rb @@ -41,7 +41,7 @@ RSpec.describe "bundle cache with multiple platforms" do end it "ensures that a successful bundle update does not delete gems for other platforms" do - bundle "update", :all => true + bundle "update", all: true expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist expect(bundled_app("vendor/cache/activesupport-2.3.5.gem")).to exist |