#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import gzip import subprocess from datetime import datetime from pathlib import Path # ============================================================ # CESTY K BINÁRKÁM (PORTABLE) # ============================================================ PROJECT_ROOT = Path(__file__).resolve().parents[1] MYSQL = PROJECT_ROOT / "bin" / "mysql.exe" MYSQLDUMP = PROJECT_ROOT / "bin" / "mysqldump.exe" # ============================================================ # KONFIGURACE # ============================================================ BACKUP_ROOT = Path(r"U:\mysqlbackup") # ============================================================ 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 get_mysql_cnf(here: Path) -> Path: cnf = here / ".mysql_backup.cnf" cnf.write_text( "[client]\n" f"host={require_env('KB_MYSQL_HOST')}\n" f"port={require_env('KB_MYSQL_PORT')}\n" f"user={require_env('KB_MYSQL_USER')}\n" f"password={require_env('KB_MYSQL_PASSWORD')}\n", encoding="utf-8" ) try: os.chmod(cnf, 0o600) except Exception: pass return cnf def list_databases(cnf_path: Path) -> list[str]: cmd = [ str(MYSQL), f"--defaults-extra-file={cnf_path}", "-N", "-B", "-e", "SHOW DATABASES;", ] p = subprocess.run(cmd, capture_output=True, text=True) if p.returncode != 0: raise SystemExit("Nelze vylistovat databáze.") return [ db.strip() for db in p.stdout.splitlines() if db and db not in ("information_schema", "mysql", "performance_schema", "sys") ] def choose_database(dbs: list[str]) -> str: print("\nDOSTUPNÉ DATABÁZE:\n") for i, db in enumerate(dbs, start=1): print(f" {i:2d}) {db}") print() while True: choice = input("Vyber číslo databáze k záloze: ").strip() if not choice.isdigit(): continue idx = int(choice) if 1 <= idx <= len(dbs): return dbs[idx - 1] def main() -> None: here = Path(__file__).resolve().parent load_dotenv(here / ".env") cnf_path = get_mysql_cnf(here) try: dbs = list_databases(cnf_path) if not dbs: raise SystemExit("Nenalezena žádná databáze k záloze.") db_name = choose_database(dbs) print(f"\n[OK] Vybraná databáze: {db_name}") # cílový adresář target_dir = BACKUP_ROOT / db_name target_dir.mkdir(parents=True, exist_ok=True) ts = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") dump_path = target_dir / f"{db_name}_{ts}.sql.gz" dump_cmd = [ str(MYSQLDUMP), f"--defaults-extra-file={cnf_path}", "--single-transaction", "--routines", "--triggers", "--events", "--hex-blob", "--default-character-set=utf8mb4", "--set-gtid-purged=OFF", db_name, ] print(f"[OK] Spouštím backup → {dump_path}") with subprocess.Popen(dump_cmd, stdout=subprocess.PIPE) as proc: with gzip.open(dump_path, "wb", compresslevel=6) as gz: gz.write(proc.stdout.read()) rc = proc.wait() if rc != 0: raise SystemExit(f"mysqldump selhal (exit={rc})") size_mb = dump_path.stat().st_size / 1024 / 1024 print(f"[OK] Hotovo ({size_mb:.2f} MB)") finally: cnf_path.unlink(missing_ok=True) if __name__ == "__main__": main()