#!/usr/bin/env python3 """Run the local app and its frontend watcher with one command.""" import os import signal import socket import subprocess import sys import time from pathlib import Path ROOT = Path(__file__).resolve().parent def start(): with socket.socket() as probe: if probe.connect_ex(("127.0.0.1", 8778)) == 0: raise SystemExit("port 8778 is already in use") commands = [ (["mise", "exec", "--", "python", "manage.py", "runserver", "8778"], ROOT), (["mise", "exec", "--", "npx", "shadow-cljs", "watch", "app"], ROOT / "frontend"), ] children = [] stopping = False def stop(_signal, _frame): nonlocal stopping stopping = True signal.signal(signal.SIGINT, stop) signal.signal(signal.SIGTERM, stop) try: for command, directory in commands: children.append(subprocess.Popen(command, cwd=directory, start_new_session=True)) print("arthur: http://localhost:8778 (Ctrl-C stops both processes)", flush=True) while not stopping: for child in children: if child.poll() is not None: raise SystemExit(f"app process exited with status {child.returncode}") time.sleep(0.25) finally: for child in children: if child.poll() is None: os.killpg(child.pid, signal.SIGTERM) for child in children: try: child.wait(timeout=5) except subprocess.TimeoutExpired: os.killpg(child.pid, signal.SIGKILL) child.wait() if __name__ == "__main__": if sys.argv[1:] == ["start"]: start() else: raise SystemExit("usage: ./do start")