Add global gem cache shared by RubyGems and Bundler#9230
Add global gem cache shared by RubyGems and Bundler#9230panozzaj wants to merge 7 commits intoruby:masterfrom
Conversation
Add opt-in support for a global .gem file cache at ~/.cache/gem/gems (respects XDG_CACHE_HOME). This allows sharing cached gems across all Ruby installations and between RubyGems and Bundler. Enable via: - Environment: RUBYGEMS_GLOBAL_GEM_CACHE=true - gemrc: global_gem_cache: true - Bundler: bundle config set global_gem_cache true When enabled, RubyGems checks the global cache before downloading and copies downloaded gems to the cache. Bundler's existing global_gem_cache setting now uses the same unified cache location.
tenderlove
left a comment
There was a problem hiding this comment.
I think this is mostly good, though I left a comment. It looks like you need to opt-in to using the global cache. I think we should make it opt-out, or possibly not configurable. I think that if people want the hold behavior, they could set XDG_CACHE_HOME to the old location.
For example:
$ XDG_CACHE_HOME=$(ruby -e'puts Gem.home') gem install blah
Open to other opinions though.
| end | ||
| end | ||
|
|
||
| install_cache_dir = File.join install_dir, "cache" |
There was a problem hiding this comment.
Shouldn't we add code that influences the install_dir variable? Or change install_cache_dir variable to point at the gem cache path? It seems like this is the right place to do it. Then I think we can avoid the copy below.
Ah yes, this is true. We could probably make it opt-in for a bugfix release, then opt-out for a middle release or something. |
| return unless cache_slug = remote.cache_slug | ||
|
|
||
| Bundler.user_cache.join("gems", cache_slug) | ||
| Pathname.new(Gem.global_gem_cache_path).join(cache_slug) |
There was a problem hiding this comment.
I think this will break if someone updates Bundler but has an old Rubygems version
There was a problem hiding this comment.
We really need to combine RubyGems / Bundler so we can do refactoring like this more freely. 😫
Instead of checking global cache separately and copying after download, integrate global_gem_cache as the first option in cache_dir selection. This removes ~20 lines while achieving the same behavior. Suggested by Aaron Patterson.
Guard against missing Gem.global_gem_cache_path method when Bundler is used with an older RubyGems version that doesn't have the global cache feature. Falls back to the previous Bundler.user_cache location. Suggested by skipkayhil.
|
@tenderlove @skipkayhil thanks for the reviews! I just pushed up a couple more commits to try to simplify and to ensure that folks that were running older versions of Rubygems would be less likely to run into issues. |
The global gem cache is now at ~/.cache/gem/gems/ (XDG standard) instead of ~/.bundle/cache/gems/ to align with the shared RubyGems/Bundler cache implementation.
When running Bundler tests against system RubyGems (which doesn't have Gem.global_gem_cache_path), the test needs to use the fallback cache location (~/.bundle/cache/gems/) that Bundler uses in that case.
|
Sorry for the delay on this. Looks like it's waiting on a build to run. I've been pushing up and it seems someone periodically manually triggers? (Not sure if there's a way for it to auto-run on push or a way for me to easily trigger. No worries, it would just speed up the feedback loop.) |
These memoized instance variables were not being cleared, causing test isolation issues when HOME environment variable changes.
|
I pushed up one more test tweak and it appears CI ran successfully. So now this one is good for a re-review. |
What was the end-user or developer problem that led to this PR?
Attempts to implement #7249. I read about this issue in this recent blog post by @tenderlove.
I will admit that I am both new to this repo and that the code was primarily generated with Claude Code. However, I reviewed it (have a lot of Ruby experience) and it seems reasonable. Additionally, I had it write some automated tests and a script to test it out end-to-end. I am hoping this changeset could at least serve as a conversation starter to make sure the requirements are clear, and since it did not take long to implement, I have low attachment to it, so open to feedback.
What is your fix for the problem, implemented in this PR?
Add opt-in support for a global .gem file cache at ~/.cache/gem/gems (respects XDG_CACHE_HOME). This allows sharing cached gems across all Ruby installations and between RubyGems and Bundler.
Enable via:
When enabled, RubyGems checks the global cache before downloading and copies downloaded gems to the cache. Bundler's existing global_gem_cache setting now uses the same unified cache location.
Note: #7249 indicates that it's a placeholder for opting everyone in to this behavior for Bundler and Rubygems, but I thought that this might be better for the next version bump since it might have some unexpected behaviors for folks. I think it would be a small code change to make it opt-out, but might be more of a development challenge to do so IMO.
Make sure the following tasks are checked