Initial commit: ABAP indexing pipeline (ingest, parser, summarize, index, query, wiki)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
"""위키 생성 CLI (계획서 v4 §5.7, §11.6).
|
||||
|
||||
python -m wiki_out.run [--program X] [--all] [--limit N] [--dry-run]
|
||||
|
||||
- 요약(Stage 3) 이 없어도 파서 구조 사실만으로 문서를 만든다(조각이 생기면 재실행 시 채워짐).
|
||||
- programs/packages/concepts 는 사람 교정 보존 병합(merge.py). 로직 조각은 프로그램 문서 안의 섹션.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
|
||||
from config.glossary import load_glossary
|
||||
from config.settings import settings
|
||||
from index.db import connect
|
||||
|
||||
from .entities import write_entity_wiki
|
||||
from .merge import merge_write
|
||||
from .okf_writer import PIPELINE, _fm, _lst, _now, _q, write_manifest, write_program_wiki
|
||||
|
||||
|
||||
def write_concepts() -> int:
|
||||
"""도메인 용어 사전을 concepts/ 문서로 출력.
|
||||
|
||||
사전 로딩은 config.glossary 로 옮겼다 — 질의 확장(query/expand.py)이 같은 사전을 써야 하고,
|
||||
파싱 규칙이 두 곳에 있으면 갈라진다.
|
||||
"""
|
||||
glossary = load_glossary()
|
||||
count = 0
|
||||
for concept, related in glossary.items():
|
||||
fm = [
|
||||
"type: concept",
|
||||
f"title: {_q(concept)}",
|
||||
f"description: {_q(concept + ' — 도메인 개념 (질의 확장용)')}",
|
||||
f"tags: {_lst(related[:10])}",
|
||||
f"generated: {{ by: {_q(PIPELINE)}, at: {_q(_now())} }}",
|
||||
]
|
||||
body = ["## 관련 용어", "",
|
||||
"이 목록은 검색 질의 확장에도 쓰인다 — `/search/logic?q=` 에 아래 어느 말로 물어도 걸린다.",
|
||||
""] + [f"- {t}" for t in related] + [""]
|
||||
rel = f"concepts/{re.sub(r'[^0-9A-Za-z가-힣_.-]', '_', concept)}.md"
|
||||
merge_write(settings.wiki_dir / rel, _fm(fm) + "\n" + "\n".join(body),
|
||||
code_hash=None, wiki_dir=settings.wiki_dir, doc_rel=rel)
|
||||
count += 1
|
||||
return count
|
||||
|
||||
|
||||
def main() -> None:
|
||||
ap = argparse.ArgumentParser(description="OKF 위키 생성")
|
||||
ap.add_argument("--program", default=None, help="프로그램 하나만")
|
||||
ap.add_argument("--all", action="store_true", help="소스 있는 전체 프로그램")
|
||||
ap.add_argument("--limit", type=int, default=None)
|
||||
ap.add_argument("--no-entities", action="store_true",
|
||||
help="tables/ functions/ tcodes/ 엔티티 페이지를 만들지 않는다")
|
||||
ap.add_argument("--dry-run", action="store_true")
|
||||
args = ap.parse_args()
|
||||
|
||||
con = connect()
|
||||
try:
|
||||
if args.program:
|
||||
names = [args.program.upper()]
|
||||
elif args.all:
|
||||
rows = con.execute(
|
||||
"SELECT name FROM program WHERE has_source=1 ORDER BY name").fetchall()
|
||||
names = [r["name"] for r in rows]
|
||||
else:
|
||||
ap.error("--program 또는 --all 필요")
|
||||
if args.limit:
|
||||
names = names[: args.limit]
|
||||
if args.dry_run:
|
||||
print(json.dumps({"would_process": len(names)}, ensure_ascii=False))
|
||||
return
|
||||
|
||||
totals = {"programs": 0, "chunks": 0, "packages": 0, "failed": 0}
|
||||
for name in names:
|
||||
try:
|
||||
s = write_program_wiki(name, con=con)
|
||||
totals["programs"] += s["programs"]
|
||||
totals["chunks"] += s["chunks"]
|
||||
totals["packages"] += s["packages"]
|
||||
except Exception as e: # noqa: BLE001
|
||||
totals["failed"] += 1
|
||||
print(f"[FAIL] {name}: {type(e).__name__}: {e}")
|
||||
totals["concepts"] = write_concepts()
|
||||
if not args.no_entities:
|
||||
# tables/ functions/ tcodes/ — 파서 사실만으로 만들어진다 (수정사항 8번)
|
||||
totals.update(write_entity_wiki(con, settings.wiki_dir))
|
||||
write_manifest(settings.wiki_dir, con)
|
||||
print(json.dumps(totals, ensure_ascii=False))
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user