Curatare globala a comentariilor si docstring-urilor (app, tools, teste, scripturi): eliminate referintele la PRD-uri, US-xxx, task-uri istorice si review-uri; pastrata doar informatia functionala, formulata scurt. Regula adaugata in CLAUDE.md (sectiunea Stil). Fara modificari de cod sau comportament. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
80 lines
2.6 KiB
Python
80 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Backup online SQLite — copie consistenta a bazei pe volum persistent.
|
|
|
|
SQLite in WAL NU se copiaza sigur cu `cp` (WAL-ul poate avea tranzactii necheckpoint-ate).
|
|
Folosim API-ul `Connection.backup` (online, consistent, fara oprirea worker-ului).
|
|
|
|
Utilizare:
|
|
python -m tools.backup # -> <db_dir>/backups/autopass-YYYYMMDD-HHMMSS.db
|
|
python -m tools.backup --out /path/snap.db # destinatie explicita
|
|
python -m tools.backup --keep 14 # pastreaza ultimele 14, sterge restul
|
|
|
|
Recomandat: rulat dintr-un cron pe gazda (ex. zilnic), tinta pe volum/montaj separat.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import sqlite3
|
|
import sys
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
|
|
from app.config import get_settings
|
|
|
|
|
|
def backup_db(src: Path, dest: Path) -> Path:
|
|
"""Backup online (consistent) din `src` in `dest`. Intoarce `dest`."""
|
|
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
src_conn = sqlite3.connect(src)
|
|
try:
|
|
dst_conn = sqlite3.connect(dest)
|
|
try:
|
|
src_conn.backup(dst_conn)
|
|
finally:
|
|
dst_conn.close()
|
|
finally:
|
|
src_conn.close()
|
|
return dest
|
|
|
|
|
|
def prune(backup_dir: Path, keep: int) -> list[Path]:
|
|
"""Pastreaza cele mai noi `keep` snapshot-uri (dupa nume = timestamp), sterge restul."""
|
|
snaps = sorted(backup_dir.glob("autopass-*.db"), reverse=True)
|
|
removed = []
|
|
for old in snaps[keep:]:
|
|
old.unlink(missing_ok=True)
|
|
removed.append(old)
|
|
return removed
|
|
|
|
|
|
def main(argv: list[str] | None = None) -> int:
|
|
parser = argparse.ArgumentParser(description="Backup online SQLite gateway RAR AUTOPASS")
|
|
parser.add_argument("--out", type=Path, default=None, help="destinatie explicita (default: <db_dir>/backups/)")
|
|
parser.add_argument("--keep", type=int, default=0, help="pastreaza ultimele N snapshot-uri (0 = nu sterge)")
|
|
args = parser.parse_args(argv)
|
|
|
|
src = get_settings().db_path
|
|
if not src.exists():
|
|
print(f"eroare: baza {src} nu exista", file=sys.stderr)
|
|
return 1
|
|
|
|
if args.out is not None:
|
|
dest = args.out
|
|
else:
|
|
stamp = datetime.now(timezone.utc).strftime("%Y%m%d-%H%M%S")
|
|
dest = src.parent / "backups" / f"autopass-{stamp}.db"
|
|
|
|
backup_db(src, dest)
|
|
print(f"backup -> {dest} ({dest.stat().st_size} bytes)")
|
|
|
|
if args.keep > 0:
|
|
removed = prune(dest.parent, args.keep)
|
|
if removed:
|
|
print(f"sterse {len(removed)} snapshot-uri vechi (pastrez {args.keep})")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|