mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-13 10:36:35 +00:00
fix(update): keep the rollback's pip retries inside the unit time limit
The health check reinstalled the previous requirements by trying the next bash path after any failure, including a 600 s pip timeout. Two files, two paths: up to 40 minutes of pip alone, while systemd stops ledmatrix-update-verify.service at TimeoutStartSec=30min -- killing the rollback half-way and leaving the update 'verifying' until the web UI calls it lost. - Like permission_utils.install_requirements_file, only a sudo refusal moves on to the next bash; a pip that ran and failed or timed out is not repeated. The refusal wording is one list (permission_utils.SUDO_REFUSAL_PHRASES), mirrored in the stdlib-only verifier and pinned equal by a test. - All reinstalls in one rollback share a 600 s budget. - WORST_CASE_SECONDS adds up every timeout on the longest path (27.5 min); a test holds it under the unit's TimeoutStartSec and that under the web UI's VERIFY_LOST_SECONDS. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -373,6 +373,14 @@ def sudo_remove_directory(path: Path, allowed_bases: Optional[list] = None) -> b
|
||||
return False
|
||||
|
||||
|
||||
#: What sudo prints when it refuses a command line outright (not in sudoers for
|
||||
#: that exact argv, or it wants a password). Only then is another bash path
|
||||
#: worth trying: after pip itself ran, a retry just repeats the failure. The
|
||||
#: automatic update's health check keeps its own copy of this list
|
||||
#: (scripts/utils/auto_update_verify.py runs without importing src/).
|
||||
SUDO_REFUSAL_PHRASES = ("a password is required", "is not allowed to run", "no tty present")
|
||||
|
||||
|
||||
def install_requirements_file(req_file: Path, timeout: int = 300) -> subprocess.CompletedProcess:
|
||||
"""
|
||||
Install a requirements.txt file for a plugin (or the project itself).
|
||||
@@ -434,10 +442,7 @@ def install_requirements_file(req_file: Path, timeout: int = 300) -> subprocess.
|
||||
# Distinguish "sudo rejected this exact command line" (worth
|
||||
# trying the next bash candidate) from "sudo ran it but pip
|
||||
# itself failed" (a real error — stop and surface it).
|
||||
denied = any(
|
||||
phrase in result.stderr
|
||||
for phrase in ("a password is required", "is not allowed to run", "no tty present")
|
||||
)
|
||||
denied = any(phrase in result.stderr for phrase in SUDO_REFUSAL_PHRASES)
|
||||
if not denied:
|
||||
# Deliberately don't interpolate req_file or the pip output here:
|
||||
# this log line is scanner-visible, and a static analyzer can't
|
||||
|
||||
Reference in New Issue
Block a user