diff options
author | David RodrÃguez <[email protected]> | 2024-11-26 19:46:26 +0100 |
---|---|---|
committer | git <[email protected]> | 2024-11-29 15:27:40 +0000 |
commit | ee7ff4a12b9eefaeced9b6da52f7b21317ab595c (patch) | |
tree | 6454d56ec346da27bad3dc27fdadbec75f7b82c7 | |
parent | 9a4d91fa9507d981a02595d1760628f74396feec (diff) |
[rubygems/rubygems] Backwards compatibility for 2.5.17-2.5.23 caches
https://github.com/rubygems/rubygems/commit/9dbfce76cf
-rw-r--r-- | lib/bundler/runtime.rb | 6 | ||||
-rw-r--r-- | lib/bundler/source/git.rb | 46 | ||||
-rw-r--r-- | spec/bundler/cache/git_spec.rb | 90 |
3 files changed, 131 insertions, 11 deletions
diff --git a/lib/bundler/runtime.rb b/lib/bundler/runtime.rb index cfad828e38..b72d3786bd 100644 --- a/lib/bundler/runtime.rb +++ b/lib/bundler/runtime.rb @@ -136,7 +136,11 @@ module Bundler specs_to_cache.each do |spec| next if spec.name == "bundler" next if spec.source.is_a?(Source::Gemspec) - spec.source.cache(spec, custom_path) if spec.source.respond_to?(:cache) + if spec.source.respond_to?(:migrate_cache) + spec.source.migrate_cache(custom_path, local: local) + elsif spec.source.respond_to?(:cache) + spec.source.cache(spec, custom_path) + end end Dir[cache_path.join("*/.git")].each do |git_dir| diff --git a/lib/bundler/source/git.rb b/lib/bundler/source/git.rb index b7870180f2..3aa48a943a 100644 --- a/lib/bundler/source/git.rb +++ b/lib/bundler/source/git.rb @@ -214,16 +214,16 @@ module Bundler requires_checkout? ? spec.post_install_message : nil end - def cache(spec, custom_path = nil) - return unless Bundler.feature_flag.cache_all? - - app_cache_path = app_cache_path(custom_path) - return if cache_path == app_cache_path + def migrate_cache(custom_path = nil, local: false) + if local + cache_to(custom_path, try_migrate: false) + else + cache_to(custom_path, try_migrate: true) + end + end - cached! - FileUtils.rm_rf(app_cache_path) - git_proxy.checkout if requires_checkout? - git_proxy.copy_to(app_cache_path, @submodules) + def cache(spec, custom_path = nil) + cache_to(custom_path, try_migrate: false) end def load_spec_files @@ -267,14 +267,36 @@ module Bundler private + def cache_to(custom_path, try_migrate: false) + return unless Bundler.feature_flag.cache_all? + + app_cache_path = app_cache_path(custom_path) + + migrate = try_migrate ? bare_repo?(app_cache_path) : false + + set_cache_path!(nil) if migrate + + return if cache_path == app_cache_path + + cached! + FileUtils.rm_rf(app_cache_path) + git_proxy.checkout if migrate || requires_checkout? + git_proxy.copy_to(app_cache_path, @submodules) + end + def checkout Bundler.ui.debug " * Checking out revision: #{ref}" - if use_app_cache? + if use_app_cache? && !bare_repo?(app_cache_path) SharedHelpers.filesystem_access(install_path.dirname) do |p| FileUtils.mkdir_p(p) end FileUtils.cp_r("#{app_cache_path}/.", install_path) else + if use_app_cache? && bare_repo?(app_cache_path) + Bundler.ui.warn "Installing from cache in old \"bare repository\" format for compatibility. " \ + "Please run `bundle cache` and commit the updated cache to migrate to the new format and get rid of this warning." + end + git_proxy.copy_to(install_path, submodules) end serialize_gemspecs_in(install_path) @@ -416,6 +438,10 @@ module Bundler def override_for(path) Bundler.settings.local_overrides.key(path) end + + def bare_repo?(path) + File.exist?(path.join("objects")) && File.exist?(path.join("HEAD")) + end end end end diff --git a/spec/bundler/cache/git_spec.rb b/spec/bundler/cache/git_spec.rb index c2e69cf3dc..39403e2d3a 100644 --- a/spec/bundler/cache/git_spec.rb +++ b/spec/bundler/cache/git_spec.rb @@ -239,6 +239,96 @@ RSpec.describe "bundle cache with git" do 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 set global_gem_cache false" + bundle "config set cache_all true" + 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_rf 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 set global_gem_cache false" + bundle "config set cache_all true" + 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_rf 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 set global_gem_cache false" + bundle "config set cache_all true" + 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/[email protected]/ system(*%W[git config --global protocol.file.allow always]) |