import os from dataclasses import dataclass, field from pathlib import PurePosixPath from typing import Any from src.container import Container from src.recipe import Recipe @dataclass class RecipeContext: """The `self` value passed to recipe phase functions.""" recipe: Recipe profile: dict container: Container jobs: int _dest_output: str | None = None env: dict[str, str] = field(default_factory=dict) @property def name(self) -> str: return self.recipe.name @property def version(self) -> str: return self.recipe.version @property def revision(self) -> int: return self.recipe.revision @property def source_dir(self) -> PurePosixPath: srcs = self.recipe.sources if len(srcs) == 1: return PurePosixPath("/sources") raise RuntimeError(f"{self.name}: multiple sources; use self.sources") @property def sources(self) -> dict[str, PurePosixPath]: srcs = self.recipe.sources if len(srcs) == 1: raise RuntimeError(f"{self.name}: only one source; use self.source_dir") out: dict[str, PurePosixPath] = {} for k in srcs.keys(): if k is None: raise RuntimeError(f"{self.name}: multiple sources must be named") out[k] = PurePosixPath("/sources") / k return out @property def build_dir(self) -> PurePosixPath: return PurePosixPath("/build") @property def sysroot(self) -> PurePosixPath: return PurePosixPath("/sysroot") @property def dest_dir(self) -> PurePosixPath: if self._dest_output is None: raise RuntimeError("dest_dir only available during install/package phases") return PurePosixPath("/dest") / self._dest_output @property def files(self) -> PurePosixPath: if self.recipe.files_dir is None: raise RuntimeError(f"{self.name}: no files/ dir") return PurePosixPath("/files") @property def prefix(self) -> str: return f"/tools/{self.name}" if self.recipe.kind == "host" else "/usr" @property def triple(self) -> str: return self.profile["triple"] @property def arch(self) -> str: return self.profile["arch"] def run( self, *argv, env: dict[str, str] | None = None, cwd: str | os.PathLike | None = None, ) -> None: flat: list[str] = [] for a in argv: if isinstance(a, (PurePosixPath, os.PathLike)): flat.append(str(a)) elif isinstance(a, bool): raise TypeError("bool not allowed in run(); use str") elif isinstance(a, (str, int)): flat.append(str(a)) else: raise TypeError(f"unsupported arg type in run(): {type(a).__name__}") merged = dict(self.env) if env: merged.update(env) cwd_s = str(cwd) if cwd is not None else "/build" self.container.exec(flat, env=merged, cwd=cwd_s)