quranic-universal-audio / scripts /devenv /setup_worktree.py
hetchyy's picture
deploy: inspector prod @ b45afa4 (part 6)
81ba97c verified
Raw
History Blame Contribute Delete
4.02 kB
#!/usr/bin/env python3
"""Fast worktree bootstrap β€” mirror `.env` + `node_modules` from the main checkout.
A freshly-added linked git worktree has no `.env` and empty `node_modules`, so
`npm run test`/`check`/`lint`/`build` and `/launch` all fail until deps exist.
Re-running the full `setup.sh` (`npm ci` + `pip`) per worktree is slow; this
copies the already-installed trees from the main worktree instead:
- `.env` (root env file)
- `node_modules` (root β€” husky + lint-staged for git hooks)
- `inspector/frontend/node_modules` (the SPA toolchain: vite / svelte / vitest)
Idempotent: skips anything already present in the worktree, never clobbers an
existing `.env`. If the main checkout itself has no `node_modules` to copy, it
falls back to `scripts/devenv/setup.sh frontend` so a first-ever setup still
works. Cross-platform: robocopy on Windows, `cp -a` elsewhere. Invoked by the
`wt` skill; safe to run from any worktree (a no-op from the main one).
"""
from __future__ import annotations
import subprocess
import sys
from pathlib import Path
def _git(*args: str, cwd: Path | None = None) -> str:
out = subprocess.run(["git", *args], cwd=cwd, capture_output=True, text=True, check=True)
return out.stdout.strip()
def _main_worktree_root(here: Path) -> Path:
"""Root of the main worktree (the one holding the shared `.git` dir)."""
common = Path(_git("rev-parse", "--path-format=absolute", "--git-common-dir", cwd=here))
return common.parent
def _copy_dir(src: Path, dst: Path) -> None:
"""Recursively copy `src` β†’ `dst` using the fastest tool per OS."""
dst.parent.mkdir(parents=True, exist_ok=True)
if sys.platform == "win32":
# robocopy exit codes 0-7 are success (8+ is a real failure).
code = subprocess.run(
[
"robocopy",
str(src),
str(dst),
"/E",
"/MT:16",
"/NFL",
"/NDL",
"/NJH",
"/NJS",
"/NP",
"/R:1",
"/W:1",
],
).returncode
if code >= 8:
raise RuntimeError(f"robocopy failed ({code}) copying {src} -> {dst}")
else:
dst.mkdir(parents=True, exist_ok=True)
subprocess.run(["cp", "-a", f"{src}/.", str(dst)], check=True)
def _has_entries(p: Path) -> bool:
return p.is_dir() and any(p.iterdir())
def _mirror(main: Path, here: Path) -> None:
env_src, env_dst = main / ".env", here / ".env"
if env_dst.exists():
print(" .env: present, kept")
elif env_src.is_file():
env_dst.write_bytes(env_src.read_bytes())
print(" .env: copied from main")
else:
print(" .env: none in main, skipped")
fe = Path("inspector/frontend/node_modules")
for rel in (Path("node_modules"), fe):
src, dst = main / rel, here / rel
if _has_entries(dst):
print(f" {rel.as_posix()}: present, kept")
elif _has_entries(src):
print(f" {rel.as_posix()}: copying from main ...")
_copy_dir(src, dst)
print(f" {rel.as_posix()}: done")
elif rel == fe:
print(" inspector/frontend/node_modules: none in main; running setup.sh frontend")
subprocess.run(["bash", str(here / "scripts/devenv/setup.sh"), "frontend"], check=True)
else:
print(f" {rel.as_posix()}: none in main, skipped")
def main() -> int:
here = Path(_git("rev-parse", "--show-toplevel")).resolve()
main_root = _main_worktree_root(here).resolve()
if main_root == here:
print("Already in the main worktree β€” nothing to mirror.")
return 0
print(f"Bootstrapping worktree from {main_root} ...")
_mirror(main_root, here)
print("Worktree ready. Use the pinned npm scripts (npm run check / build / test).")
return 0
if __name__ == "__main__":
sys.exit(main())