Files
mysqlbackup/10 Backup/20 KanBoardDestroyAndRestore.py
2026-01-28 15:20:25 +01:00

153 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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()