Skip to content

fix(project): Route Theme-Library Resources in BuildReader - #1611

Merged
RandomByte merged 2 commits into
mainfrom
fix/build-reader-getReaderForResource
Sep 24, 2026
Merged

RandomByte merged 2 commits into
mainfrom
fix/build-reader-getReaderForResource

Conversation

@RandomByte

Copy link
Copy Markdown
Member

Summary

Theme libraries have no namespace and serve their resources under a path owned by another project, for example themelib_sap_horizon serves /resources/sap/ui/core/themes/sap_horizon/library.css. BuildReader routed such a request by walking the path and matching the sap/ui/core namespace of the sap.ui.core library, which does not own the resource. The read returned null, so the reader fell back to requesting a reader for every project. That fallback (re)builds every non-fresh project, including libraries such as sap.m that have nothing to do with the theme.

Problem

BuildReader.byPath used a single best-guess reader from _getReaderForResource, then a single fallback to a reader for all projects. Namespace matching is path-based, so a theme resource served under another project's namespace segment resolves to the wrong project, reads null, and drops straight to the all-projects fallback. Requesting a reader for all projects is the expensive path: it (re)builds every stale project in the graph, so a single theme request could trigger unrelated builds.

Fix

Replace the single best-guess reader with an ordered list of candidate reader factories, evaluated lazily by byPath, returning the first resource found. A reader is requested from the build server only when the preceding candidates did not yield the resource, so the minimal set of projects is built.

The candidate order, most specific and cheapest first:

  1. Cached readers of already-built projects. Free to query, and a hit identifies the owning project without building anything.
  2. Namespace matches, most specific first.
  3. Theme libraries, when the path has a themes/ segment. Theme libraries are tracked separately at construction time because they have no namespace to match on.
  4. The application root project, for paths outside /resources/ and /test-resources/.
  5. All projects. Last resort, reached only when no more specific strategy located the resource.

The base theme, owned by sap.ui.core itself, still resolves at the namespace step (2) and builds no theme library.

Naming

_getReaderForResource returned a single reader; the new method returns the ordered candidate list and is named _getReaderCandidates.

Testing

An integration-style harness records which projects a single byPath request would build, standing in for the build the BuildServer triggers for a non-fresh project. Three tests cover the routing:

  • A colliding theme resource (themelib_sap_horizon under the sap.ui.core namespace) resolves from the theme library, and unrelated projects (sap.m, the application) are not built.
  • A base-theme resource resolves from its owning library without building any theme library.
  • A non-colliding theme resource routes to its theme library without falling back to all projects.

The two theme-library routing tests were added first and failed against the previous fallback-to-all behavior. The base-theme test passed before the fix and still passes.

A theme library contributes resources under a path that can collide with
another project's namespace: themelib_sap_horizon has no namespace and serves
/resources/sap/ui/core/themes/sap_horizon/library.css. BuildReader walks that
path, matches the sap/ui/core namespace of the sap.ui.core library (which does
not own the resource), reads null, then falls back to a reader for every
project. That fallback (re)builds unrelated stale projects such as sap.m.

Add an integration-style harness that records which projects a single byPath
request would build, and three tests: the colliding theme resource, the base
theme (owned by the library itself), and a non-colliding theme resource. The
two theme-library routing tests fail against the current fallback-to-all
behavior. The base-theme test already passes.
@RandomByte
RandomByte marked this pull request as ready for review September 24, 2026 12:57
@RandomByte
RandomByte force-pushed the fix/build-reader-getReaderForResource branch from 989760a to 755539a Compare September 24, 2026 13:12
Theme libraries have no namespace and serve their resources under a path owned
by another project, e.g. themelib_sap_horizon serves
/resources/sap/ui/core/themes/sap_horizon/library.css. The previous routing
matched such a path to the sap/ui/core namespace of the sap.ui.core library,
read null there, then requested a reader for every project. That request
(re)builds every non-fresh project, including ones unrelated to the theme.

Replace the single best-guess reader with an ordered list of candidate reader
factories evaluated lazily by byPath, returning the first resource found:

  1. cached readers of already-built projects (free, identifies the owner)
  2. namespace matches, most specific first
  3. theme libraries, when the path has a themes/ segment
  4. the application root project, for non-/resources paths
  5. all projects (last resort)

A reader is requested from the build server only when the preceding candidates
did not yield the resource, so the minimal set of projects is built. The base
theme, owned by sap.ui.core itself, still resolves at the namespace step
without building any theme library.
@RandomByte
RandomByte force-pushed the fix/build-reader-getReaderForResource branch from 755539a to 6c2cea6 Compare September 24, 2026 13:19
@RandomByte
RandomByte requested a review from a team September 24, 2026 14:15
@RandomByte
RandomByte merged commit af31b26 into main Sep 24, 2026
131 of 133 checks passed
@RandomByte
RandomByte deleted the fix/build-reader-getReaderForResource branch September 24, 2026 14:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants