#!/usr/bin/env python3 """tech-log-tree.json 을 다시 만든다. SSOT(final/document.md)에서 뽑은 글감과 이미 쓴 기록을 한 파일에 모은다. 기록 파일이 정본이므로 이 스크립트는 그것을 읽어 채우고, 아직 글이 없는 글감은 사람이 적은 항목을 그대로 둔다. python3 scripts/build-tech-log-tree.py [프로젝트 ...] """ from __future__ import annotations import json, re, sys, glob, os, datetime KINDS = ["case", "concept", "reference", "question", "decision"] ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) def front_matter(path: str) -> dict: text = open(path, encoding="utf-8").read() if not text.startswith("---"): return {} end = text.find("\n---", 3) out = {} for line in text[3:end].splitlines(): m = re.match(r"^([a-zA-Z_]+):\s*(.*)$", line) if m: out[m.group(1)] = m.group(2).strip().strip('"') return out def build(project: str) -> dict: base = os.path.join(ROOT, "docs", project) studio = os.path.join(base, "tech-log-studio") tree_path = os.path.join(studio, "tech-log-tree.json") previous = {} if os.path.exists(tree_path): previous = json.load(open(tree_path, encoding="utf-8")) ssot = "final/document.md" if os.path.exists(os.path.join(base, "final/document.md")) else None topics = {} for topic_dir in sorted(d for d in glob.glob(os.path.join(studio, "*")) if os.path.isdir(d)): topic = os.path.basename(topic_dir) entry = {"topic": topic, "kinds": {}} for kind in KINDS: items = [] for f in sorted(glob.glob(os.path.join(topic_dir, kind, "*.md"))): fm = front_matter(f) text = open(f, encoding="utf-8").read() items.append({ "title": fm.get("title", os.path.basename(f)), "slug": fm.get("slug", ""), "file": os.path.relpath(f, studio), "status": fm.get("status", "미작성"), "studioId": fm.get("id", ""), "assets": len(re.findall(r"^ - key: ", text, re.M)), "evidence": len(re.findall(r"^ - \.\./", text, re.M)), }) # 아직 글이 없는 글감은 지난 tree 에서 가져와 유지한다 written = {i["slug"] for i in items if i["slug"]} for old in previous.get("topics", {}).get(topic, {}).get("kinds", {}).get(kind, []): if not old.get("file") and old.get("slug") not in written: items.append(old) entry["kinds"][kind] = items topics[topic] = entry return { "project": project, "ssot": ssot, "generatedAt": datetime.date.today().isoformat(), "note": "글감 목록이다. file 이 있으면 이미 쓴 기록이고, 없으면 아직 쓰지 않은 글감이다.", "topics": topics, } def main(argv: list[str]) -> int: projects = argv[1:] or [ os.path.basename(os.path.dirname(p)) for p in glob.glob(os.path.join(ROOT, "docs/*/tech-log-studio")) ] for project in sorted(projects): tree = build(project) out = os.path.join(ROOT, "docs", project, "tech-log-studio", "tech-log-tree.json") with open(out, "w", encoding="utf-8") as fh: json.dump(tree, fh, ensure_ascii=False, indent=2) fh.write("\n") n = sum(len(v) for t in tree["topics"].values() for v in t["kinds"].values()) print(f"{os.path.relpath(out, ROOT)} — 주제 {len(tree['topics'])} · 글감 {n}") return 0 if __name__ == "__main__": raise SystemExit(main(sys.argv))