Files
dj/model-bridge/backup_upgrade.py

62 lines
2.9 KiB
Python

"""Create a complete upgrade rollback copy without touching live project data."""
from datetime import datetime
import hashlib
import json
import os
from pathlib import Path
import shutil
import sqlite3
import subprocess
ROOT = Path(__file__).resolve().parent.parent
DEST = ROOT / "integration-work/backups" / ("upgrade-" + datetime.now().strftime("%Y%m%d-%H%M%S"))
def main():
DEST.mkdir(parents=True, exist_ok=False)
subprocess.run(["icacls", str(DEST), "/inheritance:r", "/grant:r", os.environ["USERNAME"] + ":(OI)(CI)(F)", "SYSTEM:(OI)(CI)(F)"], check=True, capture_output=True)
data_dest = DEST / "huobao-data"
data_dest.mkdir()
database = ROOT / "huobao-data/huobao.sqlite3"
with sqlite3.connect(database.as_uri() + "?mode=ro", uri=True) as source, sqlite3.connect(data_dest / "huobao.sqlite3") as snapshot:
source.backup(snapshot)
assert snapshot.execute("PRAGMA integrity_check").fetchone()[0] == "ok"
counts = {name: snapshot.execute('SELECT count(*) FROM "' + name + '"').fetchone()[0]
for (name,) in snapshot.execute("SELECT name FROM sqlite_master WHERE type='table'")}
for item in (ROOT / "huobao-data").iterdir():
if item.name.startswith("huobao.sqlite3") or item.name == "backups":
continue
target = data_dest / item.name
if item.is_dir():
shutil.copytree(item, target)
else:
shutil.copy2(item, target)
shutil.copytree(ROOT / "HuobaoDrama", DEST / "HuobaoDrama")
shutil.copytree(ROOT / "model-bridge", DEST / "model-bridge", ignore=shutil.ignore_patterns("__pycache__", "*.log"))
shutil.copy2(ROOT / "一键启动火宝.cmd", DEST / "一键启动火宝.cmd")
profile = Path(os.environ["APPDATA"]) / "HuobaoDrama"
for name in ("storage-config.json", "Preferences", "Local State", "workspace"):
source = profile / name
if not source.exists():
continue
target = DEST / "profile" / name
target.parent.mkdir(parents=True, exist_ok=True)
if source.is_dir():
shutil.copytree(source, target)
else:
shutil.copy2(source, target)
files = []
for file in data_dest.rglob("*"):
if file.is_file():
files.append({"path": file.relative_to(data_dest).as_posix(), "bytes": file.stat().st_size,
"sha256": hashlib.file_digest(file.open("rb"), "sha256").hexdigest()})
manifest = {"path": str(DEST), "counts": counts, "data_files": files}
(DEST / "manifest.json").write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding="utf-8")
(ROOT / "integration-work/current-upgrade-backup.txt").write_text(str(DEST), encoding="utf-8")
print("Complete rollback backup:", DEST)
print("Data files:", len(files), "model configs:", counts["ai_service_configs"], "projects:", counts["dramas"], "styles:", counts["style_presets"])
if __name__ == "__main__":
main()