"""GameUpdate patch-config defaults from the tool's .env / Config tab. Translators set forge/host/org once in Config. When Step 1 copies ``gameupdate/`` into a game root, we write ``gameupdate/patch-config.txt`` from those defaults (repo stays per-game). """ from __future__ import annotations import os from pathlib import Path from dotenv import dotenv_values # .env keys (Config tab) ENV_FORGE = "gameUpdateForge" ENV_HOST = "gameUpdateHost" ENV_USERNAME = "gameUpdateUsername" ENV_BRANCH = "gameUpdateBranch" DEFAULT_FORGE = "gitlab" DEFAULT_HOST = "gitgud.io" DEFAULT_BRANCH = "main" _FORGE_HOST_DEFAULTS = { "gitlab": "gitgud.io", "github": "github.com", "forgejo": "codeberg.org", } def normalize_forge(raw: str | None) -> str: value = (raw or "").strip().lower() if value in ("", "gitlab", "gl", "gitgud"): return "gitlab" if value in ("github", "gh"): return "github" if value in ("forgejo", "gitea", "fj", "codeberg"): return "forgejo" return "gitlab" def default_host_for_forge(forge: str) -> str: return _FORGE_HOST_DEFAULTS.get(normalize_forge(forge), DEFAULT_HOST) def load_gameupdate_defaults(env_path: str | Path | None = None) -> dict[str, str]: """Return forge/host/username/branch from .env (with process env fallback).""" path = Path(env_path) if env_path is not None else Path(".env") file_vals = dotenv_values(path) if path.is_file() else {} def _get(key: str, default: str = "") -> str: raw = file_vals.get(key) if raw is None or str(raw).strip() == "": raw = os.getenv(key, default) return str(raw or default).strip() forge = normalize_forge(_get(ENV_FORGE, DEFAULT_FORGE)) host = _get(ENV_HOST, "") or default_host_for_forge(forge) host = host.replace("https://", "").replace("http://", "").split("/")[0].strip() return { "forge": forge, "host": host or default_host_for_forge(forge), "username": _get(ENV_USERNAME, ""), "branch": _get(ENV_BRANCH, DEFAULT_BRANCH) or DEFAULT_BRANCH, } def format_patch_config( *, forge: str, host: str, username: str, repo: str = "YOUR_PATCH_REPO", branch: str = DEFAULT_BRANCH, ) -> str: """Render a patch-config.txt body.""" forge = normalize_forge(forge) host = (host or default_host_for_forge(forge)).strip() username = (username or "").strip() or "YOUR_ORG_OR_USER" repo = (repo or "").strip() or "YOUR_PATCH_REPO" branch = (branch or "").strip() or DEFAULT_BRANCH lines = [ "# Generated by DazedMTLTool from Config → Game Update defaults.", "# Edit repo= per game. forge/host/username usually stay the same.", f"forge={forge}", f"host={host}", f"username={username}", f"repo={repo}", f"branch={branch}", "", ] return "\n".join(lines) def write_patch_config( game_root: str | Path, *, repo: str | None = None, env_path: str | Path | None = None, overwrite: bool = True, ) -> tuple[bool, str]: """Write ``/gameupdate/patch-config.txt`` from Config defaults. Returns ``(ok, message)``. """ root = Path(game_root) dest_dir = root / "gameupdate" dest = dest_dir / "patch-config.txt" if dest.is_file() and not overwrite: return False, f"left existing {dest}" defaults = load_gameupdate_defaults(env_path) if not defaults["username"]: return False, ( "skipped patch-config.txt (set Game Update org/username in Config first)" ) body = format_patch_config( forge=defaults["forge"], host=defaults["host"], username=defaults["username"], repo=repo or "YOUR_PATCH_REPO", branch=defaults["branch"], ) try: dest_dir.mkdir(parents=True, exist_ok=True) dest.write_text(body, encoding="utf-8") except Exception as exc: return False, f"could not write {dest}: {exc}" return True, str(dest)