Less stack-centric and location-centric model.
This commit is contained in:
62
cli/src/castle_cli/commands/clone.py
Normal file
62
cli/src/castle_cli/commands/clone.py
Normal file
@@ -0,0 +1,62 @@
|
||||
"""castle clone — clone source for programs that declare a `repo:` URL.
|
||||
|
||||
Used to provision a fresh machine: every program with a `repo:` and a missing
|
||||
local `source:` gets cloned. A program whose source already exists is skipped.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
from castle_cli.config import REPOS_DIR, load_config
|
||||
|
||||
|
||||
def _clone_one(name: str, repo: str, source: str | None, ref: str | None) -> bool:
|
||||
dest = Path(source) if source else REPOS_DIR / name
|
||||
if dest.exists():
|
||||
print(f" {name}: already present at {dest}, skipping")
|
||||
return True
|
||||
dest.parent.mkdir(parents=True, exist_ok=True)
|
||||
cmd = ["git", "clone", repo, str(dest)]
|
||||
print(f" {name}: cloning {repo} → {dest}")
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
print(f" {name}: clone failed:\n{result.stderr}")
|
||||
return False
|
||||
if ref:
|
||||
co = subprocess.run(
|
||||
["git", "-C", str(dest), "checkout", ref], capture_output=True, text=True
|
||||
)
|
||||
if co.returncode != 0:
|
||||
print(f" {name}: checkout {ref} failed:\n{co.stderr}")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def run_clone(args: argparse.Namespace) -> int:
|
||||
config = load_config()
|
||||
|
||||
if getattr(args, "name", None):
|
||||
if args.name not in config.programs:
|
||||
print(f"Unknown program: {args.name}")
|
||||
return 1
|
||||
prog = config.programs[args.name]
|
||||
if not prog.repo:
|
||||
print(f"{args.name} has no repo: URL to clone from")
|
||||
return 1
|
||||
return 0 if _clone_one(args.name, prog.repo, prog.source, prog.ref) else 1
|
||||
|
||||
# Clone all programs that declare a repo: and lack a present source.
|
||||
all_ok = True
|
||||
cloned_any = False
|
||||
for name, prog in config.programs.items():
|
||||
if not prog.repo:
|
||||
continue
|
||||
cloned_any = True
|
||||
if not _clone_one(name, prog.repo, prog.source, prog.ref):
|
||||
all_ok = False
|
||||
if not cloned_any:
|
||||
print("No programs declare a repo: URL.")
|
||||
return 0 if all_ok else 1
|
||||
Reference in New Issue
Block a user