93 lines
2.5 KiB
Python
93 lines
2.5 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Run fish-tty-repro.js under a pseudo-TTY and drain output so Node never blocks on write.
|
|
|
|
Usage (from anywhere):
|
|
python3 packages/bare-os-booter/scripts/run-fish-repro-pty.py
|
|
|
|
BARE_OS_REPRO_SKIP_STDERR=1 python3 packages/bare-os-booter/scripts/run-fish-repro-pty.py
|
|
|
|
BARE_OS_REPRO_PTY_ASSERT=1 ... # exit 2 if green prompt not detected (CI guard)
|
|
|
|
Requires: Unix (pty). Not for Windows CI.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import pty
|
|
import select
|
|
import sys
|
|
import threading
|
|
import time
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
BOOTER = os.path.dirname(HERE)
|
|
|
|
|
|
def main() -> int:
|
|
chunks: list[bytes] = []
|
|
|
|
def reader(master_fd: int, done: threading.Event) -> None:
|
|
while not done.is_set():
|
|
try:
|
|
r, _, _ = select.select([master_fd], [], [], 0.2)
|
|
except (OSError, ValueError):
|
|
break
|
|
if done.is_set():
|
|
break
|
|
if not r:
|
|
continue
|
|
try:
|
|
data = os.read(master_fd, 65536)
|
|
except OSError:
|
|
break
|
|
if not data:
|
|
break
|
|
chunks.append(data)
|
|
|
|
pid, master_fd = pty.fork()
|
|
if pid == 0:
|
|
os.chdir(BOOTER)
|
|
os.execlp("node", "node", os.path.join(HERE, "fish-tty-repro.js"))
|
|
return 0 # unreachable
|
|
|
|
done = threading.Event()
|
|
t = threading.Thread(target=reader, args=(master_fd, done))
|
|
t.start()
|
|
time.sleep(0.6)
|
|
os.write(master_fd, b"hello\n")
|
|
time.sleep(0.35)
|
|
os.write(master_fd, b"exit\n")
|
|
# Wait for Node to exit before closing the PTY master (avoids exit code 1 / hang).
|
|
_, status = os.waitpid(pid, 0)
|
|
|
|
done.set()
|
|
t.join(timeout=5.0)
|
|
try:
|
|
os.close(master_fd)
|
|
except OSError:
|
|
pass
|
|
raw = b"".join(chunks)
|
|
try:
|
|
sys.stdout.buffer.write(raw)
|
|
except BrokenPipeError:
|
|
pass
|
|
|
|
text = raw.decode("utf-8", errors="replace")
|
|
ok_green = "\x1b[32m[user@bare-os" in text or "[user@bare-os" in text
|
|
|
|
sys.stderr.write(
|
|
f"\n--- pty harness: exit status {status}, bytes {len(raw)}, "
|
|
f"saw_full_prompt_hint={ok_green} ---\n"
|
|
)
|
|
if os.environ.get("BARE_OS_REPRO_PTY_ASSERT") == "1" and not ok_green:
|
|
sys.stderr.write("BARE_OS_REPRO_PTY_ASSERT: expected green [user@bare-os] prompt\n")
|
|
return 2
|
|
if os.WIFEXITED(status):
|
|
return os.WEXITSTATUS(status)
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|