fix: harden termux update path with uv bootstrap and env guard

This commit is contained in:
adybag14-cyber 2026-05-08 19:31:40 +01:00 committed by Teknium
parent 6f7b698a08
commit 7c174e65f7
2 changed files with 41 additions and 3 deletions

View file

@ -5923,16 +5923,19 @@ def _update_via_zip(args):
# individually so update does not silently strip working capabilities.
print("→ Updating Python dependencies...")
uv_bin = shutil.which("uv")
pip_cmd = [sys.executable, "-m", "pip"]
uv_bin = shutil.which("uv") or _ensure_uv_for_termux(pip_cmd)
if uv_bin:
uv_env = {**os.environ, "VIRTUAL_ENV": str(PROJECT_ROOT / "venv")}
if _is_termux_env(uv_env):
uv_env.pop("PYTHONPATH", None)
uv_env.pop("PYTHONHOME", None)
_install_python_dependencies_with_optional_fallback([uv_bin, "pip"], env=uv_env)
else:
# Use sys.executable to explicitly call the venv's pip module,
# avoiding PEP 668 'externally-managed-environment' errors on Debian/Ubuntu.
# Some environments lose pip inside the venv; bootstrap it back with
# ensurepip before trying the editable install.
pip_cmd = [sys.executable, "-m", "pip"]
try:
subprocess.run(
pip_cmd + ["--version"],
@ -6564,6 +6567,25 @@ def _install_python_dependencies_with_optional_fallback(
)
def _is_termux_env(env: dict[str, str] | None = None) -> bool:
check = env or os.environ
prefix = str(check.get("PREFIX", ""))
return "com.termux" in prefix or prefix.startswith("/data/data/com.termux/")
def _ensure_uv_for_termux(pip_cmd: list[str]) -> str | None:
"""Best-effort uv bootstrap on Termux for faster update installs."""
uv_bin = shutil.which("uv")
if uv_bin or not _is_termux_env():
return uv_bin
try:
print(" → Termux detected: trying to install uv for faster dependency updates...")
subprocess.run(pip_cmd + ["install", "uv"], cwd=PROJECT_ROOT, check=False)
except Exception:
pass
return shutil.which("uv")
def _update_node_dependencies() -> None:
npm = shutil.which("npm")
if not npm:
@ -7304,9 +7326,13 @@ def _cmd_update_impl(args, gateway_mode: bool):
# breaks on this machine, keep base deps and reinstall the remaining extras
# individually so update does not silently strip working capabilities.
print("→ Updating Python dependencies...")
uv_bin = shutil.which("uv")
pip_cmd = [sys.executable, "-m", "pip"]
uv_bin = shutil.which("uv") or _ensure_uv_for_termux(pip_cmd)
if uv_bin:
uv_env = {**os.environ, "VIRTUAL_ENV": str(PROJECT_ROOT / "venv")}
if _is_termux_env(uv_env):
uv_env.pop("PYTHONPATH", None)
uv_env.pop("PYTHONHOME", None)
_install_python_dependencies_with_optional_fallback(
[uv_bin, "pip"], env=uv_env
)

View file

@ -246,3 +246,15 @@ class TestCmdUpdateProfileSkillSync:
cmd_update(mock_args)
assert default_p.path in synced_paths
def test_is_termux_env_true_for_termux_prefix():
from hermes_cli import main as hm
assert hm._is_termux_env({"PREFIX": "/data/data/com.termux/files/usr"}) is True
def test_is_termux_env_false_for_non_termux_prefix():
from hermes_cli import main as hm
assert hm._is_termux_env({"PREFIX": "/usr/local"}) is False