97 lines
3.5 KiB
Python
97 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Verify the file-tree census & extension census artifact against a fresh git recompute.
|
|
|
|
Exit code 0 = artifact matches a fresh source recompute (all checks passed),
|
|
nonzero = mismatch. Not a tautology: it re-enumerates the repo from git and
|
|
compares the produced tables field-for-field against the committed files.
|
|
"""
|
|
|
|
import csv
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from collections import Counter
|
|
|
|
REPO = "/root/troupe-standup"
|
|
DEST = os.path.join(REPO, "wizard-work", "ledger")
|
|
|
|
FILES = ["repo_tree.tsv", "repo_exts.tsv", "repo_files.tsv"]
|
|
|
|
|
|
def run(args):
|
|
return subprocess.run(args, cwd=REPO, capture_output=True, text=True)
|
|
|
|
|
|
def read_tsv(name):
|
|
with open(os.path.join(DEST, name), newline="", encoding="utf-8") as f:
|
|
return list(csv.reader(f, delimiter="\t"))
|
|
|
|
|
|
def main():
|
|
failures = 0
|
|
|
|
def check(name, cond, detail=""):
|
|
nonlocal failures
|
|
print(("%s %s" % ("PASS" if cond else "FAIL", name)) + ((" " + detail) if (detail and not cond) else ""))
|
|
if not cond:
|
|
failures += 1
|
|
|
|
# 1) fresh enumeration from git
|
|
tree = run(["git", "ls-tree", "-r", "--name-only", "HEAD"])
|
|
check("git ls-tree exit 0", tree.returncode == 0, tree.stderr.strip())
|
|
paths = [l for l in tree.stdout.splitlines() if l.strip()]
|
|
check("git ls-tree lists files", len(paths) > 0, "got %d" % len(paths))
|
|
|
|
dir_counts = Counter()
|
|
ext_counts = Counter()
|
|
for p in paths:
|
|
d = os.path.dirname(p)
|
|
dir_counts[d if d else "(root)"] += 1
|
|
ext = os.path.splitext(p)[1].lstrip(".").lower() or "(none)"
|
|
ext_counts[ext] += 1
|
|
|
|
# 2) repo_tree.tsv
|
|
rows = read_tsv("repo_tree.tsv")
|
|
check("repo_tree header", rows[0] == ["rank", "directory", "file_count"], str(rows[0]))
|
|
data = rows[1:]
|
|
expected_tree = sorted(dir_counts.items(), key=lambda kv: (-kv[1], kv[0]))
|
|
check("repo_tree rows == directory groups",
|
|
len(data) == len(expected_tree),
|
|
"got %d, expected %d" % (len(data), len(expected_tree)))
|
|
check("repo_tree dir/counts match recompute",
|
|
[(r[1], int(r[2])) for r in data] == [(d, c) for d, c in expected_tree])
|
|
|
|
# 3) repo_exts.tsv
|
|
rows = read_tsv("repo_exts.tsv")
|
|
check("repo_exts header", rows[0] == ["rank", "extension", "file_count"], str(rows[0]))
|
|
data = rows[1:]
|
|
expected_ext = sorted(ext_counts.items(), key=lambda kv: (-kv[1], kv[0]))
|
|
check("repo_exts rows == extension groups",
|
|
len(data) == len(expected_ext),
|
|
"got %d, expected %d" % (len(data), len(expected_ext)))
|
|
check("repo_exts ext/counts match recompute",
|
|
[(r[1], int(r[2])) for r in data] == [(d, c) for d, c in expected_ext])
|
|
|
|
# 4) repo_files.tsv
|
|
rows = read_tsv("repo_files.tsv")
|
|
check("repo_files header", rows[0] == ["rank", "path"], str(rows[0]))
|
|
file_paths = [r[1] for r in rows[1:]]
|
|
check("repo_files data rows == git ls-tree rows",
|
|
len(file_paths) == len(paths),
|
|
"got %d, git ls-tree %d" % (len(file_paths), len(paths)))
|
|
check("repo_files rows equal git ls-tree set",
|
|
sorted(file_paths) == sorted(paths))
|
|
|
|
# 5) group sums reconcile to total
|
|
check("dir sum == total", sum(dir_counts.values()) == len(paths),
|
|
"got %d, total %d" % (sum(dir_counts.values()), len(paths)))
|
|
check("ext sum == total", sum(ext_counts.values()) == len(paths),
|
|
"got %d, total %d" % (sum(ext_counts.values()), len(paths)))
|
|
|
|
print("result:", "PASS" if failures == 0 else "FAIL")
|
|
sys.exit(1 if failures else 0)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|