2"""Inject the theme-sync script into generated Doxygen HTML so the built tree is publishable as-is."""
4from __future__
import annotations
9from pathlib
import Path
12SCRIPT_NAME =
"theme-sync.js"
17 @brief Parse command-line arguments.
18 @return Parsed argument namespace.
20 parser = argparse.ArgumentParser(
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."
25 formatter_class=argparse.RawTextHelpFormatter,
30 default=Path(__file__).resolve().parents[2],
31 help=
"Repository root directory (default: parent of this script).",
35 default=
"docs_build/html",
36 help=
"Generated HTML directory relative to repo root (default: docs_build/html).",
38 return parser.parse_args()
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.
48 depth = len(page.relative_to(html_dir).parts) - 1
49 return "../" * depth + SCRIPT_NAME
52def inject(html_dir: Path, source: Path) -> tuple[int, int]:
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.
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")
65 if re.search(rf
'<script[^>]+src="[^"]*{re.escape(SCRIPT_NAME)}"', markup):
68 if "</head>" not in markup:
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")
73 return injected, skipped
78 @brief Make the generated HTML tree self-contained with respect to theme syncing.
79 @return Process status code.
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)
88 if not source.is_file():
89 print(f
"theme-sync injection failed: {source} is missing.", file=sys.stderr)
91 injected, skipped =
inject(html_dir, source)
92 print(f
"[theme-sync] injected into {injected} page(s); {skipped} already referenced it.")
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.