Files

73 lines
2.2 KiB
Python

"""Run Typst watchers with readable, document-specific output."""
from pathlib import Path
from queue import Empty, Queue
import signal
import subprocess
import sys
from threading import Thread
def relay(process, label, messages):
with process.stdout:
for line in process.stdout:
messages.put((label, line.rstrip()))
messages.put((label, None))
def interrupted(signum, frame):
raise KeyboardInterrupt
def main():
separator = sys.argv.index("--")
executable, *flags = sys.argv[1:separator]
sources = sys.argv[separator + 1:]
messages = Queue()
processes = []
signal.signal(signal.SIGTERM, interrupted)
try:
for source in sources:
process = subprocess.Popen(
[executable, "watch", *flags, source, str(Path(source).with_suffix(".pdf"))],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
encoding="utf-8",
errors="replace",
start_new_session=True,
)
processes.append(process)
Thread(target=relay, args=(process, source, messages), daemon=True).start()
while True:
try:
label, line = messages.get(timeout=0.2)
except Empty:
continue
if line is None:
print(f"[{label}] Watch-Prozess unerwartet beendet.", file=sys.stderr)
return 1
if line:
print(f"[{label}] {line}", flush=True)
except KeyboardInterrupt:
print("\nÜberwachung beendet.", flush=True)
return 0
except OSError as error:
print(f"Watch konnte nicht gestartet werden: {error}", file=sys.stderr)
return 1
finally:
# Stop all watchers, including when startup fails partway through.
for process in processes:
if process.poll() is None:
process.terminate()
for process in processes:
try:
process.wait(timeout=3)
except subprocess.TimeoutExpired:
process.kill()
process.wait()
if __name__ == "__main__":
sys.exit(main())