#!/usr/bin/env python3 """Build the configured operator frontend from its fixed working directory. No npm lifecycle hooks, standalone typechecks, tests or native builds. The caller groups related frontend edits before invoking this delivery command. """ import os import fcntl from pathlib import Path import shutil import subprocess import sys import time def main(): web = Path(__file__).resolve().parents[1] / "web" vite = web / "node_modules/vite/bin/vite.js" node = shutil.which("node") if not node or not vite.is_file(): print(f"Frontend dependency unavailable: node={node}, Vite={vite}", file=sys.stderr) return 2 env = {**os.environ, "FREECAD_WEB_FAST_LINK": "ON"} # The foreground session and the sole scheduler share web/dist. Keep the # lock outside dist: Vite clears that directory before writing a bundle. with (web / ".freecad-web-frontend-build.lock").open("a") as lock: started = time.monotonic() waiting = False while True: try: fcntl.flock(lock.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB) break except BlockingIOError: if not waiting: print("Waiting for the existing frontend delivery to release web/dist", flush=True) waiting = True if time.monotonic() - started >= 1800: print("Frontend delivery lock timed out; retain edits and resume after the active build", file=sys.stderr) return 124 time.sleep(0.25) # Vite retains the descriptor if the outer runner exits mid-delivery. return subprocess.run([node, str(vite), "build"], cwd=web, env=env, pass_fds=(lock.fileno(),), check=False).returncode if __name__ == "__main__": raise SystemExit(main())