62 lines
2.9 KiB
Python
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()
|