114 lines
3.2 KiB
Python
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())
|