diff --git a/packages/angular/build/src/tools/esbuild/angular/rewrite-bazel-paths.ts b/packages/angular/build/src/tools/esbuild/angular/rewrite-bazel-paths.ts index 8a6fb6aa82a4..b7cd376d560e 100644 --- a/packages/angular/build/src/tools/esbuild/angular/rewrite-bazel-paths.ts +++ b/packages/angular/build/src/tools/esbuild/angular/rewrite-bazel-paths.ts @@ -6,25 +6,55 @@ * found in the LICENSE file at https://angular.dev/license */ -import { join, relative } from 'node:path'; +import { join, relative, sep } from 'node:path'; const bazelBinDirectory = process.env['BAZEL_BINDIR']; const bazelExecRoot = process.env['JS_BINARY__EXECROOT']; +const execRootMarker = `${sep}execroot${sep}`; + +/** + * Sandboxed actions run in a copy of the execroot whose absolute path differs from + * `JS_BINARY__EXECROOT`, so the effective execroot is derived from the working directory. + */ +function effectiveExecRoot(): string | undefined { + const cwd = process.cwd(); + const markerIndex = cwd.indexOf(execRootMarker); + if (markerIndex === -1) { + return bazelExecRoot; + } + + const workspaceEnd = cwd.indexOf(sep, markerIndex + execRootMarker.length); + + return workspaceEnd === -1 ? cwd : cwd.slice(0, workspaceEnd); +} export function rewriteForBazel(path: string): string { if (!bazelBinDirectory || !bazelExecRoot) { return path; } - const fromExecRoot = relative(bazelExecRoot, path); + const execRoot = effectiveExecRoot() ?? bazelExecRoot; + + const fromExecRoot = relative(execRoot, path); if (!fromExecRoot.startsWith('..')) { return path; } const fromBinDirectory = relative(bazelBinDirectory, path); - if (fromBinDirectory.startsWith('..')) { - return path; + if (!fromBinDirectory.startsWith('..')) { + return join(execRoot, fromBinDirectory); + } + + // A path that realpath resolved out of a symlink-staged sandbox into the + // unsandboxed execroot: re-anchor its execroot-relative tail. + const markerIndex = path.indexOf(execRootMarker); + if (markerIndex !== -1) { + const tail = path.slice(markerIndex + execRootMarker.length); + const workspaceEnd = tail.indexOf(sep); + if (workspaceEnd !== -1) { + return join(execRoot, tail.slice(workspaceEnd + 1)); + } } - return join(bazelExecRoot, fromBinDirectory); + return path; }