z230
This commit is contained in:
152
10 Backup/20 KanBoardDestroyAndRestore.py
Normal file
152
10 Backup/20 KanBoardDestroyAndRestore.py
Normal file
@@ -0,0 +1,152 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user