#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import gzip import subprocess from pathlib import Path # ============================================================ # CESTY K BINÁRKÁM (PORTABLE) # ============================================================ PROJECT_ROOT = Path(__file__).resolve().parents[1] MYSQL = PROJECT_ROOT / "bin" / "mysql.exe" # ============================================================ # 🔧 KONFIGURACE – UPRAV SI JEN TADY # ============================================================ DUMP_FILE = Path( r"U:\MySQLBackup\Kanboard\kanboard_kanboard_2026-01-28_09-53-50.sql.gz" ) # ============================================================ def load_dotenv(dotenv_path: Path) -> None: if not dotenv_path.exists(): return for line in dotenv_path.read_text(encoding="utf-8").splitlines(): line = line.strip() if not line or line.startswith("#") or "=" not in line: continue k, v = line.split("=", 1) os.environ.setdefault(k.strip(), v.strip().strip('"').strip("'")) def require_env(name: str) -> str: v = os.getenv(name) if not v: raise SystemExit(f"Chybí proměnná {name} (dej ji do .env nebo env).") return v def extract_db_name_from_dump(dump_file: Path) -> str: """ Najde první 'CREATE DATABASE `xxx`' v dumpu """ with gzip.open(dump_file, "rb") as f: for raw in f: line = raw.decode("utf-8", errors="ignore").strip() if line.upper().startswith("CREATE DATABASE"): return line.split("`")[1] raise SystemExit("Nepodařilo se zjistit jméno DB z dumpu.") def database_exists(cnf_path: Path, db_name: str) -> bool: """ Ověří existenci DB v MySQL """ cmd = [ str(MYSQL), f"--defaults-extra-file={cnf_path}", "-N", "-B", "-e", f"SHOW DATABASES LIKE '{db_name}';", ] p = subprocess.run(cmd, capture_output=True, text=True) return db_name in (p.stdout or "") def main() -> None: if not DUMP_FILE.exists(): raise SystemExit(f"Dump neexistuje: {DUMP_FILE}") if not DUMP_FILE.name.endswith(".sql.gz"): raise SystemExit("Dump musí končit na .sql.gz") here = Path(__file__).resolve().parent load_dotenv(here / ".env") host = require_env("KB_MYSQL_HOST") port = require_env("KB_MYSQL_PORT") user = require_env("KB_MYSQL_USER") password = require_env("KB_MYSQL_PASSWORD") # dočasný mysql client config (bez hesla v CLI) cnf_path = here / ".mysql_restore.cnf" cnf_path.write_text( "[client]\n" f"host={host}\n" f"port={port}\n" f"user={user}\n" f"password={password}\n", encoding="utf-8" ) tmp_sql = DUMP_FILE.with_suffix(".restore.tmp.sql") try: try: os.chmod(cnf_path, 0o600) except Exception: pass # 🔎 zjistíme jméno DB z dumpu db_name = extract_db_name_from_dump(DUMP_FILE) print(f"[INFO] Dump obsahuje databázi: {db_name}") # 🛑 POJISTKA – DB už existuje if database_exists(cnf_path, db_name): raise SystemExit( f"❌ STOP: Databáze '{db_name}' už v MySQL existuje.\n" f" Musíš ji NEJDŘÍVE ručně smazat (DROP DATABASE {db_name};)\n" f" a teprve pak znovu spustit restore." ) print("[OK] Databáze v MySQL neexistuje → pokračuji v obnově") # ==================================================== # 1) ROZBALENÍ DUMPU DO DOČASNÉHO SQL # ==================================================== print("[INFO] Rozbaluji dump do dočasného SQL souboru") with gzip.open(DUMP_FILE, "rb") as f_in, open(tmp_sql, "wb") as f_out: f_out.write(f_in.read()) # ==================================================== # 2) RESTORE Z ČISTÉHO SQL # ==================================================== mysql_cmd = [ str(MYSQL), f"--defaults-extra-file={cnf_path}", "--binary-mode=1", ] print("[OK] Spouštím restore z dočasného SQL") with open(tmp_sql, "rb") as f_sql: p = subprocess.run(mysql_cmd, stdin=f_sql) if p.returncode != 0: raise SystemExit(f"mysql import selhal (exit={p.returncode})") print(f"[OK] Obnova databáze '{db_name}' dokončena.") finally: tmp_sql.unlink(missing_ok=True) cnf_path.unlink(missing_ok=True) if __name__ == "__main__": main()