summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Rodríguez <[email protected]>2024-11-26 19:46:26 +0100
committergit <[email protected]>2024-11-29 15:27:40 +0000
commitee7ff4a12b9eefaeced9b6da52f7b21317ab595c (patch)
tree6454d56ec346da27bad3dc27fdadbec75f7b82c7
parent9a4d91fa9507d981a02595d1760628f74396feec (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.rb6
-rw-r--r--lib/bundler/source/git.rb46
-rw-r--r--spec/bundler/cache/git_spec.rb90
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])