diff options
Diffstat (limited to 'spec/bundler/cache')
| -rw-r--r-- | spec/bundler/cache/cache_path_spec.rb | 14 | ||||
| -rw-r--r-- | spec/bundler/cache/gems_spec.rb | 330 | ||||
| -rw-r--r-- | spec/bundler/cache/git_spec.rb | 305 | ||||
| -rw-r--r-- | spec/bundler/cache/path_spec.rb | 74 | ||||
| -rw-r--r-- | spec/bundler/cache/platform_spec.rb | 18 |
5 files changed, 514 insertions, 227 deletions
diff --git a/spec/bundler/cache/cache_path_spec.rb b/spec/bundler/cache/cache_path_spec.rb index 12385427b1..2a280ea858 100644 --- a/spec/bundler/cache/cache_path_spec.rb +++ b/spec/bundler/cache/cache_path_spec.rb @@ -3,30 +3,30 @@ RSpec.describe "bundle package" do before do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G end context "with --cache-path" do it "caches gems at given path" do bundle :cache, "cache-path" => "vendor/cache-foo" - expect(bundled_app("vendor/cache-foo/rack-1.0.0.gem")).to exist + expect(bundled_app("vendor/cache-foo/myrack-1.0.0.gem")).to exist end end context "with config cache_path" do it "caches gems at given path" do - bundle "config set cache_path vendor/cache-foo" + bundle_config "cache_path vendor/cache-foo" bundle :cache - expect(bundled_app("vendor/cache-foo/rack-1.0.0.gem")).to exist + expect(bundled_app("vendor/cache-foo/myrack-1.0.0.gem")).to exist end end context "with absolute --cache-path" do it "caches gems at given path" do - bundle :cache, "cache-path" => "/tmp/cache-foo" - expect(bundled_app("/tmp/cache-foo/rack-1.0.0.gem")).to exist + bundle :cache, "cache-path" => bundled_app("vendor/cache-foo") + expect(bundled_app("vendor/cache-foo/myrack-1.0.0.gem")).to exist end end end diff --git a/spec/bundler/cache/gems_spec.rb b/spec/bundler/cache/gems_spec.rb index 63c00eba01..198279d84c 100644 --- a/spec/bundler/cache/gems_spec.rb +++ b/spec/bundler/cache/gems_spec.rb @@ -4,23 +4,23 @@ 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' + source "https://gem.repo1" + gem 'myrack' G - system_gems "rack-1.0.0", :path => path + 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/rack-1.0.0.gem")).to exist + 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") + build_gem "omg", path: bundled_app("vendor/cache") install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "omg" G @@ -28,47 +28,47 @@ 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") + 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 "rack", "1.0.0", :path => bundled_app("vendor/cache") do |s| - s.write "lib/rack.rb", "RACK = 'FAIL'" + 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 "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G - expect(the_bundle).to include_gems("rack 1.0.0") + 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 "rack-1.0.0", :path => default_bundle_path + system_gems "myrack-1.0.0", path: default_bundle_path gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G - build_gem "rack", "1.0.0", :path => bundled_app("vendor/cache") do |s| - s.write "lib/rack.rb", "RACK = 'FAIL'" + 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("rack 1.0.0") + bundle :install, local: true + expect(the_bundle).to include_gems("myrack 1.0.0") end it "creates a lockfile" do - cache_gems "rack-1.0.0" + cache_gems "myrack-1.0.0" gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G bundle "cache" @@ -78,13 +78,13 @@ RSpec.describe "bundle cache" do end context "using system gems" do - before { bundle "config set path.system true" } + before { bundle_config "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" } + before { bundle_config "path ./.bundle" } let(:path) { local_gem_path } it_behaves_like "when there are only gemsources" end @@ -93,82 +93,102 @@ RSpec.describe "bundle cache" do let(:default_json_version) { ruby "gem 'json'; require 'json'; puts JSON::VERSION" } before :each do - build_repo2 do - build_gem "json", default_json_version + 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 - build_gem "json", default_json_version, :to_system => true, :default => true - 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 "uses builtin gems when installing to system gems" do - bundle "config set path.system true" - 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 "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 "caches remote and builtin gems" do - install_gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - gem 'json', '#{default_json_version}' - gem 'rack', '1.0.0' - G + 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 - bundle :cache - expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist - expect(bundled_app("vendor/cache/json-#{default_json_version}.gem")).to exist - 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 - it "caches builtin gems when cache_all_platforms is set" do - gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - gem "json" - 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 - bundle "config set cache_all_platforms true" + it "caches builtin gems when cache_all_platforms is set" do + gemfile <<-G + source "https://gem.repo2" + gem "json" + G - bundle :cache - expect(bundled_app("vendor/cache/json-#{default_json_version}.gem")).to exist - end + bundle_config "cache_all_platforms true" - 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| - s.summary = "This builtin_gem is bundled with Ruby" + bundle :cache + expect(bundled_app("vendor/cache/json-#{default_json_version}.gem")).to exist end - install_gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - gem 'builtin_gem_2', '1.0.2' - G + 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 - bundle "install --local" - expect(the_bundle).to include_gems("builtin_gem_2 1.0.2") + 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 - it "errors if the builtin gem isn't available to cache" do - bundle "config set path.system true" + 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 "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 "path.system true" - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem 'json', '#{default_json_version}' - G + install_gemfile <<-G + source "https://gem.repo1" + gem 'json', '#{default_json_version}' + G - bundle :cache, :raise_on_error => false - expect(exitstatus).to_not eq(0) - expect(err).to include("json-#{default_json_version} is built in to Ruby, and can't be cached") + 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 "rack-1.0.0" + system_gems "myrack-1.0.0" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" git "#{lib_path("foo-1.0")}" do gem 'foo' end - gem 'rack' + gem 'myrack' G end @@ -178,7 +198,7 @@ RSpec.describe "bundle cache" do system_gems [] bundle "install --local" - expect(the_bundle).to include_gems("rack 1.0.0", "foo 1.0") + 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 @@ -191,41 +211,44 @@ RSpec.describe "bundle cache" do end describe "when previously cached" do - before :each do + let :setup_main_repo do build_repo2 install_gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - gem "rack" + source "https://gem.repo2" + gem "myrack" gem "actionpack" G bundle :cache - expect(cached_gem("rack-1.0.0")).to exist + 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 - cached_gem("rack-1.0.0").rmtree + setup_main_repo + FileUtils.rm_rf cached_gem("myrack-1.0.0") bundle :install expect(out).to include("Updating files in vendor/cache") - expect(cached_gem("rack-1.0.0")).to exist + 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 "rack", "1.2" do |s| - s.executables = "rackup" + build_gem "myrack", "1.2" do |s| + s.executables = "myrackup" end end - bundle "update", :all => true - expect(cached_gem("rack-1.2")).to exist - expect(cached_gem("rack-1.0.0")).not_to exist + 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 "#{file_uri_for(gem_repo2)}" + source "https://gem.repo2" gem "rails" G expect(cached_gem("rails-2.3.2")).to exist @@ -233,24 +256,26 @@ RSpec.describe "bundle cache" do end it "removes .gems for removed gems and dependencies" do + setup_main_repo install_gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - gem "rack" + source "https://gem.repo2" + gem "myrack" G - expect(cached_gem("rack-1.0.0")).to exist + 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 - build_git "rack" + setup_main_repo + build_git "myrack" install_gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - gem "rack", :git => "#{lib_path("rack-1.0")}" + source "https://gem.repo2" + gem "myrack", :git => "#{lib_path("myrack-1.0")}" gem "actionpack" G - expect(cached_gem("rack-1.0.0")).not_to exist + 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 @@ -258,7 +283,7 @@ RSpec.describe "bundle cache" do it "doesn't remove gems that are for another platform" do simulate_platform "java" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "platform_specific" G @@ -266,37 +291,111 @@ RSpec.describe "bundle cache" do expect(cached_gem("platform_specific-1.0-java")).to exist end - simulate_new_machine - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "platform_specific" - G + 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") + FileUtils.rm_rf cached_myrack + 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("platform_specific-1.0-#{Bundler.local_platform}")).to exist - expect(cached_gem("platform_specific-1.0-java")).to exist + expect(cached_gem("myrack-1.0.0")).to exist end - 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" - simulate_new_machine + it "raises an error when a cached gem is altered and produces a different checksum than the remote gem" do + setup_main_repo + FileUtils.rm_rf cached_gem("myrack-1.0.0") + 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 + FileUtils.rm_rf cached_gem("myrack-1.0.0") bundle :install - expect(cached_gem("rack-1.0.0")).to exist + 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 + FileUtils.rm_rf cached_gem("myrack-1.0.0") + 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 "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G bundle "cache" bundle "install" @@ -304,9 +403,10 @@ RSpec.describe "bundle cache" do end it "does not warn about all if it doesn't have any git/path dependency" do + setup_main_repo install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G bundle "cache" expect(out).not_to match(/\-\-all/) @@ -314,10 +414,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)}" + source "https://gem.repo1" gem "foo-bundler" G diff --git a/spec/bundler/cache/git_spec.rb b/spec/bundler/cache/git_spec.rb index 890ba88605..f0976ecac7 100644 --- a/spec/bundler/cache/git_spec.rb +++ b/spec/bundler/cache/git_spec.rb @@ -13,22 +13,37 @@ RSpec.describe "git base name" do end RSpec.describe "bundle cache with git" do + it "does not copy repository to vendor cache when cache_all set to false" do + git = build_git "foo" + ref = git.ref_for("main", 11) + + install_gemfile <<-G + source "https://gem.repo1" + gem "foo", :git => '#{lib_path("foo-1.0")}' + G + + bundle_config "cache_all false" + bundle :cache + expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).not_to exist + + expect(the_bundle).to include_gems "foo 1.0" + end + it "copies repository to vendor cache and uses it" do git = build_git "foo" ref = git.ref_for("main", 11) install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "foo", :git => '#{lib_path("foo-1.0")}' G - bundle "config set cache_all true" bundle :cache expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist expect(bundled_app("vendor/cache/foo-1.0-#{ref}/.git")).not_to exist expect(bundled_app("vendor/cache/foo-1.0-#{ref}/.bundlecache")).to be_file - FileUtils.rm_rf lib_path("foo-1.0") + FileUtils.rm_r lib_path("foo-1.0") expect(the_bundle).to include_gems "foo 1.0" end @@ -37,19 +52,18 @@ RSpec.describe "bundle cache with git" do ref = git.ref_for("main", 11) install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "foo", :git => '#{lib_path("foo-1.0")}' G - bundle "config set --local path vendor/bundle" + bundle_config "path vendor/bundle" bundle "install" - bundle "config set cache_all true" bundle :cache expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist expect(bundled_app("vendor/cache/foo-1.0-#{ref}/.git")).not_to exist - FileUtils.rm_rf lib_path("foo-1.0") + FileUtils.rm_r lib_path("foo-1.0") expect(the_bundle).to include_gems "foo 1.0" end @@ -57,16 +71,15 @@ RSpec.describe "bundle cache with git" do build_git "foo" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "foo", :git => '#{lib_path("foo-1.0")}' G - bundle "config set cache_all true" bundle :cache bundle :cache expect(out).to include "Updating files in vendor/cache" - FileUtils.rm_rf lib_path("foo-1.0") + FileUtils.rm_r lib_path("foo-1.0") expect(the_bundle).to include_gems "foo 1.0" end @@ -75,11 +88,10 @@ RSpec.describe "bundle cache with git" do old_ref = git.ref_for("main", 11) install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "foo", :git => '#{lib_path("foo-1.0")}' G - bundle "config set cache_all true" bundle :cache update_git "foo" do |s| @@ -89,13 +101,13 @@ RSpec.describe "bundle cache with git" do ref = git.ref_for("main", 11) expect(ref).not_to eq(old_ref) - bundle "update", :all => true + bundle "update", all: true bundle :cache expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist expect(bundled_app("vendor/cache/foo-1.0-#{old_ref}")).not_to exist - FileUtils.rm_rf lib_path("foo-1.0") + FileUtils.rm_r lib_path("foo-1.0") run "require 'foo'" expect(out).to eq("CACHE") end @@ -105,11 +117,10 @@ RSpec.describe "bundle cache with git" do old_ref = git.ref_for("main", 11) install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "foo", :git => '#{lib_path("foo-1.0")}' G - bundle "config set cache_all true" bundle :cache update_git "foo" do |s| @@ -124,7 +135,7 @@ RSpec.describe "bundle cache with git" do expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist expect(bundled_app("vendor/cache/foo-1.0-#{old_ref}")).not_to exist - FileUtils.rm_rf lib_path("foo-1.0") + FileUtils.rm_r lib_path("foo-1.0") run "require 'foo'" expect(out).to eq("CACHE") end @@ -134,13 +145,12 @@ RSpec.describe "bundle cache with git" do ref = git.ref_for("main", 11) gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "foo", :git => '#{lib_path("foo-invalid")}', :branch => :main G bundle %(config set local.foo #{lib_path("foo-1.0")}) bundle "install" - bundle "config set cache_all true" bundle :cache expect(bundled_app("vendor/cache/foo-invalid-#{ref}")).to exist @@ -154,6 +164,167 @@ RSpec.describe "bundle cache with git" do expect(out).to eq("LOCAL") end + it "can use gems after copying install folder to a different machine with git not installed" do + build_git "foo" + + gemfile <<-G + source "https://gem.repo1" + gem "foo", :git => '#{lib_path("foo-1.0")}' + G + bundle_config "path vendor/bundle" + bundle :install + + pristine_system_gems + with_path_as "" do + bundle_config "deployment true" + bundle "install --local" + expect(the_bundle).to include_gem "foo 1.0" + end + end + + it "can install after bundle cache without cloning remote repositories" do + build_git "foo" + + gemfile <<-G + source "https://gem.repo1" + gem "foo", :git => '#{lib_path("foo-1.0")}' + G + bundle :cache, "all-platforms" => true + + pristine_system_gems + bundle_config "frozen true" + bundle "install --local --verbose" + expect(out).to_not include("Fetching") + expect(the_bundle).to include_gem "foo 1.0" + end + + it "can install after bundle cache without cloning remote repositories even without the original cache" do + build_git "foo" + + gemfile <<-G + source "https://gem.repo1" + gem "foo", :git => '#{lib_path("foo-1.0")}' + G + bundle :cache, "all-platforms" => true + + pristine_system_gems + bundle_config "frozen true" + bundle "install --local --verbose" + expect(out).to_not include("Fetching") + expect(the_bundle).to include_gem "foo 1.0" + end + + it "can install after bundle cache without cloning remote repositories with only git tracked files" do + build_git "foo" + + gemfile <<-G + source "https://gem.repo1" + gem "foo", :git => '#{lib_path("foo-1.0")}' + G + bundle :cache, "all-platforms" => true + + pristine_system_gems + bundle_config "frozen true" + + # Remove untracked files (including the empty refs dir in the cache) + Dir.chdir(bundled_app) do + system(*%W[git init --quiet]) + system(*%W[git add --all]) + system(*%W[git clean -d --force --quiet]) + end + + bundle "install --local --verbose" + expect(out).to_not include("Fetching") + expect(the_bundle).to include_gem "foo 1.0" + end + + it "installs properly a bundler 2.5.17-2.5.23 cache as a bare repository without cloning remote repositories" do + git = build_git "foo" + + short_ref = git.ref_for("main", 11) + cache_dir = bundled_app("vendor/cache/foo-1.0-#{short_ref}") + + gemfile <<-G + source "https://gem.repo1" + gem "foo", :git => '#{lib_path("foo-1.0")}' + G + bundle_config "global_gem_cache false" + bundle_config "path vendor/bundle" + bundle :install + + # Simulate old cache by copying the real cache folder to vendor/cache + FileUtils.mkdir_p bundled_app("vendor/cache") + FileUtils.cp_r "#{Dir.glob(vendored_gems("cache/bundler/git/foo-1.0-*")).first}/.", cache_dir + FileUtils.rm_r bundled_app("vendor/bundle") + + bundle "install --local --verbose" + expect(err).to include("Installing from cache in old \"bare repository\" format for compatibility") + + expect(out).to_not include("Fetching") + + # leaves old cache alone + expect(cache_dir.join("lib/foo.rb")).not_to exist + expect(cache_dir.join("HEAD")).to exist + + expect(the_bundle).to include_gem "foo 1.0" + end + + it "migrates a bundler 2.5.17-2.5.23 cache as a bare repository when not running with --local" do + git = build_git "foo" + + short_ref = git.ref_for("main", 11) + cache_dir = bundled_app("vendor/cache/foo-1.0-#{short_ref}") + + gemfile <<-G + source "https://gem.repo1" + gem "foo", :git => '#{lib_path("foo-1.0")}' + G + bundle_config "global_gem_cache false" + bundle_config "path vendor/bundle" + bundle :install + + # Simulate old cache by copying the real cache folder to vendor/cache + FileUtils.mkdir_p bundled_app("vendor/cache") + FileUtils.cp_r "#{Dir.glob(vendored_gems("cache/bundler/git/foo-1.0-*")).first}/.", cache_dir + FileUtils.rm_r bundled_app("vendor/bundle") + + bundle "install --verbose" + expect(out).to include("Fetching") + + # migrates old cache alone + expect(cache_dir.join("lib/foo.rb")).to exist + expect(cache_dir.join("HEAD")).not_to exist + + expect(the_bundle).to include_gem "foo 1.0" + end + + it "migrates a bundler 2.5.17-2.5.23 cache as a bare repository when running `bundle cache`, even if gems already installed" do + git = build_git "foo" + + short_ref = git.ref_for("main", 11) + cache_dir = bundled_app("vendor/cache/foo-1.0-#{short_ref}") + + gemfile <<-G + source "https://gem.repo1" + gem "foo", :git => '#{lib_path("foo-1.0")}' + G + bundle_config "global_gem_cache false" + bundle_config "path vendor/bundle" + bundle :install + + # Simulate old cache by copying the real cache folder to vendor/cache + FileUtils.mkdir_p bundled_app("vendor/cache") + FileUtils.cp_r "#{Dir.glob(vendored_gems("cache/bundler/git/foo-1.0-*")).first}/.", cache_dir + + bundle "cache" + + # migrates old cache alone + expect(cache_dir.join("lib/foo.rb")).to exist + expect(cache_dir.join("HEAD")).not_to exist + + expect(the_bundle).to include_gem "foo 1.0" + 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]) @@ -164,18 +335,17 @@ RSpec.describe "bundle cache with git" do 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") + git "submodule add #{lib_path("submodule-1.0")} submodule-1.0", lib_path("has_submodule-1.0") + git "commit -m \"submodulator\"", lib_path("has_submodule-1.0") install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" git "#{lib_path("has_submodule-1.0")}", :submodules => true do gem "has_submodule" end G ref = git.ref_for("main", 11) - bundle "config set cache_all true" bundle :cache expect(bundled_app("vendor/cache/has_submodule-1.0-#{ref}")).to exist @@ -192,10 +362,9 @@ 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)}" + source "https://gem.repo1" gem "foo", :git => '#{lib_path("foo-1.0")}' G - bundle "config set cache_all true" bundle :cache ref = git.ref_for("main", 11) @@ -207,29 +376,67 @@ RSpec.describe "bundle cache with git" do build_git "foo" gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "foo", :git => '#{lib_path("foo-1.0")}' G - bundle "config set cache_all true" bundle :cache, "all-platforms" => true, :install => false - simulate_new_machine + pristine_system_gems with_path_as "" do - bundle "config set deployment true" - bundle :install, :local => true + bundle_config "deployment true" + bundle :install, local: true expect(the_bundle).to include_gem "foo 1.0" end end + it "can install after bundle cache generated with an older Bundler that kept checkouts in the cache" do + git = build_git("foo") + locked_revision = git.ref_for("main") + path_revision = git.ref_for("main", 11) + + git_path = lib_path("foo-1.0") + + gemfile <<-G + source "https://gem.repo1" + gem "foo", :git => '#{git_path}' + G + lockfile <<~L + GIT + remote: #{git_path}/ + revision: #{locked_revision} + specs: + foo (1.0) + + GEM + remote: https://gem.repo1/ + specs: + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + foo! + + BUNDLED WITH + #{Bundler::VERSION} + L + + # Simulate an old incorrect situation where vendor/cache would be the install location of git gems + FileUtils.mkdir_p bundled_app("vendor/cache") + FileUtils.cp_r git_path, bundled_app("vendor/cache/foo-1.0-#{path_revision}") + FileUtils.rm_r bundled_app("vendor/cache/foo-1.0-#{path_revision}/.git") + + bundle :install, env: { "BUNDLE_DEPLOYMENT" => "true", "BUNDLE_CACHE_ALL" => "true" } + 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)}" + source "https://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 @@ -245,7 +452,7 @@ RSpec.describe "bundle cache with git" 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) + # nor in .bundle (bundler 4 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 @@ -266,11 +473,39 @@ RSpec.describe "bundle cache with git" do # 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 + 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 + + it "doesn't fail when git gem has extensions and an empty cache folder is present before bundle install" do + build_git "puma" do |s| + s.add_dependency "rake" + s.extensions << "Rakefile" + s.executables = "puma" + s.write "Rakefile", <<-RUBY + task :default do + path = File.expand_path("../lib", __FILE__) + FileUtils.mkdir_p(path) + File.open("\#{path}/puma.rb", "w") do |f| + f.puts "PUMA = 'YES'" + end + end + RUBY + end + + FileUtils.mkdir_p(bundled_app("vendor/cache")) + + install_gemfile <<-G + source "https://gem.repo1" + gem "puma", :git => "#{lib_path("puma-1.0")}" + G + + bundle "exec puma" + + expect(out).to eq("YES") + end end diff --git a/spec/bundler/cache/path_spec.rb b/spec/bundler/cache/path_spec.rb index 2ad136a008..42648aea1f 100644 --- a/spec/bundler/cache/path_spec.rb +++ b/spec/bundler/cache/path_spec.rb @@ -2,14 +2,13 @@ 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)}" + source "https://gem.repo1" gem "foo", :path => '#{bundled_app("lib/foo")}' G - bundle "config set cache_all true" bundle :cache expect(bundled_app("vendor/cache/foo-1.0")).not_to exist expect(the_bundle).to include_gems "foo 1.0" @@ -19,11 +18,10 @@ RSpec.describe "bundle cache with path" do build_lib "foo" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "foo", :path => '#{lib_path("foo-1.0")}' G - bundle "config set cache_all true" bundle :cache expect(bundled_app("vendor/cache/foo-1.0")).to exist expect(bundled_app("vendor/cache/foo-1.0/.bundlecache")).to be_file @@ -35,14 +33,13 @@ 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)}" + source "https://gem.repo1" gem "#{libname}", :path => '#{libpath}' G - bundle "config set cache_all true" bundle :cache expect(bundled_app("vendor/cache/#{libname}")).to exist expect(bundled_app("vendor/cache/#{libname}/.bundlecache")).to be_file @@ -54,11 +51,10 @@ RSpec.describe "bundle cache with path" do build_lib "foo" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "foo", :path => '#{lib_path("foo-1.0")}' G - bundle "config set cache_all true" bundle :cache build_lib "foo" do |s| @@ -77,11 +73,10 @@ RSpec.describe "bundle cache with path" do build_lib "foo" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "foo", :path => '#{lib_path("foo-1.0")}' G - bundle "config set cache_all true" bundle :cache expect(bundled_app("vendor/cache/foo-1.0")).to exist @@ -89,7 +84,7 @@ RSpec.describe "bundle cache with path" do build_lib "bar" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "bar", :path => '#{lib_path("bar-1.0")}' G @@ -97,24 +92,25 @@ 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 if cache_all is set to false" do build_lib "foo" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "foo", :path => '#{lib_path("foo-1.0")}' G + bundle_config "cache_all false" bundle :cache expect(err).to be_empty 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" do build_lib "foo" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "foo", :path => '#{lib_path("foo-1.0")}' G @@ -122,48 +118,4 @@ RSpec.describe "bundle cache with path" do expect(err).to be_empty expect(bundled_app("vendor/cache/foo-1.0")).to exist end - - it "stores the given flag" do - build_lib "foo" - - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "foo", :path => '#{lib_path("foo-1.0")}' - G - - bundle "config set cache_all true" - bundle :cache - 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 - - bundle :cache - expect(bundled_app("vendor/cache/bar-1.0")).to exist - end - - it "can rewind chosen configuration" do - build_lib "foo" - - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "foo", :path => '#{lib_path("foo-1.0")}' - G - - bundle "config set cache_all true" - bundle :cache - 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 - 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..71c0eaee8e 100644 --- a/spec/bundler/cache/platform_spec.rb +++ b/spec/bundler/cache/platform_spec.rb @@ -3,10 +3,10 @@ RSpec.describe "bundle cache with multiple platforms" do before :each do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" platforms :mri, :rbx do - gem "rack", "1.0.0" + gem "myrack", "1.0.0" end platforms :jruby do @@ -16,9 +16,9 @@ RSpec.describe "bundle cache with multiple platforms" do lockfile <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: https://gem.repo1/ specs: - rack (1.0.0) + myrack (1.0.0) activesupport (2.3.5) PLATFORMS @@ -26,24 +26,24 @@ RSpec.describe "bundle cache with multiple platforms" do java DEPENDENCIES - rack (1.0.0) + myrack (1.0.0) activesupport (2.3.5) G - cache_gems "rack-1.0.0", "activesupport-2.3.5" + cache_gems "myrack-1.0.0", "activesupport-2.3.5" end it "ensures that a successful bundle install does not delete gems for other platforms" do bundle "install" - expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist + expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist expect(bundled_app("vendor/cache/activesupport-2.3.5.gem")).to exist 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/myrack-1.0.0.gem")).to exist expect(bundled_app("vendor/cache/activesupport-2.3.5.gem")).to exist end end |
