99 lines
3.2 KiB
Python
99 lines
3.2 KiB
Python
"""
|
|
Utility: Check whether specific drawers actually finished exporting.
|
|
|
|
Interactive — prompts for one or more drawer IDs, then for each drawer compares
|
|
its manifest (the documents FCCS said it would export, captured during Step 2)
|
|
against the files actually sitting in the export folder, and reports any
|
|
missing documents.
|
|
|
|
Handles two quirks of the FCCS export (see fccs_config.evaluate_drawer):
|
|
|
|
1. Page-splitting: a single manifest document (e.g. "Donations") is exported
|
|
as one file if it's a single page, or as "Donations Page 1",
|
|
"Donations Page 2", ... for a multi-page document. All of those count as
|
|
that one document being present.
|
|
|
|
2. Filename sanitization: FCCS strips characters that are illegal in Windows
|
|
filenames (: / \\ ? * " < > |) from document titles, so comparison is done
|
|
on a normalized key so these still match.
|
|
|
|
fccs_verify.py applies this same logic in batch across every drawer; this tool
|
|
is for spot-checking specific drawers (e.g. ones the log marked failed).
|
|
|
|
USAGE
|
|
-----
|
|
python fccs_check.py
|
|
Drawer ID(s): 08097 18430
|
|
"""
|
|
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
from fccs_config import (
|
|
parse_args, load_config, evaluate_drawer, index_files_by_drawer,
|
|
)
|
|
|
|
|
|
def report_drawer(drawer_id, files, manifest_dir, out):
|
|
"""Evaluate one drawer and print a human-readable completeness report."""
|
|
r = evaluate_drawer(drawer_id, files, manifest_dir)
|
|
|
|
out("")
|
|
if not r["has_manifest"]:
|
|
out(f"[{drawer_id}] NO MANIFEST at {r['manifest_path']} — cannot verify "
|
|
"(was this drawer exported by the tool?)")
|
|
return
|
|
|
|
expected = r["expected"]
|
|
missing = r["missing"]
|
|
out(f"[{drawer_id}] manifest lists {len(expected)} document(s); "
|
|
f"{r['file_count']} file(s) in export folder.")
|
|
if missing:
|
|
out(f" INCOMPLETE — {len(missing)} document(s) missing from export:")
|
|
for m in missing:
|
|
out(f" - {m}")
|
|
else:
|
|
out(f" COMPLETE — all {len(expected)} manifest document(s) present.")
|
|
if r["extras"]:
|
|
out(f" Note: {len(r['extras'])} exported document(s) not in the manifest:")
|
|
for e in r["extras"]:
|
|
out(f" - {e}")
|
|
if r["unparsed"]:
|
|
out(f" Note: {r['unparsed']} file(s) had no recognizable date anchor "
|
|
"and were skipped.")
|
|
|
|
|
|
def main():
|
|
args = parse_args()
|
|
cfg = load_config(args.config)
|
|
export_dir = cfg.get("paths", "export_dir")
|
|
manifest_dir = cfg.get("paths", "manifest_dir")
|
|
|
|
if not os.path.isdir(export_dir):
|
|
print(f"ERROR: export directory not found: {export_dir}")
|
|
sys.exit(1)
|
|
|
|
files_by_drawer = index_files_by_drawer(export_dir)
|
|
|
|
print("FCCS export completeness check")
|
|
print(f" export folder : {export_dir}")
|
|
print(f" manifests : {manifest_dir}")
|
|
print("Enter drawer ID(s) separated by spaces or commas (blank to quit).")
|
|
|
|
while True:
|
|
try:
|
|
raw = input("\nDrawer ID(s): ").strip()
|
|
except EOFError:
|
|
break
|
|
if not raw:
|
|
break
|
|
ids = [i for i in re.split(r"[\s,]+", raw) if i]
|
|
for drawer_id in ids:
|
|
report_drawer(drawer_id, files_by_drawer.get(drawer_id, []),
|
|
manifest_dir, print)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|