@@ -126,12 +126,15 @@ async function resolveRoot(root: string|undefined, runfiles: Runfiles) {
126126export class Runfiles {
127127 manifest : Map < string , string > | undefined ;
128128 dir : string | undefined ;
129- noBin : boolean ;
129+ execroot : boolean ;
130130 /**
131- * If the environment gives us enough hints, we can know the path to the package
132- * in the form workspace_name/path/to/package
131+ * If the environment gives us enough hints, we can know the workspace name
133132 */
134- packagePath : string | undefined ;
133+ workspace : string | undefined ;
134+ /**
135+ * If the environment gives us enough hints, we can know the package path
136+ */
137+ package : string | undefined ;
135138
136139 constructor ( env : typeof process . env ) {
137140 // If Bazel sets a variable pointing to a runfiles manifest,
@@ -159,18 +162,21 @@ export class Runfiles {
159162 If you want to test runfiles manifest behavior, add
160163 --spawn_strategy=standalone to the command line.` ) ;
161164 }
162-
163- const wksp = env [ 'TEST_WORKSPACE' ] ;
164- const target = env [ 'TEST_TARGET' ] ;
165- if ( ! ! wksp && ! ! target ) {
166- // //path/to:target -> //path/to
167- const pkg = target . split ( ':' ) [ 0 ] ;
168- this . packagePath = path . posix . join ( wksp , pkg ) ;
165+ const wksp = env [ 'BAZEL_WORKSPACE' ] ;
166+ if ( ! ! wksp ) {
167+ this . workspace = wksp ;
169168 }
170-
171- // If under runfiles (and not unit testing) then don't add a bin to taget for bin links
172- this . noBin = ! ! env [ 'TEST_TARGET' ] && wksp !== 'build_bazel_rules_nodejs' &&
173- target !== '//internal/linker/test:unit_tests' ;
169+ // If target is from an external workspace such as @npm //rollup/bin:rollup
170+ // resolvePackageRelative is not supported since package is in an external
171+ // workspace.
172+ const target = env [ 'BAZEL_TARGET' ] ;
173+ if ( ! ! target && ! target . startsWith ( '@' ) ) {
174+ // //path/to:target -> path/to
175+ this . package = target . split ( ':' ) [ 0 ] . replace ( / ^ \/ \/ / , '' ) ;
176+ }
177+ // We can derive if the process is being run in the execroot
178+ // if there is a bazel-out folder at the cwd.
179+ this . execroot = existsSync ( 'bazel-out' ) ;
174180 }
175181
176182 lookupDirectory ( dir : string ) : string | undefined {
@@ -228,11 +234,29 @@ export class Runfiles {
228234 throw new Error ( `could not resolve modulePath ${ modulePath } ` ) ;
229235 }
230236
237+ resolveWorkspaceRelative ( modulePath : string ) {
238+ if ( ! this . workspace ) {
239+ throw new Error ( 'workspace could not be determined from the environment' ) ;
240+ }
241+ return this . resolve ( path . posix . join ( this . workspace , modulePath ) ) ;
242+ }
243+
231244 resolvePackageRelative ( modulePath : string ) {
232- if ( ! this . packagePath ) {
233- throw new Error ( 'packagePath could not be determined from the environment' ) ;
245+ if ( ! this . workspace ) {
246+ throw new Error ( 'workspace could not be determined from the environment' ) ;
247+ }
248+ if ( ! this . package ) {
249+ throw new Error ( 'package could not be determined from the environment' ) ;
250+ }
251+ return this . resolve ( path . posix . join ( this . workspace , this . package , modulePath ) ) ;
252+ }
253+
254+ patchRequire ( ) {
255+ const requirePatch = process . env [ 'BAZEL_NODE_PATCH_REQUIRE' ] ;
256+ if ( ! requirePatch ) {
257+ throw new Error ( 'require patch location could not be determined from the environment' ) ;
234258 }
235- return this . resolve ( path . posix . join ( this . packagePath , modulePath ) ) ;
259+ require ( requirePatch ) ;
236260 }
237261}
238262
@@ -257,6 +281,18 @@ async function exists(p: string) {
257281 }
258282}
259283
284+ function existsSync ( p : string ) {
285+ try {
286+ fs . statSync ( p )
287+ return true ;
288+ } catch ( e ) {
289+ if ( e . code === 'ENOENT' ) {
290+ return false ;
291+ }
292+ throw e ;
293+ }
294+ }
295+
260296/**
261297 * Given a set of module aliases returns an array of recursive `LinkerTreeElement`.
262298 *
@@ -491,9 +527,11 @@ export async function main(args: string[], runfiles: Runfiles) {
491527 let target : string = '<package linking failed>' ;
492528 switch ( root ) {
493529 case 'bin' :
530+ // If we are in the execroot then add the bin path to the target; otherwise
531+ // we are in runfiles and the bin path should be omitted.
494532 // FIXME(#1196)
495- target = runfiles . noBin ? path . join ( workspaceAbs , toWorkspaceDir ( modulePath ) ) :
496- path . join ( workspaceAbs , bin , toWorkspaceDir ( modulePath ) ) ;
533+ target = runfiles . execroot ? path . join ( workspaceAbs , bin , toWorkspaceDir ( modulePath ) ) :
534+ path . join ( workspaceAbs , toWorkspaceDir ( modulePath ) ) ;
497535 break ;
498536 case 'src' :
499537 target = path . join ( workspaceAbs , toWorkspaceDir ( modulePath ) ) ;
0 commit comments