59 lines
1.7 KiB
Python
Executable file
59 lines
1.7 KiB
Python
Executable file
#!/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")
|