notebook vb
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
import subprocess
|
||||
import os
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
import zipfile
|
||||
import time
|
||||
import traceback
|
||||
|
||||
from EmailMessagingGraph import send_mail
|
||||
|
||||
# ============================================================
|
||||
# CONFIG
|
||||
# ============================================================
|
||||
|
||||
GBAK = r"C:\Program Files\Firebird\Firebird_2_5_CGM\bin\gbak.exe"
|
||||
FB_USER = "SYSDBA"
|
||||
FB_PASS = "masterkey"
|
||||
FB_PORT = "3050"
|
||||
|
||||
MAIN_DB = r"localhost/3050:C:\medicus 3\data\MEDICUS.FDB"
|
||||
EXT_DIR = Path(r"U:\externi")
|
||||
BACKUP_DIR = Path(r"U:\medicusbackup")
|
||||
|
||||
MAIL_TO = "vladimir.buzalka@buzalka.cz"
|
||||
|
||||
CHUNK = 8 * 1024 * 1024 # 8 MB
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HELPERS
|
||||
# ============================================================
|
||||
|
||||
def gbak_and_zip(label: str, db_conn: str, fbk: Path, zipf: Path, log: Path) -> dict:
|
||||
"""
|
||||
Run gbak backup and ZIP the result.
|
||||
Returns a result dict.
|
||||
"""
|
||||
result = {
|
||||
"label": label,
|
||||
"ok": False,
|
||||
"fbk_size": 0,
|
||||
"zip_size": 0,
|
||||
"t_gbak": 0,
|
||||
"t_zip": 0,
|
||||
"error": None,
|
||||
}
|
||||
|
||||
# 1) GBAK
|
||||
print(f"GBAK: {label} ... ", end="", flush=True)
|
||||
t0 = time.time()
|
||||
cmd = [GBAK, "-b", "-user", FB_USER, "-pas", FB_PASS, db_conn, str(fbk), "-v"]
|
||||
with open(log, "w", encoding="utf-8") as f:
|
||||
subprocess.run(cmd, stdout=f, stderr=subprocess.STDOUT, check=True)
|
||||
result["t_gbak"] = time.time() - t0
|
||||
result["fbk_size"] = fbk.stat().st_size
|
||||
print(f"OK ({result['t_gbak']:.0f}s, {result['fbk_size']/1024/1024:.1f} MB)")
|
||||
|
||||
# 2) ZIP
|
||||
t1 = time.time()
|
||||
processed = 0
|
||||
fbk_size = result["fbk_size"]
|
||||
with zipfile.ZipFile(zipf, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as zf:
|
||||
zi = zipfile.ZipInfo(fbk.name)
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
with zf.open(zi, "w", force_zip64=True) as z:
|
||||
with open(fbk, "rb") as src:
|
||||
while buf := src.read(CHUNK):
|
||||
z.write(buf)
|
||||
processed += len(buf)
|
||||
pct = processed * 100 / fbk_size
|
||||
print(f"\r ZIP {label}: {pct:6.2f}%", end="", flush=True)
|
||||
print()
|
||||
result["t_zip"] = time.time() - t1
|
||||
result["zip_size"] = zipf.stat().st_size
|
||||
|
||||
# 3) Delete FBK + LOG
|
||||
fbk.unlink()
|
||||
log.unlink()
|
||||
|
||||
result["ok"] = True
|
||||
return result
|
||||
|
||||
|
||||
def format_result(r: dict) -> str:
|
||||
ratio = 100 * (1 - r["zip_size"] / r["fbk_size"]) if r["fbk_size"] else 0
|
||||
return (
|
||||
f" {r['label']}: "
|
||||
f"FBK {r['fbk_size']/1024/1024:.1f} MB → "
|
||||
f"ZIP {r['zip_size']/1024/1024:.1f} MB "
|
||||
f"({ratio:.0f}% komprese, "
|
||||
f"gbak {r['t_gbak']:.0f}s, zip {r['t_zip']:.0f}s)"
|
||||
)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# MAIN
|
||||
# ============================================================
|
||||
|
||||
def main():
|
||||
BACKUP_DIR.mkdir(parents=True, exist_ok=True)
|
||||
now = datetime.now()
|
||||
ts = now.strftime("%Y-%m-%d_%H-%M-%S")
|
||||
|
||||
backed_up = []
|
||||
errors = []
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 1) Hlavní DB – MEDICUS.FDB
|
||||
# ----------------------------------------------------------
|
||||
fbk = BACKUP_DIR / f"MEDICUS_{ts}.fbk"
|
||||
zipf = BACKUP_DIR / f"MEDICUS_{ts}.zip"
|
||||
log = BACKUP_DIR / f"MEDICUS_{ts}.log"
|
||||
try:
|
||||
r = gbak_and_zip("MEDICUS", MAIN_DB, fbk, zipf, log)
|
||||
backed_up.append(r)
|
||||
except Exception:
|
||||
errors.append({"label": "MEDICUS", "error": traceback.format_exc()})
|
||||
for f in (fbk, log):
|
||||
if f.exists():
|
||||
f.unlink()
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 2) Externí DB – MEDICUS_FILES_*.fdb
|
||||
# ----------------------------------------------------------
|
||||
fdb_all = sorted(
|
||||
set(EXT_DIR.glob("MEDICUS_FILES_*.fdb")) | set(EXT_DIR.glob("MEDICUS_FILES_*.FDB")),
|
||||
key=lambda p: p.name.lower(),
|
||||
)
|
||||
|
||||
for fdb in fdb_all:
|
||||
name = fdb.stem
|
||||
fbk = BACKUP_DIR / f"{name}_{ts}.fbk"
|
||||
zipf = BACKUP_DIR / f"{name}_{ts}.zip"
|
||||
log = BACKUP_DIR / f"{name}_{ts}.log"
|
||||
db_conn = f"localhost/{FB_PORT}:{fdb}"
|
||||
try:
|
||||
r = gbak_and_zip(name, db_conn, fbk, zipf, log)
|
||||
backed_up.append(r)
|
||||
except Exception:
|
||||
errors.append({"label": name, "error": traceback.format_exc()})
|
||||
for f in (fbk, log):
|
||||
if f.exists():
|
||||
f.unlink()
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Report
|
||||
# ----------------------------------------------------------
|
||||
total = 1 + len(fdb_all)
|
||||
report = [
|
||||
f"Backup Medicus – {now.strftime('%d.%m.%Y %H:%M')}",
|
||||
f"Celkem DB: {total} | OK: {len(backed_up)} | Chyby: {len(errors)}",
|
||||
f"Výstupní adresář: {BACKUP_DIR}",
|
||||
"",
|
||||
]
|
||||
|
||||
if backed_up:
|
||||
report.append("--- Zálohováno ---")
|
||||
total_zip = sum(r["zip_size"] for r in backed_up)
|
||||
for r in backed_up:
|
||||
report.append(format_result(r))
|
||||
report.append(f" Celková velikost ZIP: {total_zip/1024/1024:.1f} MB")
|
||||
report.append("")
|
||||
|
||||
if errors:
|
||||
report.append("--- CHYBY ---")
|
||||
for e in errors:
|
||||
report.append(f" {e['label']}:\n{e['error']}")
|
||||
report.append("")
|
||||
|
||||
has_errors = bool(errors)
|
||||
subject = (
|
||||
f"{'X' if has_errors else 'OK'} MEDICUS backup "
|
||||
f"{len(backed_up)}/{total}"
|
||||
+ (f" – {len(errors)} chyb" if has_errors else "")
|
||||
)
|
||||
|
||||
send_mail(MAIL_TO, subject, "\n".join(report))
|
||||
print("\n" + "\n".join(report))
|
||||
|
||||
if errors:
|
||||
raise RuntimeError(f"{len(errors)} backup(s) failed")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user