"""Filesystem path helpers for source-checkout and container runtimes.""" from __future__ import annotations import os from functools import lru_cache from pathlib import Path @lru_cache(maxsize=1) def repo_root() -> Path: """Return the Vignette repository root. The API is run both from a source checkout and from Docker, where the code lives under /app/apps/api. Keep that layout knowledge here instead of repeating fragile ``Path(__file__).parents[...]`` offsets across modules. """ override = os.getenv("VIGNETTE_REPO_ROOT", "").strip() if override: return Path(override).expanduser().resolve() current = Path(__file__).resolve() for candidate in current.parents: if ( (candidate / "apps" / "api" / "app").is_dir() and (candidate / "data").exists() ): return candidate for candidate in current.parents: if ( (candidate / "apps" / "api").is_dir() and (candidate / "README.md").exists() ): return candidate raise RuntimeError("Vignette repository root not found; set VIGNETTE_REPO_ROOT") def repo_path(*parts: str) -> Path: """Build an absolute path under the repository root.""" return repo_root().joinpath(*parts)