Skip to content

Commit b08a181

Browse files
hoe-jocastler
authored andcommitted
[rules score] fix parallel trlc merge
1 parent 99b8dcf commit b08a181

5 files changed

Lines changed: 121 additions & 7 deletions

File tree

MODULE.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ use_repo(pip, "manual_analysis_deps")
291291
bazel_dep(name = "trlc", version = "0.0.0")
292292
git_override(
293293
module_name = "trlc",
294-
commit = "7f06d0396fd0e5f02b657d25700775af5113b7e0",
294+
commit = "c4c531b9d667085daa09dfc1590edacc314bfda4",
295295
remote = "https://github.com/bmw-software-engineering/trlc.git",
296296
)
297297

bazel/rules/rules_score/docs/rule_reference.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,10 @@ cross-module dependencies and automatic HTML merging.
7272
- no
7373
- Bazel visibility
7474

75-
**Generated targets:** ``<name>`` — Sphinx build; output under ``bazel-bin/<name>/html/``
75+
**Generated targets:**
76+
77+
- ``<name>`` — HTML output under ``bazel-bin/<name>/html/``; use in ``deps`` of other ``sphinx_module`` targets.
78+
- ``<name>_needs`` — ``needs.json`` produced by the needs builder; consumed transitively by downstream modules for cross-module ``{requirement:downstream-ref}`` resolution. See :ref:`two-phase-sphinx-build` for the full data-flow description.
7679

7780

7881
Artifact Rules

bazel/rules/rules_score/docs/tooling_architecture.rst

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,20 @@ are rendered under :doc:`tool_reference/index`.
123123
* - **Sphinx (Docs)**
124124
- ``score_build`` (``src/sphinx_wrapper.py``),
125125
``html_merge_tool`` (``src/sphinx_html_merge.py``),
126-
``sphinx_module_ext`` / ``bazel_sphinx_needs``
126+
``sphinx_module_ext``,
127+
``trlc`` Sphinx extension (``@trlc``)
127128
- ``sphinx_module``, ``dependable_element``
128-
- Two-phase documentation build: phase 1 emits ``needs.json`` for
129-
sphinx-needs cross-referencing, phase 2 builds HTML and merges
130-
dependency modules into one site.
129+
- Two-phase documentation build: **phase 1** (``<name>_needs`` target)
130+
runs Sphinx with ``--builder needs`` to emit ``needs.json`` containing
131+
any native ``sphinx-needs`` (``.. need::``) directives found in the
132+
sources. **Phase 2** (``<name>`` target) runs Sphinx with
133+
``--builder html``, resolving ``trlc`` ``.. requirement:definition::``
134+
cross-references within the relocated source tree and consuming
135+
``needs.json`` files of all ``deps`` via ``needs_external_needs_json``
136+
for cross-module ``sphinx-needs`` links.
137+
``src/sphinx_html_merge.py`` then merges dependency HTML directories
138+
into the final output site.
139+
See :ref:`two-phase-sphinx-build` for details.
131140
* - **Lobster Bazel**
132141
- ``//lobster_bazel:lobster_linker`` (``parse_source_files.py``)
133142
- ``rules_score_impl`` (tool-qualification chain)
@@ -169,3 +178,86 @@ feed that pipeline:
169178
* **FMEA** (``failuremodes.trlc`` / ``controlmeasures.trlc``) → ``lobster-trlc``;
170179
**FTA** (``fta.puml``) → ``safety_analysis_tools`` → ``root_causes.lobster``.
171180
* **Unit tests** (gtest) → ``gtest_report`` → ``<unit>.lobster``.
181+
182+
.. _two-phase-sphinx-build:
183+
184+
Two-phase Sphinx build
185+
----------------------
186+
187+
Every ``sphinx_module`` call expands into **two** Bazel targets that run
188+
sequentially:
189+
190+
.. code-block:: text
191+
192+
<name>_needs (phase 1 — needs builder)
193+
<name> (phase 2 — HTML builder)
194+
195+
Phase 1 — ``<name>_needs``
196+
~~~~~~~~~~~~~~~~~~~~~~~~~~
197+
198+
Sphinx is invoked with ``--builder needs`` against the **static docs/ source
199+
tree** (only ``srcs`` files — the checked-in ``.rst``/``.md`` files plus the
200+
generated ``trlc_rst`` outputs that are listed as label targets in ``srcs``).
201+
Generated/external files from ``renamed_srcs`` and ``docs_library_deps`` are
202+
**not** included; their toctree entries produce ``toc.not_readable`` warnings
203+
that are suppressed in ``conf.template.py`` (see below for why this is safe).
204+
205+
The needs builder scans every document for ``.. need::`` directives
206+
(``sphinx-needs`` native format) and writes them to a ``needs.json`` file.
207+
208+
The ``toc.not_readable`` suppression in ``conf.template.py`` is safe for the
209+
HTML phase because that phase relocates every file into a staging directory, so
210+
it never encounters an unresolvable toctree entry.
211+
212+
The resulting ``needs.json`` (empty for modules whose requirements are authored
213+
in TRLC rather than native ``sphinx-needs`` format) is wrapped in a
214+
``SphinxNeedsInfo`` provider and propagated transitively so that every
215+
downstream module can consume it.
216+
217+
Phase 2 — ``<name>``
218+
~~~~~~~~~~~~~~~~~~~~
219+
220+
Sphinx is invoked with ``--builder html`` against a **relocated copy** of all
221+
source files (``srcs``, ``renamed_srcs``, ``docs_library_deps``) symlinked into
222+
a unified staging directory under ``bazel-bin/``.
223+
224+
This is also where ``.. requirement:definition::`` directives (from the ``trlc``
225+
Sphinx extension) are processed and cross-references resolved. The raw
226+
requirement records come from ``.trlc`` source files compiled by the
227+
``trlc_rst`` Bazel rule into ``.rst`` files that contain the directives. The
228+
chain is:
229+
230+
.. code-block:: text
231+
232+
*.trlc
233+
└─ trlc_rst (Bazel rule, @trlc)
234+
└─ requirements_rst.rst (.. requirement:definition:: <ID> ...)
235+
└─ Sphinx HTML builder (resolves {requirement:downstream-ref})
236+
237+
Before the HTML build starts, ``sphinx_module_ext.py`` reads the aggregated
238+
``needs_external_needs.json``
239+
(written by the Bazel rule from all incoming ``SphinxNeedsInfo`` providers) and
240+
populates the ``needs_external_needs`` Sphinx configuration key. This tells
241+
``sphinx-needs`` where to find the ``needs.json`` of each dependency and what
242+
base URL to use for generated hyperlinks, so a ``{requirement:downstream-ref}``
243+
role in a spec file can link directly to the requirement definition page in the
244+
dependency's HTML.
245+
246+
After the HTML build, ``src/sphinx_html_merge.py`` copies each dependency's
247+
output directory into ``<name>/html/<dep-name>/`` so the final site is
248+
self-contained.
249+
250+
.. code-block:: text
251+
252+
deps[*].needs.json ──► needs_external_needs.json
253+
254+
sources (all relocated) ───────┤
255+
256+
Sphinx HTML builder
257+
258+
<name>/_html/ ──► sphinx_html_merge
259+
260+
<name>/html/
261+
├── index.html
262+
├── dep1/ ← merged
263+
└── dep2/ ← merged

