PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
inject_theme_sync.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2"""Inject the theme-sync script into generated Doxygen HTML so the built tree is publishable as-is."""
3
4from __future__ import annotations
5
6import argparse
7import re
8import sys
9from pathlib import Path
10
11
12SCRIPT_NAME = "theme-sync.js"
13
14
15def parse_args() -> argparse.Namespace:
16 """!
17 @brief Parse command-line arguments.
18 @return Parsed argument namespace.
19 """
20 parser = argparse.ArgumentParser(
21 description=(
22 "Copy theme-sync.js into the generated HTML tree and reference it from every page.\n"
23 "Idempotent: pages that already reference the script are left untouched."
24 ),
25 formatter_class=argparse.RawTextHelpFormatter,
26 )
27 parser.add_argument(
28 "--repo-root",
29 type=Path,
30 default=Path(__file__).resolve().parents[2],
31 help="Repository root directory (default: parent of this script).",
32 )
33 parser.add_argument(
34 "--html-dir",
35 default="docs_build/html",
36 help="Generated HTML directory relative to repo root (default: docs_build/html).",
37 )
38 return parser.parse_args()
39
40
41def relative_script_path(page: Path, html_dir: Path) -> str:
42 """!
43 @brief Build the script reference for one page, correct for pages in subdirectories.
44 @param[in] page Generated HTML page.
45 @param[in] html_dir Root of the generated HTML tree.
46 @return Relative href to the theme-sync script.
47 """
48 depth = len(page.relative_to(html_dir).parts) - 1
49 return "../" * depth + SCRIPT_NAME
50
51
52def inject(html_dir: Path, source: Path) -> tuple[int, int]:
53 """!
54 @brief Copy the script into the tree and reference it from every generated page.
55 @param[in] html_dir Root of the generated HTML tree.
56 @param[in] source Authoritative theme-sync script in the repository.
57 @return Counts of pages injected and pages already carrying the reference.
58 """
59 (html_dir / SCRIPT_NAME).write_text(source.read_text(encoding="utf-8"), encoding="utf-8")
60 injected = skipped = 0
61 for page in sorted(html_dir.rglob("*.html")):
62 markup = page.read_text(encoding="utf-8", errors="replace")
63 # Match the actual script reference, not a prose mention: pages that document
64 # theme-sync.js contain the bare filename and still need the tag injected.
65 if re.search(rf'<script[^>]+src="[^"]*{re.escape(SCRIPT_NAME)}"', markup):
66 skipped += 1
67 continue
68 if "</head>" not in markup:
69 continue
70 tag = f'<script type="text/javascript" src="{relative_script_path(page, html_dir)}"></script>\n</head>'
71 page.write_text(markup.replace("</head>", tag, 1), encoding="utf-8")
72 injected += 1
73 return injected, skipped
74
75
76def main() -> int:
77 """!
78 @brief Make the generated HTML tree self-contained with respect to theme syncing.
79 @return Process status code.
80 """
81 args = parse_args()
82 repo_root = args.repo_root.resolve()
83 html_dir = (repo_root / args.html_dir).resolve()
84 source = repo_root / "docs" / SCRIPT_NAME
85 if not html_dir.is_dir():
86 print(f"theme-sync injection failed: {args.html_dir} does not exist.", file=sys.stderr)
87 return 1
88 if not source.is_file():
89 print(f"theme-sync injection failed: {source} is missing.", file=sys.stderr)
90 return 1
91 injected, skipped = inject(html_dir, source)
92 print(f"[theme-sync] injected into {injected} page(s); {skipped} already referenced it.")
93 return 0
94
95
96if __name__ == "__main__":
97 raise SystemExit(main())
str relative_script_path(Path page, Path html_dir)
Build the script reference for one page, correct for pages in subdirectories.
argparse.Namespace parse_args()
Parse command-line arguments.
tuple[int, int] inject(Path html_dir, Path source)
Copy the script into the tree and reference it from every generated page.
int main()
Make the generated HTML tree self-contained with respect to theme syncing.