fix(update_stage): look the shim marker up in the process home, not ~/.hermes
update_stage rebuilt the home from HERMES_HOME with a literal ~/.hermes fallback while update_lock resolves the same marker through get_process_hermes_home(). Where the platform default differs (sudo invoker, data-dir suffix) the two disagreed and the old-shim UI fallback found no marker, leaving the hand-off window frozen. hermes_constants is stdlib-only, so the lazy import keeps this module usable under -I -S -B.
This commit is contained in:
@@ -33,6 +33,14 @@ UI_SPAWNED_ENV = "HERMES_UPDATE_UI_ACTIVE"
|
||||
MARKER_NAME = ".hermes-update-in-progress"
|
||||
|
||||
|
||||
def _process_home() -> Path:
|
||||
"""The marker and the shim's log live in the PROCESS home (update_lock.update_marker_path):
|
||||
the shim resolved ``$HERMES_HOME`` or the platform default, never a profile override, and
|
||||
the platform default (sudo invoker, data-dir suffix) is not ``~/.hermes`` everywhere."""
|
||||
from hermes_constants import get_process_hermes_home
|
||||
return get_process_hermes_home()
|
||||
|
||||
|
||||
def status_file() -> Path | None:
|
||||
"""The watching shim's status file, or None when no UI is discoverable."""
|
||||
exported = os.environ.get(STATUS_FILE_ENV, "").strip()
|
||||
@@ -49,9 +57,8 @@ def _status_from_marker() -> Path | None:
|
||||
shim's status file lives beside it, pid-suffixed. No marker (plain CLI
|
||||
update) or no matching file → no UI.
|
||||
"""
|
||||
home = os.environ.get("HERMES_HOME") or str(Path.home() / ".hermes")
|
||||
try:
|
||||
pid = int((Path(home) / MARKER_NAME).read_text(encoding="utf-8-sig")
|
||||
pid = int((_process_home() / MARKER_NAME).read_text(encoding="utf-8-sig")
|
||||
.splitlines()[0].strip())
|
||||
except (OSError, ValueError, IndexError):
|
||||
return None
|
||||
@@ -113,8 +120,7 @@ def ensure_panel(update_root: Path) -> None:
|
||||
if not panel.is_file():
|
||||
return
|
||||
try:
|
||||
home = os.environ.get("HERMES_HOME") or str(Path.home() / ".hermes")
|
||||
log = Path(home) / "logs" / "desktop-update-handoff.log"
|
||||
log = _process_home() / "logs" / "desktop-update-handoff.log"
|
||||
if log.is_file() and _ui_present_in_log(log.read_text(encoding="utf-8-sig", errors="replace")[-8000:]):
|
||||
return
|
||||
import subprocess
|
||||
|
||||
@@ -67,6 +67,24 @@ def test_marker_fallback_covers_the_old_shim(status_file, tmp_path, monkeypatch)
|
||||
"Updating Python dependencies (PM)")
|
||||
|
||||
|
||||
def test_marker_fallback_uses_the_platform_home_without_env_var(status_file, tmp_path, monkeypatch):
|
||||
"""The shim without HERMES_HOME resolved the platform default, which is not ~/.hermes
|
||||
on every host (sudo invoker, data-dir suffix); the marker must be looked up there."""
|
||||
import hermes_constants
|
||||
|
||||
monkeypatch.delenv("HERMES_HOME", raising=False)
|
||||
monkeypatch.setattr(hermes_constants, "_get_platform_default_hermes_home", lambda: tmp_path / "platform")
|
||||
(tmp_path / "platform").mkdir()
|
||||
(tmp_path / "platform" / update_stage.MARKER_NAME).write_text(
|
||||
f"80335\n{int(time.time())}\n", encoding="utf-8")
|
||||
status_file.write_text('{"status":"running","message":"old"}', encoding="utf-8")
|
||||
monkeypatch.setenv("TMPDIR", str(tmp_path))
|
||||
|
||||
update_stage.publish_stage("Building products")
|
||||
|
||||
_assert_running(status_file.read_text(encoding="utf-8"), "Building products")
|
||||
|
||||
|
||||
def test_no_ui_sources_is_inert(status_file, tmp_path, monkeypatch):
|
||||
"""A plain CLI update has no env var and no marker: publish must no-op."""
|
||||
monkeypatch.setenv("HERMES_HOME", str(tmp_path)) # no marker inside
|
||||
|
||||
Reference in New Issue
Block a user