112 lines
3.0 KiB
Python
112 lines
3.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Export a clean Antigravity-only workspace from a full checkout."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import shutil
|
|
from pathlib import Path
|
|
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
|
|
FILES = [
|
|
"AGENTS.md",
|
|
"GEMINI.md",
|
|
"README.md",
|
|
"docs/antigravity-clean-workspace.md",
|
|
"docs/platform-adapters.md",
|
|
"scripts/dr.py",
|
|
"scripts/deploy_adapters.py",
|
|
]
|
|
|
|
DIRS = [
|
|
".agent",
|
|
"configs",
|
|
"scripts/runtime",
|
|
"scripts/reporting",
|
|
]
|
|
|
|
EMPTY_DIRS = [
|
|
"projects",
|
|
]
|
|
|
|
EXCLUDED_NAMES = {
|
|
"__pycache__",
|
|
".pytest_cache",
|
|
}
|
|
|
|
|
|
def copy_file(src: Path, dst: Path, *, dry_run: bool) -> None:
|
|
if dry_run:
|
|
print(f"file {src.relative_to(REPO_ROOT)} -> {dst}")
|
|
return
|
|
dst.parent.mkdir(parents=True, exist_ok=True)
|
|
shutil.copy2(src, dst)
|
|
|
|
|
|
def ignore_names(_: str, names: list[str]) -> set[str]:
|
|
return {name for name in names if name in EXCLUDED_NAMES}
|
|
|
|
|
|
def copy_dir(src: Path, dst: Path, *, dry_run: bool) -> None:
|
|
if dry_run:
|
|
print(f"dir {src.relative_to(REPO_ROOT)} -> {dst}")
|
|
return
|
|
if dst.exists():
|
|
shutil.rmtree(dst)
|
|
shutil.copytree(src, dst, ignore=ignore_names)
|
|
|
|
|
|
def export_workspace(target: Path, *, force: bool, dry_run: bool) -> None:
|
|
target = target.expanduser().resolve()
|
|
if target == REPO_ROOT:
|
|
raise SystemExit("target must not be the full repository root")
|
|
if target.exists() and any(target.iterdir()) and not force:
|
|
raise SystemExit(f"target is not empty: {target}; use --force to replace managed files")
|
|
|
|
if not dry_run:
|
|
target.mkdir(parents=True, exist_ok=True)
|
|
|
|
for rel in FILES:
|
|
src = REPO_ROOT / rel
|
|
if not src.exists():
|
|
raise FileNotFoundError(src)
|
|
copy_file(src, target / rel, dry_run=dry_run)
|
|
|
|
for rel in DIRS:
|
|
src = REPO_ROOT / rel
|
|
if not src.exists():
|
|
raise FileNotFoundError(src)
|
|
copy_dir(src, target / rel, dry_run=dry_run)
|
|
|
|
for rel in EMPTY_DIRS:
|
|
if dry_run:
|
|
print(f"dir {rel} -> {target / rel}")
|
|
else:
|
|
(target / rel).mkdir(parents=True, exist_ok=True)
|
|
keep = target / rel / ".gitkeep"
|
|
keep.touch(exist_ok=True)
|
|
|
|
if not dry_run:
|
|
print(f"exported clean Antigravity workspace: {target}")
|
|
print("open this target directory in Antigravity")
|
|
|
|
|
|
def build_parser() -> argparse.ArgumentParser:
|
|
parser = argparse.ArgumentParser(description="Export a clean Antigravity-only workspace")
|
|
parser.add_argument("--target", required=True, type=Path, help="output workspace directory")
|
|
parser.add_argument("--force", action="store_true", help="replace managed files in a non-empty target")
|
|
parser.add_argument("--dry-run", action="store_true", help="show what would be copied")
|
|
return parser
|
|
|
|
|
|
def main() -> int:
|
|
args = build_parser().parse_args()
|
|
export_workspace(args.target, force=args.force, dry_run=args.dry_run)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|