eclipse-score / eclipse-score/tooling
PlantUML SVG rendering under --remote_download_minimal: sysroot/font resolution relies on fragile runtime glob + non-hermetic tempfile, not rule-level dependency
- Dominant language
- Rust
- Stars
- 8
- Forks
- 37
- Avg merge
- 2d 13h
- Merged PRs (30d)
- 22
Description
### Problem
`sphinx_module`'s PlantUML rendering crashes on CI (RBE with `--remote_download_minimal`) with:
```
RuntimeException: Fontconfig head is null, check your fonts or fonts configuration
```
thrown by `sun.awt.FontConfiguration.readFontConfigFile()`. Root cause: the hermetic JDK toolchain (`remotejdk21_linux`) ships no `$JAVA_HOME/conf/fonts/fontconfig.properties`, so it always falls into a native auto-generation path that crashes in the fontless build sandbox. This is unrelated to Linux `fonts.conf`/`FONTCONFIG_FILE` — confirmed setting that env var has zero effect on this JDK-internal mechanism.
A working fix was prototyped downstream in `conf.template.py` via the documented `-Dsun.awt.fontconfig=` JVM flag, pointed at a minimal properties file referencing a DejaVu font from the same sysroot `dot` already uses via `exec_in_sysroot`/fakechroot. That prototype confirmed the approach resolves the crash and restores SVG rendering, but its implementation has known soundness gaps described below.
### Why the prototype is a workaround, not a sound fix
1. **Sysroot path discovery is glob-based, not a real dependency edge.** The prototype searches `graphviz_dot + ".runfiles"` recursively for a directory literally named `dot_sysroot`. This only works because of a naming convention in `exec_in_sysroot.bzl` (`"_sysroot"`), not because the Sphinx build target actually declares a dependency on the sysroot. Any rename/refactor of `exec_in_sysroot` silently breaks font resolution.
2. **Root architectural gap**: the Sphinx doc action depends on `dot` (the launcher) but not on `dot_sysroot` (the TreeArtifact) directly. Under `--remote_download_minimal`, `dot_sysroot` is therefore not staged as a bazel-out sibling and is only reachable via `dot`'s own runfiles — an implementation detail of `exec_in_sysroot`'s launcher, not a contract.
3. **Non-hermetic runtime side effect**: the prototype calls `tempfile.mkdtemp()` and writes `fontconfig.properties` at Sphinx-build Python-execution time, outside Bazel's action graph. Not cached, not sandboxed, not reproducible as a build artifact.
4. **Hardcoded single font**: assumes `DejaVuSans.ttf` exists at a fixed path inside the sysroot and maps it to a made-up subset name (`alphabetic`) rather than the standard JDK logical-font mapping (`serif`/`sansserif`/`monospaced`/`dialog`/`dialoginput`). Silently breaks if the `graphviz` apt package's font deps change.
### Suggested fix
- Add an explicit provider/attribute from `exec_in_sysroot` (or the `dot`-producing rule) exposing the sysroot's `File`/`TreeArtifact` directly to consumers — e.g. a `SysrootInfo` provider with a `root` field — instead of relying on runfiles-directory-naming conventions.
- Wire the Sphinx/PlantUML build rule to declare an explicit `data`/dep on that sysroot (same pattern already used for other build-time env vars passed to `conf.py`), so it's staged correctly under `--remote_download_minimal` without glob search.
- Generate `fontconfig.properties` as a genrule/build action (tracked Bazel output), not at Python runtime in `conf.py`. Pass its path in via an env var set by the rule.
- Use the standard JDK logical-font mapping (`serif`, `sansserif`, `monospaced`, `dialog`, `dialoginput` → real font files) instead of a single custom `alphabetic` subset, so it degrades more gracefully if font files change.
### References
- JDK font-configuration-files spec: https://docs.oracle.com/en/java/javase/17/intl/font-configuration-files.html
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with conf.template.py and exec_in_sysroot.bzl, then trace the Sphinx/PlantUML build rule and the remotejdk21_linux toolchain under --remote_download_minimal. Determine how the sysroot is currently exposed and staged. Done means the rule has an explicit sysroot dependency, a generated font configuration artifact, standard JDK logical-font mappings, and CI SVG rendering succeeds without runtime globbing or temporary files.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, python
- Domain
- build-system, documentation, tooling
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100