77 lines
2.3 KiB
Python
77 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Regression test: cmux CLI should not exit with SIGPIPE on broken stdout pipes."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import glob
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
|
|
|
|
def resolve_cmux_cli() -> str:
|
|
explicit = os.environ.get("CMUX_CLI_BIN") or os.environ.get("CMUX_CLI")
|
|
if explicit and os.path.exists(explicit) and os.access(explicit, os.X_OK):
|
|
return explicit
|
|
|
|
candidates: list[str] = []
|
|
candidates.extend(glob.glob(os.path.expanduser("~/Library/Developer/Xcode/DerivedData/*/Build/Products/Debug/cmux")))
|
|
candidates.extend(glob.glob("/tmp/cmux-*/Build/Products/Debug/cmux"))
|
|
candidates = [p for p in candidates if os.path.exists(p) and os.access(p, os.X_OK)]
|
|
if candidates:
|
|
candidates.sort(key=os.path.getmtime, reverse=True)
|
|
return candidates[0]
|
|
|
|
in_path = shutil.which("cmux")
|
|
if in_path:
|
|
return in_path
|
|
|
|
raise RuntimeError("Unable to find cmux CLI binary. Set CMUX_CLI_BIN.")
|
|
|
|
|
|
def run_with_closed_stdout(cli_path: str, *args: str) -> tuple[int, str]:
|
|
read_fd, write_fd = os.pipe()
|
|
os.close(read_fd)
|
|
proc = subprocess.Popen(
|
|
[cli_path, *args],
|
|
stdout=write_fd,
|
|
stderr=subprocess.PIPE,
|
|
text=True,
|
|
close_fds=True,
|
|
)
|
|
os.close(write_fd)
|
|
_, stderr = proc.communicate()
|
|
return proc.returncode, (stderr or "").strip()
|
|
|
|
|
|
def require_zero_exit(cli_path: str, *args: str) -> tuple[bool, str]:
|
|
code, err = run_with_closed_stdout(cli_path, *args)
|
|
if code != 0:
|
|
cmd = " ".join(args)
|
|
return False, f"`cmux {cmd}` exited {code} with closed stdout pipe (stderr={err!r})"
|
|
return True, ""
|
|
|
|
|
|
def main() -> int:
|
|
try:
|
|
cli_path = resolve_cmux_cli()
|
|
except Exception as exc:
|
|
print(f"FAIL: {exc}")
|
|
return 1
|
|
|
|
ok_version, version_msg = require_zero_exit(cli_path, "--version")
|
|
ok_help, help_msg = require_zero_exit(cli_path, "help")
|
|
|
|
failures = [msg for msg in [version_msg, help_msg] if msg]
|
|
if failures:
|
|
print("FAIL: CLI still fails on broken stdout pipes")
|
|
for failure in failures:
|
|
print(f"- {failure}")
|
|
return 1
|
|
|
|
print("PASS: CLI ignores SIGPIPE and exits cleanly when stdout pipe is closed")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|