fix(install): abort Windows venv recreate when rename-aside fails
When Rename-Item on the live venv is denied, do not fall back to an in-place Remove-Item that can gut site-packages and leave no rollback. Also mark venv-blocker probe failures with probe_failed so they cannot be read as a clear scan (#83149).
This commit is contained in:
@@ -28,14 +28,28 @@ _SENSITIVE_LONG_FLAGS: list[str] = [
|
||||
]
|
||||
|
||||
|
||||
def _probe_fail_json() -> str:
|
||||
"""Return the standard probe-failure JSON document."""
|
||||
return json.dumps({"ok": False, "blocked": False, "processes": []})
|
||||
def _probe_fail_json(diagnostic: str = "probe failed") -> str:
|
||||
"""Return the standard probe-failure JSON document.
|
||||
|
||||
``ok: false`` plus ``probe_failed: true`` means the detector itself could
|
||||
not run — this is *not* a clear scan. Callers must treat
|
||||
``ok is not True`` / non-zero exit as probe failure, never as
|
||||
``blocked: false`` "clear" (#83149).
|
||||
"""
|
||||
return json.dumps(
|
||||
{
|
||||
"ok": False,
|
||||
"probe_failed": True,
|
||||
"blocked": False,
|
||||
"processes": [],
|
||||
"error": diagnostic,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _emit_probe_fail(diagnostic: str) -> NoReturn:
|
||||
"""Print one JSON to stdout, diagnostic to stderr, exit non-zero."""
|
||||
print(_probe_fail_json())
|
||||
print(_probe_fail_json(diagnostic))
|
||||
print(diagnostic, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
+12
-4
@@ -2460,15 +2460,23 @@ function Install-Venv {
|
||||
}
|
||||
# Move the old venv aside before creating its replacement. A directory
|
||||
# rename is atomic on the same volume and does not require deleting
|
||||
# files mapped as DLLs. Never fall back to deleting the live venv:
|
||||
# Windows can remove unlocked files first, then fail on one locked
|
||||
# file, leaving no usable interpreter and no rollback source.
|
||||
# files mapped as DLLs. NEVER fall back to deleting the live venv
|
||||
# (#83149): Remove-Item -Recurse can delete most of site-packages and
|
||||
# then fail on one locked .pyd, leaving a gutted venv with no usable
|
||||
# interpreter and no rollback source. Abort with the previous install
|
||||
# intact so the user can close holders and retry.
|
||||
$venvBackupName = "venv.stale.{0}-{1}" -f (Get-Date -Format "yyyyMMddHHmmss"), ([Guid]::NewGuid().ToString("N"))
|
||||
try {
|
||||
Rename-Item -LiteralPath "venv" -NewName $venvBackupName -ErrorAction Stop
|
||||
$venvParked = $true
|
||||
} catch {
|
||||
throw "Could not move existing venv aside without deleting it. Close running Hermes processes and retry. $($_.Exception.Message)"
|
||||
$renameErr = $_.Exception.Message
|
||||
throw (
|
||||
"Could not move the existing venv aside ($renameErr). " +
|
||||
"A process still has the install directory open (often a non-Hermes " +
|
||||
"python.exe that resolved into this venv via PATH). Close those " +
|
||||
"processes and retry - the previous install was left intact."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user