from dataclasses import dataclass from pathlib import Path @dataclass(frozen=True) class Layout: """All filesystem paths used by the builder.""" repo: Path build: Path @property def recipes_dir(self) -> Path: return self.repo / "recipes" @property def host_recipes_dir(self) -> Path: return self.repo / "host-recipes" @property def profiles_dir(self) -> Path: return self.repo / "profiles" @property def dockerfile(self) -> Path: return self.repo / "Dockerfile" @property def cache_dir(self) -> Path: return self.repo / "cache" @property def tarball_cache(self) -> Path: return self.cache_dir / "tarballs" @property def git_cache(self) -> Path: return self.cache_dir / "git" @property def cache_lock(self) -> Path: return self.cache_dir / ".lock" @property def sources_dir(self) -> Path: return self.repo / "sources" def source_tree(self, name: str, version: str) -> Path: return self.sources_dir / f"{name}-{version}" @property def profile_link(self) -> Path: return self.build / "profile" @property def build_workdirs(self) -> Path: return self.build / "builds" def build_workdir(self, name: str) -> Path: return self.build_workdirs / name @property def host_pkgs_dir(self) -> Path: return self.build / "host-pkgs" def host_pkg_dir(self, name: str) -> Path: return self.host_pkgs_dir / name def host_pkg_marker(self, name: str, version: str, revision: int) -> Path: return self.host_pkg_dir(name) / f".built-{version}-r{revision}" @property def pkgs_dir(self) -> Path: return self.build / "pkgs" def apk_path(self, output: str, version: str, revision: int) -> Path: return self.pkgs_dir / f"{output}-{version}-r{revision}.apk" @property def apkindex(self) -> Path: return self.pkgs_dir / "Packages.adb" @property def image_hash_file(self) -> Path: return self.build / ".image-hash" def ensure(self) -> None: for p in ( self.cache_dir, self.tarball_cache, self.git_cache, self.sources_dir, self.build_workdirs, self.host_pkgs_dir, self.pkgs_dir, ): p.mkdir(parents=True, exist_ok=True) def find_repo_root(start: Path) -> Path: cur = start.resolve() for p in (cur, *cur.parents): if (p / "Dockerfile").is_file() and (p / "profiles").is_dir(): return p raise FileNotFoundError( f"Could not find Orchid repo root (looking for Dockerfile + profiles/) from {start}" )