From db728ac2e4298c1d809ccab08d2b707fd6c144aa Mon Sep 17 00:00:00 2001 From: rob Date: Tue, 28 Oct 2025 22:24:46 -0300 Subject: [PATCH] 1st commit --- src/cascadingdev/cli.py | 13 ++++++++ tools/bundle_smoke.py | 74 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 tools/bundle_smoke.py diff --git a/src/cascadingdev/cli.py b/src/cascadingdev/cli.py index b5b9db3..1622485 100644 --- a/src/cascadingdev/cli.py +++ b/src/cascadingdev/cli.py @@ -16,6 +16,11 @@ def main(): p_rel.add_argument("--kind", choices=["major","minor","patch"], default="patch") p_pack = sub.add_parser("pack", help="Zip the current installer bundle") p_pack.add_argument("--out", help="Output zip path (default: ./install/cascadingdev-.zip)") + p_bs = sub.add_parser("bundle-smoke", help="Unpack the zip and run installer into a temp dir") + p_bs.add_argument("--keep", action="store_true") + p_bs.add_argument("--ramble", action="store_true") + p_bs.add_argument("--bundle", help="Path to installer zip") + p_bs.add_argument("--target", help="Write demo repo to this path") args = ap.parse_args() if args.version: @@ -65,5 +70,13 @@ def main(): print(f"Packed → {out}") return 0 + if args.cmd == "bundle-smoke": + cmd = [sys.executable, str(ROOT / "tools" / "bundle_smoke.py")] + if args.keep: cmd.append("--keep") + if args.ramble: cmd.append("--ramble") + if args.bundle: cmd += ["--bundle", args.bundle] + if args.target: cmd += ["--target", args.target] + return run(cmd) + ap.print_help() return 0 diff --git a/tools/bundle_smoke.py b/tools/bundle_smoke.py new file mode 100644 index 0000000..4fdd85b --- /dev/null +++ b/tools/bundle_smoke.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +import tempfile, shutil, subprocess, sys, argparse +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--bundle", help="Path to a specific installer zip (defaults to install/cascadingdev-.zip)") + ap.add_argument("--keep", action="store_true", help="Keep temporary directory for inspection") + ap.add_argument("--target", help="Write the demo repo to this path instead of a temp dir") + ap.add_argument("--ramble", action="store_true", help="Run installer without --no-ramble") + args = ap.parse_args() + + ver = (ROOT / "VERSION").read_text().strip() + zip_path = Path(args.bundle) if args.bundle else (ROOT / "install" / f"cascadingdev-{ver}.zip") + if not zip_path.exists(): + print(f"Zip missing: {zip_path}. Run `cdev pack` first or pass --bundle."); sys.exit(2) + + def run_once(extract_dir: Path, target_dir: Path) -> int: + shutil.unpack_archive(str(zip_path), str(extract_dir), "zip") + setup = next(extract_dir.rglob("setup_cascadingdev.py")) + target_dir.mkdir(parents=True, exist_ok=True) + print(f"[•] Running installer from: {setup}") + cmd = [sys.executable, str(setup), "--target", str(target_dir)] + if not args.ramble: + cmd.append("--no-ramble") + rc = subprocess.call(cmd) + if rc != 0: + print(f"Installer exited with {rc}"); return rc + # quick asserts + required = [ + target_dir / "process" / "policies.yml", + target_dir / "Docs" / "features" / ".ai-rules.yml", + target_dir / ".ai-rules.yml", + target_dir / "USER_GUIDE.md", + target_dir / ".git" / "hooks" / "pre-commit", + ] + missing = [str(p) for p in required if not p.exists()] + if missing: + print("Missing after install:\n " + "\n ".join(missing)); return 3 + print(f"[✓] Bundle smoke OK. Demo repo: {target_dir}") + return 0 + + if args.target: + # Use a fixed location (never auto-delete). Clean if exists. + target_dir = Path(args.target).expanduser().resolve() + if target_dir.exists(): + shutil.rmtree(target_dir) + extract_dir = target_dir.parent / (target_dir.name + "-bundle") + if extract_dir.exists(): + shutil.rmtree(extract_dir) + extract_dir.mkdir(parents=True, exist_ok=True) + rc = run_once(extract_dir, target_dir) + print(f"[i] Extracted bundle kept at: {extract_dir}") + return rc + + # Temp-mode (default) + with tempfile.TemporaryDirectory(prefix="cd-bundle-") as tmp: + tmpdir = Path(tmp) + extract_dir = tmpdir / "bundle" + target_dir = tmpdir / "demo-repo" + rc = run_once(extract_dir, target_dir) + if args.keep: + print(f"[i] Keeping temp dir: {tmpdir}") + print(" You can inspect it now; press Enter to clean up...") + try: input() + except EOFError: pass + return rc + # auto-clean + return rc + +if __name__ == "__main__": + sys.exit(main())