87 lines
2.3 KiB
Python
87 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Extract the tracked-directory census from the git tree at HEAD.
|
|
|
|
Source of truth: `git ls-files` at the checked-out revision (not a snapshot
|
|
file), so a clean clone reproduces this artifact exactly.
|
|
|
|
Output: ranked table of the top-level directory each tracked file lives in,
|
|
with a `(root)` bucket for files stored at the repository root.
|
|
|
|
Usage:
|
|
python3 extract_tracked_directory_census.py [--out PATH]
|
|
|
|
Default out: <repo>/wizard-work/ledger/2026-11-03-tracked-directory-census.csv
|
|
"""
|
|
import argparse
|
|
import collections
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
REPO = os.path.dirname(
|
|
os.path.dirname(HERE)
|
|
)
|
|
DEFAULT_OUT = os.path.join(
|
|
REPO, "wizard-work", "ledger",
|
|
"2026-11-03-tracked-directory-census.csv",
|
|
)
|
|
|
|
|
|
def tracked_files(repo):
|
|
"""Return the list of paths recorded by git ls-files at HEAD."""
|
|
proc = subprocess.run(
|
|
["git", "ls-files"],
|
|
cwd=repo,
|
|
check=True,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
return proc.stdout.splitlines()
|
|
|
|
|
|
def directory_of(path):
|
|
d = os.path.dirname(path)
|
|
return d if d else "(root)"
|
|
|
|
|
|
def build_rows(repo):
|
|
counts = collections.Counter()
|
|
for rel in tracked_files(repo):
|
|
rel = rel.rstrip("\r")
|
|
if not rel:
|
|
continue
|
|
counts[directory_of(rel)] += 1
|
|
total = sum(counts.values())
|
|
ranked = sorted(counts.items(), key=lambda kv: (-kv[1], kv[0]))
|
|
rows = []
|
|
for i, (directory, count) in enumerate(ranked, 1):
|
|
rows.append((i, directory, count, total))
|
|
return rows, total
|
|
|
|
|
|
def write_csv(path, rows, total):
|
|
with open(path, "w", encoding="utf-8", newline="") as f:
|
|
f.write("rank,directory,tracked_count,total\n")
|
|
for i, directory, count, total in rows:
|
|
f.write(f"{i},{directory},{count},{total}\n")
|
|
|
|
|
|
def main(argv=None):
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument(
|
|
"--out",
|
|
default=DEFAULT_OUT,
|
|
help=f"write CSV to PATH (default: {DEFAULT_OUT})",
|
|
)
|
|
args = parser.parse_args(argv)
|
|
|
|
rows, total = build_rows(REPO)
|
|
write_csv(args.out, rows, total)
|
|
print(f"wrote {args.out} ({len(rows)} rows, total tracked files = {total})")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|