@@ -188,11 +188,49 @@ if ! cmp "$(pwd)/toolchain/pyproject.toml" "$(pwd)/build/pyproject.toml" > /dev/
188188 if [ " ${GITHUB_ACTIONS:- } " = " true" ] && [ -w " ${TMPDIR:-/ tmp} " ]; then
189189 export UV_CACHE_DIR=" ${TMPDIR:-/ tmp} /uv-cache-${USER:- $(id -un)} "
190190 fi
191+
192+ # uv's cache (~/.cache/uv by default, or the node-local redirect above
193+ # in CI) is shared per-user across every repo/worktree/matrix leg. uv's
194+ # own cache lock protects individual entries, but concurrent installs
195+ # from separate uv processes can still race while one extracts/prunes
196+ # the shared archive-v0 store, leaving a corrupted entry (e.g. a
197+ # missing dist-info METADATA file) that fails every subsequent install
198+ # until the cache is manually cleared -- both across self-hosted CI
199+ # matrix legs (Frontier, Phoenix) sharing a login node, and across
200+ # concurrent local builds by the same user. Serialize the install
201+ # call itself so only one uv process touches a given cache dir at a
202+ # time. Fall back to /tmp for the lock file itself if TMPDIR isn't
203+ # writable (e.g. a stale TMPDIR left over from a prior job's
204+ # since-deleted scratch dir), so a bad TMPDIR can't break installs
205+ # that used to work fine before this lock existed.
206+ UV_LOCK_DIR=" ${TMPDIR:-/ tmp} "
207+ [ -d " $UV_LOCK_DIR " ] && [ -w " $UV_LOCK_DIR " ] || UV_LOCK_DIR=/tmp
208+ UV_INSTALL_LOCK=" ${UV_LOCK_DIR} /mfc-uv-install-${USER:- $(id -un)} .lock"
209+ if command -v flock > /dev/null 2>&1 ; then
210+ uv_install () { flock " $UV_INSTALL_LOCK " uv pip install " $@ " ; }
211+ else
212+ uv_install () { uv pip install " $@ " ; }
213+ fi
214+
215+ # A cache entry corrupted before this lock existed (or by any other
216+ # cause) will otherwise fail every subsequent install until someone
217+ # notices and clears the cache by hand -- which is exactly what
218+ # happened here (a stale corrupted entry on a self-hosted runner kept
219+ # failing across multiple PRs before anyone caught it). Self-heal: on
220+ # the first failure, clear the cache and retry once before giving up.
221+ uv_install_with_retry () {
222+ if uv_install " $@ " ; then
223+ return 0
224+ fi
225+ warn " (venv) uv install failed; clearing the uv cache and retrying once, in case a corrupted cache entry is the cause..."
226+ uv cache clean > /dev/null 2>&1 || true
227+ uv_install " $@ "
228+ }
191229 log " (venv) Using$MAGENTA uv$COLOR_RESET for fast installation..."
192230
193231 if [ " $verbose " = " 1" ]; then
194232 # Verbose mode: show full uv output
195- if uv pip install " $( pwd) /toolchain" ; then
233+ if uv_install_with_retry " $( pwd) /toolchain" ; then
196234 ok " (venv) Installation succeeded."
197235 cp " $( pwd) /toolchain/pyproject.toml" " $( pwd) /build/"
198236 else
@@ -203,7 +241,7 @@ if ! cmp "$(pwd)/toolchain/pyproject.toml" "$(pwd)/build/pyproject.toml" > /dev/
203241 fi
204242 else
205243 # Default: show progress but filter out individual package lines (+ pkg==ver)
206- uv pip install " $( pwd) /toolchain" > " $PIP_LOG " 2>&1
244+ uv_install_with_retry " $( pwd) /toolchain" > " $PIP_LOG " 2>&1
207245 UV_EXIT=$?
208246 # Show filtered output (progress info without package list)
209247 # Filter out lines like " + pkg==1.0", " - pkg==1.0", " ~ pkg==1.0"
0 commit comments