mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-01 12:02:05 +00:00
* fix(windows): stop subprocess console-window popups + add CI guard The single biggest source of Windows 'terminal popup' bug reports was bare subprocess.run/Popen calls spawning a console window. The compat helpers (windows_hide_flags / windows_detach_popen_kwargs) already existed but the footgun checker had no rule to stop new bare calls from reintroducing the flash. - scripts/check-windows-footguns.py: new AST-based rule flagging subprocess calls that can create a new console — output-redirection-aware (capture/ redirect/check_output exempt) and POSIX-only-program-aware (launchctl/ systemctl/brew/etc. exempt). Comprehensive on real popups, no annotation burden on calls that can't flash. - Swept all genuine window-spawning sites through windows_hide_flags()/ windows_detach_popen_kwargs(); marked intentionally-visible launches (editor/terminal/foreground re-exec) with '# windows-footgun: ok'. - tests/scripts/test_windows_footgun_subprocess_rule.py: behavior-contract tests + full-repo cleanliness invariant. - CONTRIBUTING.md: documents the rule + the helper pattern. * test: accept creationflags kwarg in psutil_android fake_subprocess_run The Windows no-window sweep added creationflags=windows_hide_flags() to install_psutil_android.py's subprocess.run call; the test's fake stub had a fixed (cmd) signature and raised TypeError on the new kwarg.
103 lines
3.2 KiB
Python
Executable file
103 lines
3.2 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""Install psutil on Termux/Android by patching upstream platform detection.
|
|
|
|
psutil's setup currently gates Linux sources behind
|
|
``sys.platform.startswith('linux')``. On Termux, Python reports
|
|
``sys.platform == 'android'``, so ``pip install psutil`` aborts with
|
|
"platform android is not supported" — even though psutil compiles fine
|
|
when the Linux source path is reused.
|
|
|
|
This script downloads the official psutil sdist, applies a one-line
|
|
patch (``LINUX = sys.platform.startswith(("linux", "android"))``), and
|
|
installs the patched tree with ``pip install --no-build-isolation``.
|
|
|
|
Usage:
|
|
python scripts/install_psutil_android.py [--pip "/path/to/pip"] [--uv]
|
|
|
|
When neither flag is given, the script auto-detects ``uv`` on PATH and
|
|
falls back to ``<sys.executable> -m pip``.
|
|
|
|
This is a stopgap. Remove once psutil upstream merges
|
|
https://github.com/giampaolo/psutil/pull/2762 and ships a release.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import urllib.request
|
|
from pathlib import Path
|
|
|
|
# Keep sibling imports working when invoked as
|
|
# ``python scripts/install_psutil_android.py`` from the repo checkout.
|
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
if str(REPO_ROOT) not in sys.path:
|
|
sys.path.insert(0, str(REPO_ROOT))
|
|
|
|
from hermes_cli.psutil_android import (
|
|
PSUTIL_URL,
|
|
PsutilAndroidInstallError,
|
|
prepare_patched_psutil_sdist,
|
|
)
|
|
from hermes_cli._subprocess_compat import windows_hide_flags
|
|
|
|
|
|
|
|
def _resolve_install_cmd(pip_arg: str | None, prefer_uv: bool) -> list[str]:
|
|
if pip_arg:
|
|
return pip_arg.split()
|
|
if prefer_uv:
|
|
uv = shutil.which("uv")
|
|
if not uv:
|
|
sys.exit("--uv requested but no uv on PATH")
|
|
return [uv, "pip"]
|
|
auto_uv = shutil.which("uv")
|
|
if auto_uv:
|
|
return [auto_uv, "pip"]
|
|
return [sys.executable, "-m", "pip"]
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument(
|
|
"--pip",
|
|
help="Explicit installer command (e.g. '/usr/bin/uv pip' or 'python -m pip')",
|
|
)
|
|
parser.add_argument(
|
|
"--uv",
|
|
action="store_true",
|
|
help="Force using uv (errors out if uv is not on PATH)",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
install_cmd_prefix = _resolve_install_cmd(args.pip, args.uv)
|
|
|
|
print(
|
|
"→ Termux/Android: prebuilding psutil with Linux source path "
|
|
"compatibility shim (see psutil#2762)..."
|
|
)
|
|
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
tmp_path = Path(tmp)
|
|
archive = tmp_path / "psutil.tar.gz"
|
|
urllib.request.urlretrieve(PSUTIL_URL, archive)
|
|
try:
|
|
src_root = prepare_patched_psutil_sdist(archive, tmp_path)
|
|
except PsutilAndroidInstallError as exc:
|
|
sys.exit(str(exc))
|
|
|
|
cmd = install_cmd_prefix + ["install", "--no-build-isolation", str(src_root)]
|
|
print(f" $ {' '.join(cmd)}")
|
|
result = subprocess.run(cmd, creationflags=windows_hide_flags())
|
|
if result.returncode != 0:
|
|
return result.returncode
|
|
|
|
print("✓ psutil installed via Android compatibility shim")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|