mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-09 20:26:33 +00:00
The Sphinx configuration, extensions and generators lived in the separate infinito-sphinx repository, whose image baked a snapshot of core at build time from a base image name core no longer publishes. Only core consumed it, and its generators read core's role layout, so the two repositories drifted without any CI covering the pair. The tooling now ships in roles/web-app-docs/files/, and web-app-sphinx is renamed to web-app-docs. The container is a small service instead of a static image: - it keeps a git mirror of the repository in the docs_sites volume; - /latest/ is the last commit of the default branch, rebuilt whenever a fetch finds a new one while the previous build stays online; - every release tag is selectable in the sidebar switcher and on /versions/, and is built the first time someone opens it, behind a progress bar; - replicas share the volume: the one holding builder.lock fetches and builds, the queue and the build states are files beside the sites, so another replica resumes the queue when the builder dies. The theme rewrites every page serially after the build, which took about 75 minutes for the 4544 pages; that pass now runs on the -j workers with the theme's own function. sphinx-apidoc skips tests/, because tests/utils/bare_bootstrap_probe.py installs an import blocker when autodoc imports it and killed the Sphinx workers. The roles overview is generated by a separate process, so autodoc resolves utils from the version being built, not from main. The role pages now show galaxy_info.description instead of the top-level key that never existed. The Sphinx packages join the dev extra, because the mirrored unit tests of the tooling import them. min_storage now budgets the built image, the latest site and a running build's scratch instead of the old image's size. The Playwright suite is split into front page, versions and on-demand build files; the last one selects an unbuilt tag in the overview and asserts the build gets queued. Operators must rename the web-app-sphinx inventory group to web-app-docs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
70 lines
2.1 KiB
Python
70 lines
2.1 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from docutils import nodes
|
|
from docutils.frontend import get_default_settings
|
|
from docutils.parsers.rst import Directive
|
|
from docutils.utils import new_document
|
|
from myst_parser.parsers.sphinx_ import MystParser
|
|
|
|
|
|
def _strip_title(doc):
|
|
"""Drop the leading title of a parsed Markdown document in place.
|
|
|
|
Args:
|
|
doc: docutils document produced by :class:`MystParser`.
|
|
"""
|
|
first = doc.children[0] if doc.children else None
|
|
if not isinstance(first, nodes.section):
|
|
return
|
|
|
|
if first.children and isinstance(first.children[0], nodes.title):
|
|
if len(first.children) > 1:
|
|
first.pop(0)
|
|
else:
|
|
first.children[0].clear()
|
|
|
|
if not any(
|
|
isinstance(child, nodes.title) and child.astext().strip()
|
|
for child in first.children
|
|
):
|
|
doc.children = list(first.children) + doc.children[1:]
|
|
|
|
|
|
class MarkdownIncludeDirective(Directive):
|
|
required_arguments = 1
|
|
optional_arguments = 0
|
|
final_argument_whitespace = True
|
|
has_content = False
|
|
|
|
def _error(self, message):
|
|
return self.state_machine.reporter.error(
|
|
message,
|
|
nodes.literal_block(self.block_text, self.block_text),
|
|
line=self.lineno,
|
|
)
|
|
|
|
def run(self):
|
|
env = self.state.document.settings.env
|
|
_, filename = env.relfn2path(self.arguments[0])
|
|
path = Path(filename)
|
|
if not path.exists():
|
|
return [self._error(f"File not found: {filename}")]
|
|
try:
|
|
markdown = path.read_text(encoding="utf-8")
|
|
except (OSError, UnicodeDecodeError) as exc:
|
|
return [self._error(f"Error reading file {filename}: {exc}")]
|
|
|
|
settings = get_default_settings(MystParser)
|
|
settings.env = env
|
|
doc = new_document(filename, settings=settings)
|
|
MystParser().parse(markdown, doc)
|
|
_strip_title(doc)
|
|
return doc.children
|
|
|
|
|
|
def setup(app):
|
|
app.add_directive("markdown-include", MarkdownIncludeDirective)
|
|
return {"version": "0.1", "parallel_read_safe": True}
|