"""Carga de games.toml → objetos Game con valores derivados.""" from __future__ import annotations import tomllib from dataclasses import dataclass, field from pathlib import Path from urllib.parse import urlparse DEFAULT_VERSION_CMD = "git describe --tags --always" DEFAULT_ICON_REL = "release/icons/icon.png" @dataclass class Game: id: str name: str clone_url: str run_cmd: str build_cmd: str = "" version_cmd: str = DEFAULT_VERSION_CMD info_url: str = "" icon_rel: str = DEFAULT_ICON_REL def __post_init__(self) -> None: if not self.info_url: self.info_url = derive_info_url(self.clone_url) @dataclass class Config: data_dir: str = "jlauncher_data" games: list[Game] = field(default_factory=list) def derive_info_url(clone_url: str) -> str: """De una URL de clone Gitea deriva la URL de la API REST del repo. https://host/org/repo.git -> https://host/api/v1/repos/org/repo """ parsed = urlparse(clone_url) path = parsed.path.strip("/") if path.endswith(".git"): path = path[: -len(".git")] parts = [p for p in path.split("/") if p] if len(parts) < 2 or not parsed.scheme or not parsed.netloc: return "" owner, repo = parts[-2], parts[-1] return f"{parsed.scheme}://{parsed.netloc}/api/v1/repos/{owner}/{repo}" def load_config(path: Path) -> Config: with open(path, "rb") as fh: raw = tomllib.load(fh) games: list[Game] = [] for entry in raw.get("game", []): missing = [k for k in ("id", "name", "clone_url", "run_cmd") if not entry.get(k)] if missing: raise ValueError( f"Juego con campos obligatorios faltantes {missing}: {entry!r}" ) games.append( Game( id=entry["id"], name=entry["name"], clone_url=entry["clone_url"], run_cmd=entry["run_cmd"], build_cmd=entry.get("build_cmd", ""), version_cmd=entry.get("version_cmd") or DEFAULT_VERSION_CMD, info_url=entry.get("info_url", ""), icon_rel=entry.get("icon_rel") or DEFAULT_ICON_REL, ) ) if not games: raise ValueError("games.toml no define ningún [[game]]") return Config(data_dir=raw.get("data_dir", "jlauncher_data"), games=games)