Files
troupe-standup/wizard-work/ledger/drops-catalog.py
T

162 lines
5.3 KiB
Python

#!/usr/bin/env python3
"""Build the Stackchain Library drops catalog from the source folder.
Source: /root/stackchain-library-updates/drops (42 top-level entries:
39 day-drop folders, one probe JSON, and two global checksum files).
One row per entry with a recursive file-type breakdown. Idempotent:
re-running re-derives the same numbers from the same files.
Artifacts written to BOTH:
- /root/.hermes/profiles/ledger/wizard-outputs/ledger/ (profile outputs)
- /root/troupe-standup/wizard-work/ledger/ (troupe repo)
"""
import csv
import os
from collections import Counter
DROPS = "/root/stackchain-library-updates/drops"
OUT_JSON = None # not used here
OUT_CSV = "drops-catalog.csv"
OUT_MD = "drops-catalog.md"
TARGETS = (
"/root/.hermes/profiles/ledger/wizard-outputs/ledger",
"/root/troupe-standup/wizard-work/ledger",
)
# Explicit top-level entries that are files, not folders.
FILE_ENTRIES = (
"2026-10-23-probe-blocks.json",
"checksums.sha256",
"checksums.sha256.NOTES.md",
)
def classify(name):
"""Return a category key for a filename."""
low = name.lower()
if low.endswith(".mp4"):
return "mp4"
if low.endswith(".json"):
return "json"
if low.endswith(".txt"):
return "txt"
if low.endswith(".md"):
return "md"
if low.endswith((".jpg", ".jpeg", ".png", ".gif", ".webp", ".webm")):
return "jpg"
return "other"
def catalog_entry(path):
is_file = os.path.isfile(path)
if is_file:
try:
size = os.path.getsize(path)
except OSError:
size = 0
return {
"path": os.path.basename(path),
"kind": "file",
"total_files": 1,
"mp4": 0, "json": 0, "txt": 0, "md": 0, "jpg": 0, "other": 0,
"size_bytes": size,
}
total = 0
counts = Counter()
size = 0
for root, _dirs, files in os.walk(path):
for fn in files:
fp = os.path.join(root, fn)
total += 1
counts[classify(fn)] += 1
try:
size += os.path.getsize(fp)
except OSError:
pass
return {
"path": os.path.basename(path.rstrip("/")),
"kind": "dir",
"total_files": total,
"mp4": counts["mp4"],
"json": counts["json"],
"txt": counts["txt"],
"md": counts["md"],
"jpg": counts["jpg"],
"other": counts["other"],
"size_bytes": size,
}
def build_rows():
rows = []
if os.path.isdir(DROPS):
for name in sorted(os.listdir(DROPS)):
p = os.path.join(DROPS, name)
rows.append(catalog_entry(p))
for name in sorted(FILE_ENTRIES):
p = os.path.join(DROPS, name)
if os.path.isfile(p) and not any(r["path"] == name for r in rows):
rows.append(catalog_entry(p))
return rows
def write_csv(rows, target):
path = os.path.join(target, OUT_CSV)
with open(path, "w", encoding="utf-8", newline="") as f:
writer = csv.DictWriter(f, fieldnames=list(rows[0].keys()))
writer.writeheader()
writer.writerows(rows)
return path
def write_md(rows, target):
path = os.path.join(target, OUT_MD)
lines = []
lines.append("# Stackchain library drops catalog")
lines.append("")
lines.append("Source: `%s`. One row per top-level entry (39 day-drop folders, "
"one probe JSON, two checksum files). `md` counts reproduced "
"`MANIFEST.md` files." % DROPS)
lines.append("")
lines.append("| Path | Kind | Files | MP4 | JSON | TXT | MANIFEST(md) | JPG | Other | Size(B) |")
lines.append("|---|------|-------|-----|------|-----|--------------|-----|-----|---------|")
for r in rows:
lines.append(
"| `{path}` | {kind} | {total} | {mp4} | {json} | {txt} | {md} | {jpg} | "
"{other} | {size} |".format(
path=r["path"], kind=r["kind"], total=r["total_files"],
mp4=r["mp4"], json=r["json"], txt=r["txt"], md=r["md"],
jpg=r["jpg"], other=r["other"], size=r["size_bytes"]))
lines.append("")
totals = {k: sum(r[k] for r in rows) for k in
("total_files", "mp4", "json", "txt", "md", "jpg", "other", "size_bytes")}
lines.append("**Summary:** {n} entries · {files} total files · {md} with "
"MANIFEST.md · {mp4} mp4 · {json} json · {txt} txt · {jpg} jpg · "
"{other} other · {size} bytes.".format(
n=len(rows), files=totals["total_files"], md=totals["md"],
mp4=totals["mp4"], json=totals["json"], txt=totals["txt"],
jpg=totals["jpg"], other=totals["other"], size=totals["size_bytes"]))
lines.append("")
with open(path, "w", encoding="utf-8") as f:
f.write("\n".join(lines))
return path
def main():
rows = build_rows()
for target in TARGETS:
os.makedirs(target, exist_ok=True)
csv_path = write_csv(rows, target)
md_path = write_md(rows, target)
print("wrote", csv_path)
print("wrote", md_path)
print("total entries:", len(rows))
print("by kind:", {k: sum(1 for r in rows if r["kind"] == k)
for k in ("dir", "file")})
if __name__ == "__main__":
main()