manage_docs cli
This commit is contained in:
152
manage_docs.py
Normal file
152
manage_docs.py
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
"""
|
||||||
|
MkDocs documentation management CLI.
|
||||||
|
|
||||||
|
This script provides a proper CLI interface to:
|
||||||
|
- Generate MkDocs Markdown files with mkdocstrings directives
|
||||||
|
- Build the documentation site
|
||||||
|
- Serve the documentation site locally
|
||||||
|
|
||||||
|
All operations are performed by calling MkDocs as a Python library
|
||||||
|
(no shell command invocation).
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
- mkdocs
|
||||||
|
- mkdocs-material
|
||||||
|
- mkdocstrings[python]
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python manage_docs.py generate
|
||||||
|
python manage_docs.py build
|
||||||
|
python manage_docs.py serve
|
||||||
|
|
||||||
|
Optional flags:
|
||||||
|
--docs-dir PATH Path to docs directory (default: ./docs)
|
||||||
|
--package-root NAME Root Python package name (default: mail_intake)
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from mkdocs.commands import build as mkdocs_build
|
||||||
|
from mkdocs.commands import serve as mkdocs_serve
|
||||||
|
from mkdocs.config import load_config
|
||||||
|
|
||||||
|
|
||||||
|
PROJECT_ROOT = Path(__file__).resolve().parent
|
||||||
|
DEFAULT_DOCS_DIR = PROJECT_ROOT / "docs"
|
||||||
|
DEFAULT_PACKAGE_ROOT = "mail_intake"
|
||||||
|
MKDOCS_YML = PROJECT_ROOT / "mkdocs.yml"
|
||||||
|
|
||||||
|
def generate_docs_from_nav(
|
||||||
|
project_root: Path,
|
||||||
|
docs_root: Path,
|
||||||
|
package_root: str,
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Create and populate MkDocs Markdown files with mkdocstrings directives.
|
||||||
|
|
||||||
|
This function:
|
||||||
|
- Walks the Python package structure
|
||||||
|
- Mirrors it under the docs directory
|
||||||
|
- Creates missing .md files
|
||||||
|
- Overwrites content with ::: package.module
|
||||||
|
|
||||||
|
Example:
|
||||||
|
mail_intake/config.py -> docs/mail_intake/config.md
|
||||||
|
mail_intake/adapters/base.py -> docs/mail_intake/adapters/base.md
|
||||||
|
"""
|
||||||
|
|
||||||
|
package_dir = project_root / package_root
|
||||||
|
if not package_dir.exists():
|
||||||
|
raise FileNotFoundError(f"Package not found: {package_dir}")
|
||||||
|
|
||||||
|
docs_root.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
for py_file in package_dir.rglob("*.py"):
|
||||||
|
if py_file.name == "__init__.py":
|
||||||
|
continue
|
||||||
|
|
||||||
|
rel = py_file.relative_to(project_root)
|
||||||
|
md_path = docs_root / rel.with_suffix(".md")
|
||||||
|
|
||||||
|
md_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
module_path = ".".join(rel.with_suffix("").parts)
|
||||||
|
title = md_path.stem.replace("_", " ").title()
|
||||||
|
|
||||||
|
content = f"""# {title}
|
||||||
|
|
||||||
|
::: {module_path}
|
||||||
|
"""
|
||||||
|
|
||||||
|
md_path.write_text(content, encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def load_mkdocs_config():
|
||||||
|
if not MKDOCS_YML.exists():
|
||||||
|
raise FileNotFoundError("mkdocs.yml not found at project root")
|
||||||
|
return load_config(str(MKDOCS_YML))
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_generate(args: argparse.Namespace) -> None:
|
||||||
|
generate_docs_from_nav(
|
||||||
|
project_root=PROJECT_ROOT,
|
||||||
|
docs_root=args.docs_dir,
|
||||||
|
package_root=args.package_root,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_build(_: argparse.Namespace) -> None:
|
||||||
|
config = load_mkdocs_config()
|
||||||
|
mkdocs_build.build(config)
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_serve(_: argparse.Namespace) -> None:
|
||||||
|
config = load_mkdocs_config()
|
||||||
|
mkdocs_serve.serve(config)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
prog="manage_docs.py",
|
||||||
|
description="Manage MkDocs documentation for the project",
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--docs-dir",
|
||||||
|
type=Path,
|
||||||
|
default=DEFAULT_DOCS_DIR,
|
||||||
|
help="Path to the docs directory",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--package-root",
|
||||||
|
default=DEFAULT_PACKAGE_ROOT,
|
||||||
|
help="Root Python package name",
|
||||||
|
)
|
||||||
|
|
||||||
|
subparsers = parser.add_subparsers(dest="command", required=True)
|
||||||
|
|
||||||
|
subparsers.add_parser(
|
||||||
|
"generate",
|
||||||
|
help="Generate Markdown files with mkdocstrings directives",
|
||||||
|
).set_defaults(func=cmd_generate)
|
||||||
|
|
||||||
|
subparsers.add_parser(
|
||||||
|
"build",
|
||||||
|
help="Build the MkDocs site",
|
||||||
|
).set_defaults(func=cmd_build)
|
||||||
|
|
||||||
|
subparsers.add_parser(
|
||||||
|
"serve",
|
||||||
|
help="Serve the MkDocs site locally",
|
||||||
|
).set_defaults(func=cmd_serve)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
args.func(args)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user