"""Artifact and build-output paths. Stored paths are relative to `Config.data_dir` so the database stays valid when the data directory moves (a deployment copy, a docker volume, a restored backup). Rows written by older builds hold absolute paths; readers accept both rather than needing a migration. """ from __future__ import annotations from pathlib import Path APK_NAME = "dsh-sync.apk" APK_META_NAME = "dsh-sync.json" def dist_dir(cfg) -> Path: return cfg.data_dir / "dist" def artifact_relpath(plugin_id: str, version: str) -> str: """Value stored in plugin_versions.artifact_path.""" return f"{plugin_id}/{version}.tar.gz" def artifact_path(cfg, stored: str) -> Path: """Resolve a stored artifact path to an absolute path on this machine.""" p = Path(stored) if p.is_absolute(): return p root = cfg.plugins_dir.resolve() resolved = (root / p).resolve() # Path comes from our own DB, but never let a bad row escape the plugins dir. if not resolved.is_relative_to(root): raise ValueError(f"artifact path escapes plugins dir: {stored!r}") return resolved def apk_path(cfg) -> Path: return dist_dir(cfg) / APK_NAME def apk_meta_path(cfg) -> Path: return dist_dir(cfg) / APK_META_NAME