import importlib.util from pathlib import Path from typing import Any from src.layout import Layout REQUIRED_KEYS = ("arch", "triple", "container_image") def _load_module(path: Path, name: str): spec = importlib.util.spec_from_file_location(name, path) if spec is None or spec.loader is None: raise RuntimeError(f"cannot load profile module {path}") mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) return mod def load_profile(layout: Layout) -> dict[str, Any]: link = layout.profile_link if not link.exists(): raise FileNotFoundError(f"{link} missing a profile") target = link.resolve() if not target.is_file(): raise FileNotFoundError(f"profile {target.name}: missing config.py") mod = _load_module(target, f"orchid_profile_{target.name}") if not hasattr(mod, "profile"): raise AttributeError(f"profile {target.name}: config.py must define profile()") data = mod.profile() if not isinstance(data, dict): raise TypeError(f"profile {target.name}: profile() must return a dict") missing = [k for k in REQUIRED_KEYS if k not in data] if missing: raise ValueError(f"profile {target.name}: missing keys {missing}") data["__name__"] = target.name return data def init_build_dir(build: Path, repo: Path, profile_name: str) -> None: profile_src = repo / "profiles" / (profile_name + ".py") if not (profile_src).is_file(): raise FileNotFoundError(f"profile {profile_name!r} not found at {profile_src}") build.mkdir(parents=True, exist_ok=False) link = build / "profile" # Use relative symlink so the build dir can be moved with the repo. import os rel = Path(os.path.relpath(profile_src, build)) link.symlink_to(rel)