Skip to content

Commit aa03fc8

Browse files
committed
Support remapping into runfiles tree when requested
1 parent 5b8e0c8 commit aa03fc8

File tree

2 files changed

+73
-5
lines changed

2 files changed

+73
-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: 60 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,30 @@ 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+
return filePath;
79+
}
80+
5781
async function resolveInExecroot({
5882
build,
5983
bindir,
6084
execroot,
85+
runfiles,
6186
importPath,
6287
otherOptions,
6388
}: ResolveInExecrootOptions): Promise<OnResolveResult> {
@@ -85,8 +110,39 @@ async function resolveInExecroot({
85110
`Error: esbuild resolved a path outside of BAZEL_BINDIR (${bindir}): ${result.path}`,
86111
);
87112
}
88-
// Otherwise remap the bindir-relative path
89-
const correctedPath = join(execroot, result.path.substring(result.path.indexOf(bindir)));
113+
// Get the path under the bindir for the file. This allows us to map into
114+
// the execroot or the runfiles directory (if present).
115+
// Example:
116+
// bindir = bazel-out/<arch>/bin
117+
// result.path = <base>/execroot/bazel-out/<arch>/bin/external/repo+/path/file.ts
118+
// binDirRelativePath = external/repo+/path/file.ts
119+
const binDirRelativePath = result.path.substring(
120+
result.path.indexOf(bindir) + bindir.length + 1,
121+
);
122+
// We usually remap into the bindir. However, when sources are provided
123+
// as `data` (runfiles), they will be in the runfiles root instead. The
124+
// runfiles path is absolute and under the bindir, so we don't need to
125+
// join anything to it. The execroot does not include the bindir, so there
126+
// we add it again after previously removing it from the result path.
127+
const remapBase = runfiles ?? path.join(execroot, bindir);
128+
// The path relative to the remapBase also differs between runfiles and
129+
// bindir, but only if the file is in an external repository. External
130+
// repositories appear under `external/repo+` in the bindir, whereas they
131+
// are directly under `repo+` in the runfiles tree. This difference needs
132+
// to be accounted for by removing a potential `external/` prefix when
133+
// mapping into runfiles.
134+
const remapBaseRelativePath = runfiles
135+
? removeExternalPathPrefix(binDirRelativePath)
136+
: binDirRelativePath;
137+
// Join the paths back together. The results will look slightly different
138+
// between runfiles and bindir, but this is intentional.
139+
// Source path:
140+
// <bin>/external/repo+/path/file.ts
141+
// Example in bindir:
142+
// <sandbox-bin>/external/repo+/path/file.ts
143+
// Example in runfiles:
144+
// <sandbox-bin>/path/bin.runfiles/repo+/path/file.ts
145+
const correctedPath = join(remapBase, remapBaseRelativePath);
90146
if (process.env.JS_BINARY__LOG_DEBUG) {
91147
// eslint-disable-next-line no-console
92148
console.error(

0 commit comments

Comments
 (0)