#!/usr/bin/env python3 """Render an ASCII tree of tracked files, read from stdin (one path per line). Used by the `sync-project-tree` workflow to regenerate this repo's PROJECT_TREE.md snapshot in the RunicGateway/docs repo. Feed it `git ls-files`: git ls-files | python3 .gitea/scripts/gen_tree.py Deterministic ordering: directories before files, each group sorted case-insensitively with the raw name as a tiebreak. Output uses the classic `tree(1)` box-drawing style so the result is stable across runs and platforms. """ import sys def build(paths): root = {} for p in paths: p = p.strip().replace("\\", "/") if not p: continue node = root for part in p.split("/"): node = node.setdefault(part, {}) return root def render(node, prefix, lines): entries = list(node.items()) # directories (non-empty children dict) before files, then case-insensitive name entries.sort(key=lambda kv: (0 if kv[1] else 1, kv[0].lower(), kv[0])) for i, (name, child) in enumerate(entries): last = i == len(entries) - 1 branch = "└── " if last else "├── " suffix = "/" if child else "" lines.append(f"{prefix}{branch}{name}{suffix}") if child: render(child, prefix + (" " if last else "│ "), lines) def main(): try: sys.stdout.reconfigure(encoding="utf-8", newline="\n") except AttributeError: pass root_label = sys.argv[1] if len(sys.argv) > 1 else "." tree = build(sys.stdin.read().splitlines()) lines = [f"{root_label}/"] render(tree, "", lines) sys.stdout.write("\n".join(lines) + "\n") if __name__ == "__main__": main()