PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
stamp_docs_revision.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2"""Stamp generated Doxygen HTML with the Git revision it documents."""
3
4from __future__ import annotations
5
6import argparse
7import json
8import subprocess
9from pathlib import Path
10
11
12REPO_ROOT = Path(__file__).resolve().parents[2]
13
14
15def git_output(*args: str) -> str:
16 """!
17 @brief Return trimmed output from one Git command.
18 @param[in] args Arguments passed after `git`.
19 @return Decoded, trimmed Git stdout.
20 """
21
22 return subprocess.check_output(["git", *args], cwd=REPO_ROOT, text=True).strip()
23
24
25def resolve_release_identity(dirty: bool) -> dict:
26 """!
27 @brief Resolve the PICurv release identity the same way the conductor does.
28
29 @details Mirrors `_source_build_identity()` in `picurv_cli/core.py` using only Git
30 and the `VERSION` file, so the docs build stays free of a `picurv_cli`
31 import (and its PETSc-adjacent dependency chain) while still reporting the
32 same `release_version` / `build_id` a user sees from `picurv version`.
33 @param[in] dirty Whether the working tree carries uncommitted tracked changes.
34 @return Mapping with `release_version`, `build_id`, and `released`.
35 """
36
37 release_version = (REPO_ROOT / "VERSION").read_text(encoding="utf-8").strip()
38 short_sha = git_output("rev-parse", "--short=12", "HEAD")
39 dev_distance = None
40 describe = subprocess.run(
41 ["git", "describe", "--tags", "--match", f"v{release_version}", "--long"],
42 cwd=REPO_ROOT, text=True, capture_output=True, check=False,
43 )
44 if describe.returncode == 0:
45 parts = describe.stdout.strip().rsplit("-", 2)
46 if len(parts) == 3 and parts[1].isdigit():
47 dev_distance = int(parts[1])
48 else:
49 dev_distance = int(git_output("rev-list", "--count", "HEAD"))
50 released = dev_distance == 0 and not dirty
51 suffix = "" if dev_distance in (0, None) else f".dev{dev_distance}"
52 build_id = f"{release_version}{suffix}+g{short_sha}" + (".dirty" if dirty else "")
53 return {"release_version": release_version, "build_id": build_id, "released": released}
54
55
56def parse_args() -> argparse.Namespace:
57 """!
58 @brief Parse generated-documentation stamping arguments.
59 @return Parsed command-line namespace.
60 """
61
62 parser = argparse.ArgumentParser(description=__doc__)
63 parser.add_argument("--html-dir", type=Path, required=True, help="generated Doxygen HTML directory")
64 return parser.parse_args()
65
66
67def main() -> int:
68 """!
69 @brief Write revision metadata and load it on every generated HTML page.
70 @return Process status code.
71 """
72
73 args = parse_args()
74 html_dir = args.html_dir.resolve()
75 if not html_dir.is_dir():
76 raise SystemExit(f"HTML directory does not exist: {html_dir}")
77 sha = git_output("rev-parse", "HEAD")
78 remote = git_output("remote", "get-url", "origin")
79 if remote.startswith("git@github.com:"):
80 remote = "https://github.com/" + remote[len("git@github.com:"):]
81 if remote.endswith(".git"):
82 remote = remote[:-4]
83 clean = not bool(git_output("status", "--porcelain"))
84 revision = {
85 "sha": sha,
86 "short_sha": sha[:12],
87 "commit_url": f"{remote}/commit/{sha}",
88 "clean": clean,
89 **resolve_release_identity(dirty=not clean),
90 }
91 (html_dir / "picurv-docs-revision.js").write_text(
92 "window.PICURV_DOCS_REVISION = " + json.dumps(revision, sort_keys=True) + ";\n",
93 encoding="utf-8",
94 )
95 for page in html_dir.rglob("*.html"):
96 relative = page.relative_to(html_dir)
97 script_path = "../picurv-docs-revision.js" if relative.parts[0] == "search" else "picurv-docs-revision.js"
98 content = page.read_text(encoding="utf-8")
99 if "picurv-docs-revision.js" not in content:
100 content = content.replace("</head>", f'<script src="{script_path}"></script>\n</head>')
101 page.write_text(content, encoding="utf-8")
102 print(f"Stamped generated documentation as PICurv {revision['build_id']} (commit {sha}).")
103 return 0
104
105
106if __name__ == "__main__":
107 raise SystemExit(main())
str git_output(*str args)
Return trimmed output from one Git command.
argparse.Namespace parse_args()
Parse generated-documentation stamping arguments.
dict resolve_release_identity(bool dirty)
Resolve the PICurv release identity the same way the conductor does.
int main()
Write revision metadata and load it on every generated HTML page.