docs: auto-generate Makefile reference page for RTD
Adds a Sphinx extension at docs/_source/_ext/makefile_targets.py that parses the project Makefile's '## description' annotations and writes docs/_source/api/makefile.rst at build time. Same convention 'make help' uses, so the reference stays in sync with the source. Generated page is grouped by target prefix (fetch-, ingest-, distill-, docs-, etc.) and rendered as a list-table. Shows on RTD alongside the autodoc API modules. Generated file is gitignored — RTD regenerates on every build.
This commit is contained in:
parent
306b7f3701
commit
546fa6d690
4 changed files with 81 additions and 1 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -21,3 +21,6 @@ bench/qa_results/
|
|||
|
||||
# Sphinx build artifacts (generated; RTD builds on its servers)
|
||||
docs/_source/_build/
|
||||
|
||||
# Auto-generated by docs/_source/_ext/makefile_targets.py at Sphinx build time
|
||||
docs/_source/api/makefile.rst
|
||||
|
|
|
|||
74
docs/_source/_ext/makefile_targets.py
Normal file
74
docs/_source/_ext/makefile_targets.py
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
"""Generate docs/_source/api/makefile.rst from Makefile ## annotations.
|
||||
|
||||
Convention: every documented target has the form
|
||||
target-name: deps ## one-line description
|
||||
|
||||
This extension parses the project's Makefile and writes an RST page
|
||||
listing every documented target, grouped by category prefix.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
TARGET_RE = re.compile(r"^([a-zA-Z0-9_-]+):.*?##\s*(.*)$")
|
||||
|
||||
|
||||
def parse_makefile(makefile_path: Path) -> list[tuple[str, str]]:
|
||||
"""Return list of (target, description) tuples from a Makefile."""
|
||||
targets = []
|
||||
for line in makefile_path.read_text(encoding="utf-8").splitlines():
|
||||
m = TARGET_RE.match(line)
|
||||
if m:
|
||||
targets.append((m.group(1), m.group(2).strip()))
|
||||
return targets
|
||||
|
||||
|
||||
def categorize(targets: list[tuple[str, str]]) -> dict[str, list[tuple[str, str]]]:
|
||||
"""Group targets by leading prefix (e.g. 'fetch-', 'ingest-', 'docs-')."""
|
||||
groups: dict[str, list[tuple[str, str]]] = {}
|
||||
for name, desc in targets:
|
||||
prefix = name.split("-", 1)[0] if "-" in name else name
|
||||
groups.setdefault(prefix, []).append((name, desc))
|
||||
return groups
|
||||
|
||||
|
||||
def generate_rst(targets: list[tuple[str, str]], output_path: Path) -> None:
|
||||
"""Write a single RST page listing every documented target."""
|
||||
groups = categorize(targets)
|
||||
lines = [
|
||||
"Makefile reference",
|
||||
"==================",
|
||||
"",
|
||||
"Every aborist workflow lives behind a ``make`` target. This page is",
|
||||
"auto-generated from the project ``Makefile``'s ``## description``",
|
||||
"annotations at Sphinx build time, so it stays in sync with the source.",
|
||||
"",
|
||||
"Run ``make help`` locally for the same listing.",
|
||||
"",
|
||||
]
|
||||
for prefix in sorted(groups):
|
||||
lines.append(prefix)
|
||||
lines.append("-" * len(prefix))
|
||||
lines.append("")
|
||||
lines.append(".. list-table::")
|
||||
lines.append(" :widths: 25 75")
|
||||
lines.append(" :header-rows: 1")
|
||||
lines.append("")
|
||||
lines.append(" * - Target")
|
||||
lines.append(" - Description")
|
||||
for name, desc in sorted(groups[prefix]):
|
||||
lines.append(f" * - ``{name}``")
|
||||
lines.append(f" - {desc}")
|
||||
lines.append("")
|
||||
output_path.write_text("\n".join(lines), encoding="utf-8")
|
||||
|
||||
|
||||
def setup(app):
|
||||
"""Sphinx hook: regenerate makefile.rst at the start of every build."""
|
||||
project_root = Path(app.srcdir).parent.parent
|
||||
makefile = project_root / "Makefile"
|
||||
output = Path(app.srcdir) / "api" / "makefile.rst"
|
||||
if makefile.exists():
|
||||
targets = parse_makefile(makefile)
|
||||
generate_rst(targets, output)
|
||||
return {"version": "1.0", "parallel_read_safe": True}
|
||||
|
|
@ -3,9 +3,10 @@
|
|||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Add aborist package to path
|
||||
# Add aborist package + local _ext (Sphinx extensions) to path
|
||||
project_root = Path(__file__).parent.parent.parent
|
||||
sys.path.insert(0, str(project_root))
|
||||
sys.path.insert(0, str(Path(__file__).parent / "_ext"))
|
||||
|
||||
# Project info
|
||||
project = "Aborist"
|
||||
|
|
@ -20,6 +21,7 @@ extensions = [
|
|||
"sphinx.ext.napoleon",
|
||||
"sphinx.ext.intersphinx",
|
||||
"sphinx.ext.viewcode",
|
||||
"makefile_targets", # local: generates api/makefile.rst from Makefile ## annotations
|
||||
]
|
||||
|
||||
# Autodoc settings
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ Contents:
|
|||
:maxdepth: 3
|
||||
:caption: API Modules
|
||||
|
||||
api/makefile
|
||||
api/substrate
|
||||
api/storage
|
||||
api/retrieval
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue