Files
gaokao-volunteer-system/scripts/backup_collect_order_artifacts.py
Hermes Agent 246f21c7f2
Some checks failed
CI / pytest (Python 3.10) (push) Has been cancelled
CI / pytest (Python 3.11) (push) Has been cancelled
CI / pytest (Python 3.12) (push) Has been cancelled
feat(review): land unified remediation and rules evidence closure
2026-06-18 10:21:38 +08:00

114 lines
3.2 KiB
Python

#!/usr/bin/env python3
from __future__ import annotations
import argparse
import json
import shutil
import sqlite3
import sys
from pathlib import Path
ARTIFACT_COLUMNS: tuple[tuple[str, str], ...] = (
("audit_report", "audit_report"),
("pdf_path", "pdf_path"),
)
def _safe_target_path(source: Path) -> Path:
if source.is_absolute():
return Path(*source.parts[1:])
return source
def collect_order_artifacts(orders_db: Path, output_dir: Path) -> dict[str, object]:
if not orders_db.is_file():
return {
"copied": 0,
"missing": 0,
"skipped": [{"reason": "orders_db_missing", "path": str(orders_db)}],
}
conn = sqlite3.connect(orders_db)
conn.row_factory = sqlite3.Row
copied = 0
missing = 0
skipped: list[dict[str, str]] = []
try:
try:
rows = conn.execute(
"SELECT id, audit_report, pdf_path FROM orders ORDER BY created_at, id"
)
except sqlite3.OperationalError as exc:
return {
"copied": 0,
"missing": 0,
"skipped": [
{
"reason": "orders_table_unavailable",
"path": str(orders_db),
"error": str(exc),
}
],
}
for row in rows:
order_id = str(row["id"])
for column_name, artifact_kind in ARTIFACT_COLUMNS:
raw_path = row[column_name]
if not raw_path:
continue
source = Path(str(raw_path))
if not source.is_file():
missing += 1
skipped.append(
{
"order_id": order_id,
"artifact": artifact_kind,
"path": str(source),
"reason": "missing_source",
}
)
continue
relative_target = (
Path(order_id) / artifact_kind / _safe_target_path(source)
)
target = output_dir / relative_target
target.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(source, target)
copied += 1
finally:
conn.close()
return {
"copied": copied,
"missing": missing,
"skipped": skipped,
}
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(
description="Collect order-linked delivery artifacts into a backup staging dir"
)
parser.add_argument("--orders-db", required=True, help="Path to orders.db")
parser.add_argument(
"--output-dir",
required=True,
help="Directory where copied artifacts should be stored",
)
args = parser.parse_args(argv)
result = collect_order_artifacts(
orders_db=Path(args.orders_db).resolve(),
output_dir=Path(args.output_dir).resolve(),
)
json.dump(result, sys.stdout, ensure_ascii=False)
sys.stdout.write("\n")
return 0
if __name__ == "__main__":
raise SystemExit(main())