Skip to content

Commit 9e46123

Browse files
committed
Support remapping into runfiles tree when requested
1 parent 938480e commit 9e46123

File tree

2 files changed

+74
-5
lines changed

2 files changed

+74
-5
lines changed

packages/angular/build/src/tools/esbuild/application-code-bundle.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,8 +616,20 @@ function getEsBuildCommonOptions(options: NormalizedApplicationBuildOptions): Bu
616616
) {
617617
const bindir = process.env.BAZEL_BINDIR;
618618
const execroot = process.env.JS_BINARY__EXECROOT;
619+
620+
let runfiles: string | undefined;
621+
// If requested, remap paths to the runfiles tree in the sandbox instead of the bindir
622+
// directly. This allows `js_binary` and `js_test` rules to invoke the Angular CLI against
623+
// their runfiles.
624+
if (
625+
process.env.BAZEL_SANDBOX_PLUGIN_REMAP_TO_RUNFILES === '1' ||
626+
process.env.BAZEL_SANDBOX_PLUGIN_REMAP_TO_RUNFILES === 'true'
627+
) {
628+
runfiles = process.env.JS_BINARY__RUNFILES;
629+
}
630+
619631
if (bindir && execroot) {
620-
plugins.push(createBazelSandboxPlugin({ bindir, execroot }));
632+
plugins.push(createBazelSandboxPlugin({ bindir, execroot, runfiles }));
621633
}
622634
}
623635

packages/angular/build/src/tools/esbuild/sandbox-plugin-bazel.ts

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@
1212

1313
import type { OnResolveResult, Plugin, PluginBuild, ResolveOptions } from 'esbuild';
1414
import { stat } from 'node:fs/promises';
15-
import { join } from 'node:path';
15+
import path, { join } from 'node:path';
1616

1717
export interface CreateBazelSandboxPluginOptions {
1818
bindir: string;
1919
execroot: string;
20+
runfiles?: string;
2021
}
2122

2223
// Under Bazel, esbuild will follow symlinks out of the sandbox when the sandbox is enabled. See https://github.com/aspect-build/rules_esbuild/issues/58.
@@ -25,6 +26,7 @@ export interface CreateBazelSandboxPluginOptions {
2526
export function createBazelSandboxPlugin({
2627
bindir,
2728
execroot,
29+
runfiles,
2830
}: CreateBazelSandboxPluginOptions): Plugin {
2931
return {
3032
name: 'bazel-sandbox',
@@ -40,7 +42,14 @@ export function createBazelSandboxPlugin({
4042
}
4143
otherOptions.pluginData.executedSandboxPlugin = true;
4244

43-
return await resolveInExecroot({ build, bindir, execroot, importPath, otherOptions });
45+
return await resolveInExecroot({
46+
build,
47+
bindir,
48+
execroot,
49+
runfiles,
50+
importPath,
51+
otherOptions,
52+
});
4453
});
4554
},
4655
};
@@ -50,14 +59,31 @@ interface ResolveInExecrootOptions {
5059
build: PluginBuild;
5160
bindir: string;
5261
execroot: string;
62+
runfiles?: string;
5363
importPath: string;
5464
otherOptions: ResolveOptions;
5565
}
5666

67+
const EXTERNAL_PREFIX = 'external/';
68+
69+
function removeExternalPathPrefix(filePath: string): string {
70+
// Normalize to relative path without leading slash.
71+
if (filePath.startsWith('/')) {
72+
filePath = filePath.substring(1);
73+
}
74+
// Remove the EXTERNAL_PREFIX if present.
75+
if (filePath.startsWith(EXTERNAL_PREFIX)) {
76+
filePath = filePath.substring(EXTERNAL_PREFIX.length);
77+
}
78+
79+
return filePath;
80+
}
81+
5782
async function resolveInExecroot({
5883
build,
5984
bindir,
6085
execroot,
86+
runfiles,
6187
importPath,
6288
otherOptions,
6389
}: ResolveInExecrootOptions): Promise<OnResolveResult> {
@@ -85,8 +111,39 @@ async function resolveInExecroot({
85111
`Error: esbuild resolved a path outside of BAZEL_BINDIR (${bindir}): ${result.path}`,
86112
);
87113
}
88-
// Otherwise remap the bindir-relative path
89-
const correctedPath = join(execroot, result.path.substring(result.path.indexOf(bindir)));
114+
// Get the path under the bindir for the file. This allows us to map into
115+
// the execroot or the runfiles directory (if present).
116+
// Example:
117+
// bindir = bazel-out/<arch>/bin
118+
// result.path = <base>/execroot/bazel-out/<arch>/bin/external/repo+/path/file.ts
119+
// binDirRelativePath = external/repo+/path/file.ts
120+
const binDirRelativePath = result.path.substring(
121+
result.path.indexOf(bindir) + bindir.length + 1,
122+
);
123+
// We usually remap into the bindir. However, when sources are provided
124+
// as `data` (runfiles), they will be in the runfiles root instead. The
125+
// runfiles path is absolute and under the bindir, so we don't need to
126+
// join anything to it. The execroot does not include the bindir, so there
127+
// we add it again after previously removing it from the result path.
128+
const remapBase = runfiles ?? path.join(execroot, bindir);
129+
// The path relative to the remapBase also differs between runfiles and
130+
// bindir, but only if the file is in an external repository. External
131+
// repositories appear under `external/repo+` in the bindir, whereas they
132+
// are directly under `repo+` in the runfiles tree. This difference needs
133+
// to be accounted for by removing a potential `external/` prefix when
134+
// mapping into runfiles.
135+
const remapBaseRelativePath = runfiles
136+
? removeExternalPathPrefix(binDirRelativePath)
137+
: binDirRelativePath;
138+
// Join the paths back together. The results will look slightly different
139+
// between runfiles and bindir, but this is intentional.
140+
// Source path:
141+
// <bin>/external/repo+/path/file.ts
142+
// Example in bindir:
143+
// <sandbox-bin>/external/repo+/path/file.ts
144+
// Example in runfiles:
145+
// <sandbox-bin>/path/bin.runfiles/repo+/path/file.ts
146+
const correctedPath = join(remapBase, remapBaseRelativePath);
90147
if (process.env.JS_BINARY__LOG_DEBUG) {
91148
// eslint-disable-next-line no-console
92149
console.error(

0 commit comments

Comments
 (0)