summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/bundler/source/rubygems/remote.rb14
-rw-r--r--spec/bundler/install/global_cache_spec.rb41
2 files changed, 50 insertions, 5 deletions
diff --git a/lib/bundler/source/rubygems/remote.rb b/lib/bundler/source/rubygems/remote.rb
index 9c5c06de24..ed55912a99 100644
--- a/lib/bundler/source/rubygems/remote.rb
+++ b/lib/bundler/source/rubygems/remote.rb
@@ -16,6 +16,9 @@ module Bundler
@anonymized_uri = remove_auth(@uri).freeze
end
+ MAX_CACHE_SLUG_HOST_SIZE = 255 - 1 - 32 # 255 minus dot minus MD5 length
+ private_constant :MAX_CACHE_SLUG_HOST_SIZE
+
# @return [String] A slug suitable for use as a cache key for this
# remote.
#
@@ -28,10 +31,15 @@ module Bundler
host = cache_uri.to_s.start_with?("file://") ? nil : cache_uri.host
uri_parts = [host, cache_uri.user, cache_uri.port, cache_uri.path]
- uri_digest = SharedHelpers.digest(:MD5).hexdigest(uri_parts.compact.join("."))
+ uri_parts.compact!
+ uri_digest = SharedHelpers.digest(:MD5).hexdigest(uri_parts.join("."))
+
+ uri_parts.pop
+ host_parts = uri_parts.join(".")
+ return uri_digest if host_parts.empty?
- uri_parts[-1] = uri_digest
- uri_parts.compact.join(".")
+ shortened_host_parts = host_parts[0...MAX_CACHE_SLUG_HOST_SIZE]
+ [shortened_host_parts, uri_digest].join(".")
end
end
diff --git a/spec/bundler/install/global_cache_spec.rb b/spec/bundler/install/global_cache_spec.rb
index a4431bff8b..130c841ce9 100644
--- a/spec/bundler/install/global_cache_spec.rb
+++ b/spec/bundler/install/global_cache_spec.rb
@@ -7,12 +7,16 @@ RSpec.describe "global gem caching" do
let(:source) { "http://localgemserver.test" }
let(:source2) { "http://gemserver.example.org" }
+ def cache_base
+ home(".bundle", "cache", "gems")
+ end
+
def source_global_cache(*segments)
- home(".bundle", "cache", "gems", "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", *segments)
+ cache_base.join("localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", *segments)
end
def source2_global_cache(*segments)
- home(".bundle", "cache", "gems", "gemserver.example.org.80.1ae1663619ffe0a3c9d97712f44c705b", *segments)
+ cache_base.join("gemserver.example.org.80.1ae1663619ffe0a3c9d97712f44c705b", *segments)
end
it "caches gems into the global cache on download" do
@@ -49,6 +53,39 @@ RSpec.describe "global gem caching" do
expect(err).to include("Gem::Package::FormatError: package metadata is missing in #{source_global_cache("myrack-1.0.0.gem")}")
end
+ it "uses a shorter path for the cache to not hit filesystem limits" do
+ install_gemfile <<-G, artifice: "compact_index", verbose: true
+ source "http://#{"a" * 255}.test"
+ gem "myrack"
+ G
+
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ source_segment = "a" * 222 + ".a3cb26de2edfce9f509a65c611d99c4b"
+ source_cache = cache_base.join(source_segment)
+ cached_gem = source_cache.join("myrack-1.0.0.gem")
+ expect(cached_gem).to exist
+ ensure
+ # We cleanup dummy files created by this spec manually because due to a
+ # Ruby on Windows bug, `FileUtils.rm_rf` (run in our global after hook)
+ # cannot traverse directories with such long names. So we delete
+ # everything explicitly to workaround the bug. An alternative workaround
+ # would be to shell out to `rm -rf`. That also works fine, but I went with
+ # the more verbose and explicit approach. This whole ensure block can be
+ # removed once/if https://bugs.ruby-lang.org/issues/21177 is fixed, and
+ # once the fix propagates to all supported rubies.
+ File.delete cached_gem
+ Dir.rmdir source_cache
+
+ File.delete compact_index_cache_path.join(source_segment, "info", "myrack")
+ Dir.rmdir compact_index_cache_path.join(source_segment, "info")
+ File.delete compact_index_cache_path.join(source_segment, "info-etags", "myrack-92f3313ce5721296f14445c3a6b9c073")
+ Dir.rmdir compact_index_cache_path.join(source_segment, "info-etags")
+ Dir.rmdir compact_index_cache_path.join(source_segment, "info-special-characters")
+ File.delete compact_index_cache_path.join(source_segment, "versions")
+ File.delete compact_index_cache_path.join(source_segment, "versions.etag")
+ Dir.rmdir compact_index_cache_path.join(source_segment)
+ end
+
describe "when the same gem from different sources is installed" do
it "should use the appropriate one from the global cache" do
bundle "config path.system true"