feat: Backup-Prüfung nennt die neueste vollständige Sicherung
Bei 35 Sicherungen hilft eine blosse Liste wenig. Das Skript zeigt jetzt je Sicherung Zeitpunkt, Schlagwörter, Budget-Vorlagen und wie viele Buchungen eine Kategorie tragen – und nennt am Ende die neueste noch vollständige samt der fertigen Befehle zum Zurückspielen. Tabellen, die es zum Sicherungszeitpunkt noch nicht gab, erscheinen als '–' statt als Fehler. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Regular → Executable
+71
-15
@@ -1,22 +1,78 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Listet je Backup, wie viele Schlagwörter/Budget-Vorlagen/kategorisierte
|
||||
Buchungen darin stecken. So sieht man, welches Backup noch heil ist."""
|
||||
import glob, os, sqlite3, sys
|
||||
"""Prüft die Datenbank-Sicherungen auf Vollständigkeit.
|
||||
|
||||
muster = sys.argv[1] if len(sys.argv) > 1 else "/var/lib/certain-finance/backups/*.db"
|
||||
print(f"{'Datei':<34}{'Schlagw.':>9}{'Budget':>8}{'Buch.m.Kat':>12}")
|
||||
for f in sorted(glob.glob(muster)):
|
||||
Listet je Sicherung, wie viele Schlagwörter, Budget-Vorlagen und kategorisierte
|
||||
Buchungen darin stecken, und nennt am Ende die NEUESTE noch vollständige. So
|
||||
muss man nach einem Datenverlust nicht nach Zeitstempel raten.
|
||||
|
||||
Aufruf: pruefe_backups.py [muster]
|
||||
"""
|
||||
import glob
|
||||
import os
|
||||
import sqlite3
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
MUSTER = sys.argv[1] if len(sys.argv) > 1 else "/var/lib/certain-finance/backups/*.db"
|
||||
|
||||
|
||||
def zaehle(pfad: str) -> dict | None:
|
||||
"""Kennzahlen einer Sicherung. None, wenn die Datei unlesbar ist."""
|
||||
try:
|
||||
con = sqlite3.connect(f"file:{f}?mode=ro", uri=True)
|
||||
def z(sql):
|
||||
con = sqlite3.connect(f"file:{pfad}?mode=ro", uri=True)
|
||||
except sqlite3.Error:
|
||||
return None
|
||||
def z(sql: str):
|
||||
try:
|
||||
return con.execute(sql).fetchone()[0]
|
||||
except sqlite3.Error:
|
||||
return "-"
|
||||
print(f"{os.path.basename(f):<34}"
|
||||
f"{z('SELECT COUNT(*) FROM categorization_rules'):>9}"
|
||||
f"{z('SELECT COUNT(*) FROM budget_template_lines'):>8}"
|
||||
f"{z('SELECT COUNT(*) FROM transactions WHERE category_id IS NOT NULL'):>12}")
|
||||
return None # Tabelle gab es zu dem Zeitpunkt noch nicht
|
||||
werte = {
|
||||
"schlagwoerter": z("SELECT COUNT(*) FROM categorization_rules"),
|
||||
"budget": z("SELECT COUNT(*) FROM budget_template_lines"),
|
||||
"kategorisiert": z("SELECT COUNT(*) FROM transactions WHERE category_id IS NOT NULL"),
|
||||
"buchungen": z("SELECT COUNT(*) FROM transactions"),
|
||||
}
|
||||
con.close()
|
||||
except Exception as e:
|
||||
print(f"{os.path.basename(f):<34} Fehler: {e}")
|
||||
return werte
|
||||
|
||||
|
||||
def zahl(v) -> str:
|
||||
return "–" if v is None else str(v)
|
||||
|
||||
|
||||
dateien = sorted(glob.glob(MUSTER), key=os.path.getmtime)
|
||||
if not dateien:
|
||||
print(f"Keine Sicherungen gefunden unter: {MUSTER}")
|
||||
raise SystemExit(1)
|
||||
|
||||
print(f"{'Sicherung':<32}{'Zeitpunkt':<18}{'Schlagw.':>9}{'Budget':>8}{'Buch.':>7}{'davon m. Kat.':>15}")
|
||||
print("-" * 91)
|
||||
neueste_heil = None
|
||||
for f in dateien:
|
||||
w = zaehle(f)
|
||||
zeit = datetime.fromtimestamp(os.path.getmtime(f)).strftime("%d.%m. %H:%M")
|
||||
if w is None:
|
||||
print(f"{os.path.basename(f):<32}{zeit:<18} nicht lesbar")
|
||||
continue
|
||||
print(f"{os.path.basename(f):<32}{zeit:<18}{zahl(w['schlagwoerter']):>9}"
|
||||
f"{zahl(w['budget']):>8}{zahl(w['buchungen']):>7}{zahl(w['kategorisiert']):>15}")
|
||||
if (w["schlagwoerter"] or 0) > 0:
|
||||
neueste_heil = (f, w, zeit)
|
||||
|
||||
print()
|
||||
if neueste_heil:
|
||||
f, w, zeit = neueste_heil
|
||||
print(f"NEUESTE Sicherung mit Schlagwörtern: {os.path.basename(f)} ({zeit})")
|
||||
print(f" {w['schlagwoerter']} Schlagwörter, {zahl(w['budget'])} Budget-Vorlagen, "
|
||||
f"{zahl(w['kategorisiert'])} von {zahl(w['buchungen'])} Buchungen kategorisiert")
|
||||
print()
|
||||
print("Zurückspielen (Dienst stoppen, sichern, ersetzen, starten):")
|
||||
print(" sudo systemctl stop certain-finance")
|
||||
print(" sudo cp /var/lib/certain-finance/app.db /var/lib/certain-finance/app.db.kaputt")
|
||||
print(f" sudo cp {f} /var/lib/certain-finance/app.db")
|
||||
print(" sudo systemctl start certain-finance")
|
||||
else:
|
||||
print("Keine Sicherung enthält Schlagwörter.")
|
||||
print("Dann waren zum Sicherungszeitpunkt noch keine angelegt – die Zuordnung")
|
||||
print("lässt sich stattdessen nachträglich über die Schlagwörter neu erzeugen.")
|
||||
|
||||
Reference in New Issue
Block a user