#!/usr/bin/env python3 """ issue_index.py — rebuild tmp/issues/INDEX.md from what is on disk. Offline. A map of the local store, nothing else. The `origin` column is the only place the index acknowledges that a tracker exists: `local` means the issue has never left this machine, `gitea` means the sync layer has pushed or pulled it. Both are ordinary issues here. Usage: issue_index.py [--out tmp/issues] """ import argparse import os import re import sys sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import issue # noqa: E402 def cell(v): if isinstance(v, (list, tuple)): return ", ".join(str(x) for x in v) or "—" v = str(v or "").strip() return v.replace("|", "\\|") or "—" def build(root): issues = issue.load_all(root) rows = [] for i in sorted(issues): iss = issues[i] rest = [l for l in iss.labels if not l.startswith("type/")] rows.append({ "id": i, "state": cell(iss.state), "type": cell(iss.type), "labels": cell(rest), "title": cell(iss.title), "milestone": cell(iss.milestone), "depends": cell(iss.depends), "origin": cell(iss.origin), }) listing = os.listdir(root) if os.path.isdir(root) else [] trees = sorted(f for f in listing if re.match(r'^tree-.+\.md$', f)) out = ["# Issue store", "", "Every issue this project knows about. `origin: local` means it " "exists nowhere else — a complete state, not a pending one. Any " "other value names the tracker it also lives in; the handle is in " "the file. Rebuild with `issue_index.py`.", ""] if rows: out += ["| id | state | type | labels | title | milestone | depends | origin |", "|---|---|---|---|---|---|---|---|"] out += ["| [%s](%s.md) | %s | %s | %s | %s | %s | %s | %s |" % ( r["id"], r["id"], r["state"], r["type"], r["labels"], r["title"], r["milestone"], r["depends"], r["origin"]) for r in rows] else: out.append("_empty_") if trees: out += ["", "## Dependency trees", ""] out += ["- [%s](%s)" % (t, t) for t in trees] cycles = issue.find_cycles(issue.graph(issues)) if cycles: out += ["", "## Dependency cycles", ""] out += ["- %s" % " -> ".join(c) for c in cycles] out.append("") path = os.path.join(root, "INDEX.md") os.makedirs(root, exist_ok=True) with open(path, "w") as f: f.write("\n".join(out)) return path, len(rows) def main(): ap = argparse.ArgumentParser(description="Rebuild the local issue index (offline)") ap.add_argument("--out", default=issue.ISSUE_ROOT, help="store root (default: tmp/issues)") args = ap.parse_args() path, n = build(args.out) print("%s — %d issue(s)" % (path, n)) if __name__ == "__main__": main()