Skip to content

Commit

Permalink
fix(runfiles): support bzlmod repo mappings
Browse files Browse the repository at this point in the history
  • Loading branch information
jbedard committed Aug 19, 2024
1 parent ab85b37 commit 09d0738
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 1 deletion.
4 changes: 4 additions & 0 deletions packages/runfiles/paths.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// NB: on windows thanks to legacy 8-character path segments it might be like
// c:/b/ojvxx6nx/execroot/build_~1/bazel-~1/x64_wi~1/bin/internal/npm_in~1/test
export const BAZEL_OUT_REGEX = /(\/bazel-out\/|\/bazel-~1\/x64_wi~1\/)/;

// The runfiles root symlink under which the repository mapping can be found.
// https://cs.opensource.google/bazel/bazel/+/1b073ac0a719a09c9b2d1a52680517ab22dc971e:src/main/java/com/google/devtools/build/lib/analysis/Runfiles.java;l=424
export const REPO_MAPPING_RLOCATION = "_repo_mapping";
36 changes: 35 additions & 1 deletion packages/runfiles/runfiles.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as fs from 'fs';
import * as path from 'path';

import {BAZEL_OUT_REGEX} from './paths';
import {BAZEL_OUT_REGEX, REPO_MAPPING_RLOCATION} from './paths';

/**
* Class that provides methods for resolving Bazel runfiles.
Expand All @@ -17,6 +17,10 @@ export class Runfiles {
* If the environment gives us enough hints, we can know the package path
*/
package: string|undefined;
/**
* If the environment has repo mappings, we can use them to resolve repo relative paths.
*/
repoMappings: Map<string, string>|undefined;

constructor(private _env: typeof process.env) {
// If Bazel sets a variable pointing to a runfiles manifest,
Expand All @@ -29,8 +33,10 @@ export class Runfiles {
this.manifest = this.loadRunfilesManifest(_env['RUNFILES_MANIFEST_FILE']!);
} else if (!!_env['RUNFILES_DIR']) {
this.runfilesDir = path.resolve(_env['RUNFILES_DIR']!);
this.repoMappings = this.loadRepoMapping(this.runfilesDir);
} else if (!!_env['RUNFILES']) {
this.runfilesDir = path.resolve(_env['RUNFILES']!);
this.repoMappings = this.loadRepoMapping(this.runfilesDir);
} else {
throw new Error(
'Every node program run under Bazel must have a $RUNFILES_DIR, $RUNFILES or $RUNFILES_MANIFEST_FILE environment variable');
Expand Down Expand Up @@ -116,6 +122,25 @@ export class Runfiles {
return runfilesEntries;
}

loadRepoMapping(runfilesDir: string): Map<string, string>|undefined {
const repoMappingPath = path.join(runfilesDir, REPO_MAPPING_RLOCATION);

if (fs.existsSync(repoMappingPath)) {
const repoMappings = new Map<string, string>()
const mappings = fs.readFileSync(repoMappingPath, {encoding: 'utf-8'});
for (const line of mappings.split('\n')) {
if (!line) continue;
const [from, repoName, repoPath] = line.split(',');

// TODO: from !== ''?
if (from === '') {
repoMappings.set(repoName, repoPath);
}
}
return repoMappings;
}
}

/** Resolves the given module path. */
resolve(modulePath: string) {
// Normalize path by converting to forward slashes and removing all trailing
Expand Down Expand Up @@ -189,6 +214,15 @@ export class Runfiles {
}
}
}
if (this.repoMappings && this.repoMappings.has(moduleBase)) {
const mappedRepo = this.repoMappings.get(moduleBase)
if (mappedRepo !== moduleBase) {
const maybe = this._resolve(mappedRepo, moduleTail)
if (maybe !== undefined) {
return maybe;
}
}
}
if (this.runfilesDir) {
const maybe = path.join(this.runfilesDir, moduleBase, moduleTail || '');
if (fs.existsSync(maybe)) {
Expand Down

0 comments on commit 09d0738

Please sign in to comment.