bazel/rules/rules_score/private/sphinx_module.bzl

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,15 @@ def _score_needs_impl(ctx):
8484
# Get config file (generate or use provided)
8585
config_file = _create_config_py(ctx)
8686

87-
# Phase 1: Build needs.json (without external needs)
87+
# Phase 1: Build needs.json (without external needs).
88+
# The needs builder (sphinx-needs NeedsBuilder) only collects `.. need::`
89+
# directives — it is blind to the custom trlc `RequirementsDomain` and its
90+
# `.. requirement:definition::` directives. Generated/external files
91+
# (renamed_srcs, docs_library_deps) are therefore not needed here. Their
92+
# toctree entries would produce toc.not_readable warnings because Sphinx's
93+
# source root is the original docs/ checkout; those are suppressed in
94+
# conf.template.py (safe: the HTML phase relocates everything so it never
95+
# emits toc.not_readable).
8896
needs_inputs = ctx.files.srcs + [config_file]
8997
needs_args = [
9098
"--index_file",

bazel/rules/rules_score/templates/conf.template.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,17 @@
6969
"**/*_design",
7070
]
7171

72+
# Suppress toctree warnings for documents absent from the needs builder's source
73+
# tree. The needs builder runs against only the static docs/ checkout; generated
74+
# files (trlc_rst outputs, renamed_srcs, docs_library_deps) live in bazel-out/
75+
# and are invisible to it. Their toctree references produce toc.not_readable
76+
# warnings that are cosmetic: the needs builder (sphinx-needs NeedsBuilder)
77+
# captures only `.. need::` directives, not trlc `.. requirement:definition::`
78+
# directives, so needs.json content is unaffected by missing files.
79+
# This suppression is safe for the HTML phase because that phase relocates every
80+
# file into a unified staging directory, so it never encounters toc.not_readable.
81+
suppress_warnings = ["toc.not_readable"]
82+
7283
# Enable markdown rendering
7384
source_suffix = {
7485
".rst": "restructuredtext",

0 commit comments

Comments
 (0)