Skip to content

Commit 0451700

Browse files
hsbtclaude
andcommitted
Lock compact_index vendoring against parallel races
The vendored compact_index install ran without any coordination, so two test setups starting at once could both write into tmp/compact_index/ at the same time. The skip guard also checked a single file, which meant an interrupted download leaving only lib/compact_index.rb behind would be treated as a complete vendor tree on the next run. Take an exclusive file lock around the install and only skip the download once every expected file is present, removing the tree under the same lock when COMPACT_INDEX_REF forces a refresh. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 7343eef commit 0451700

1 file changed

Lines changed: 22 additions & 14 deletions

File tree

spec/support/rubygems_ext.rb

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -84,26 +84,34 @@ def install_test_deps
8484
def install_vendored_compact_index
8585
target_root = Path.tmp_root.join("compact_index")
8686
require "fileutils"
87+
FileUtils.mkdir_p(Path.tmp_root)
8788

88-
if ENV["COMPACT_INDEX_REF"]
89-
FileUtils.rm_rf(target_root)
90-
elsif File.exist?(target_root.join("lib/compact_index.rb"))
91-
return
92-
end
93-
94-
require "open-uri"
95-
ref = ENV["COMPACT_INDEX_REF"] || "7c68a7b39761c61a66f9299f85b889ec39afc02c"
96-
%w[
89+
files = %w[
9790
lib/compact_index.rb
9891
lib/compact_index/dependency.rb
9992
lib/compact_index/gem.rb
10093
lib/compact_index/gem_version.rb
10194
lib/compact_index/versions_file.rb
102-
].each do |path|
103-
url = "https://raw.githubusercontent.com/rubygems/rubygems.org/#{ref}/#{path}"
104-
target = target_root.join(path)
105-
FileUtils.mkdir_p(File.dirname(target))
106-
File.write(target, URI.parse(url).open(&:read))
95+
]
96+
97+
# Serialize installs so parallel test setups don't race on the same
98+
# vendor tree, and only skip the download when every file is present so
99+
# an interrupted run can't leave a partial copy behind.
100+
File.open(Path.tmp_root.join("compact_index.lock"), File::CREAT | File::RDWR) do |lock|
101+
lock.flock(File::LOCK_EX)
102+
103+
FileUtils.rm_rf(target_root) if ENV["COMPACT_INDEX_REF"]
104+
105+
next if files.all? {|path| File.exist?(target_root.join(path)) }
106+
107+
require "open-uri"
108+
ref = ENV["COMPACT_INDEX_REF"] || "7c68a7b39761c61a66f9299f85b889ec39afc02c"
109+
files.each do |path|
110+
url = "https://raw.githubusercontent.com/rubygems/rubygems.org/#{ref}/#{path}"
111+
target = target_root.join(path)
112+
FileUtils.mkdir_p(File.dirname(target))
113+
File.write(target, URI.parse(url).open(&:read))
114+
end
107115
end
108116
end
109117

0 commit comments

Comments
 (0)