1717import static java .util .stream .Collectors .joining ;
1818
1919import com .google .common .annotations .VisibleForTesting ;
20+ import com .google .common .base .Preconditions ;
2021import com .google .common .base .Supplier ;
2122import com .google .common .base .Suppliers ;
2223import com .google .common .collect .ImmutableCollection ;
2627import com .google .common .collect .Maps ;
2728import com .google .common .collect .Sets ;
2829import com .google .devtools .build .lib .actions .Artifact ;
30+ import com .google .devtools .build .lib .analysis .LocationExpander .LocationFunction .PathType ;
2931import com .google .devtools .build .lib .cmdline .Label ;
32+ import com .google .devtools .build .lib .cmdline .LabelConstants ;
3033import com .google .devtools .build .lib .cmdline .LabelSyntaxException ;
3134import com .google .devtools .build .lib .cmdline .RepositoryMapping ;
3235import com .google .devtools .build .lib .packages .BuildType ;
@@ -63,34 +66,35 @@ public final class LocationExpander {
6366 private static final boolean EXACTLY_ONE = false ;
6467 private static final boolean ALLOW_MULTIPLE = true ;
6568
66- private static final boolean USE_LOCATION_PATHS = false ;
67- private static final boolean USE_EXEC_PATHS = true ;
68-
6969 private final RuleErrorConsumer ruleErrorConsumer ;
7070 private final ImmutableMap <String , LocationFunction > functions ;
7171 private final RepositoryMapping repositoryMapping ;
72+ private final String workspaceRunfilesDirectory ;
7273
7374 @ VisibleForTesting
7475 LocationExpander (
7576 RuleErrorConsumer ruleErrorConsumer ,
7677 Map <String , LocationFunction > functions ,
77- RepositoryMapping repositoryMapping ) {
78+ RepositoryMapping repositoryMapping ,
79+ String workspaceRunfilesDirectory ) {
7880 this .ruleErrorConsumer = ruleErrorConsumer ;
7981 this .functions = ImmutableMap .copyOf (functions );
8082 this .repositoryMapping = repositoryMapping ;
83+ this .workspaceRunfilesDirectory = workspaceRunfilesDirectory ;
8184 }
8285
8386 private LocationExpander (
84- RuleErrorConsumer ruleErrorConsumer ,
87+ RuleContext ruleContext ,
8588 Label root ,
8689 Supplier <Map <Label , Collection <Artifact >>> locationMap ,
8790 boolean execPaths ,
8891 boolean legacyExternalRunfiles ,
8992 RepositoryMapping repositoryMapping ) {
9093 this (
91- ruleErrorConsumer ,
94+ ruleContext ,
9295 allLocationFunctions (root , locationMap , execPaths , legacyExternalRunfiles ),
93- repositoryMapping );
96+ repositoryMapping ,
97+ ruleContext .getWorkspaceName ());
9498 }
9599
96100 /**
@@ -215,7 +219,10 @@ private String expand(String value, ErrorReporter reporter) {
215219 // (2) Call appropriate function to obtain string replacement.
216220 String functionValue = value .substring (nextWhitespace + 1 , end ).trim ();
217221 try {
218- String replacement = functions .get (fname ).apply (functionValue , repositoryMapping );
222+ String replacement =
223+ functions
224+ .get (fname )
225+ .apply (functionValue , repositoryMapping , workspaceRunfilesDirectory );
219226 result .append (replacement );
220227 } catch (IllegalStateException ise ) {
221228 reporter .report (ise .getMessage ());
@@ -230,23 +237,29 @@ private String expand(String value, ErrorReporter reporter) {
230237
231238 @ VisibleForTesting
232239 static final class LocationFunction {
240+ enum PathType {
241+ LOCATION ,
242+ EXEC ,
243+ RLOCATION ,
244+ }
245+
233246 private static final int MAX_PATHS_SHOWN = 5 ;
234247
235248 private final Label root ;
236249 private final Supplier <Map <Label , Collection <Artifact >>> locationMapSupplier ;
237- private final boolean execPaths ;
250+ private final PathType pathType ;
238251 private final boolean legacyExternalRunfiles ;
239252 private final boolean multiple ;
240253
241254 LocationFunction (
242255 Label root ,
243256 Supplier <Map <Label , Collection <Artifact >>> locationMapSupplier ,
244- boolean execPaths ,
257+ PathType pathType ,
245258 boolean legacyExternalRunfiles ,
246259 boolean multiple ) {
247260 this .root = root ;
248261 this .locationMapSupplier = locationMapSupplier ;
249- this .execPaths = execPaths ;
262+ this .pathType = Preconditions . checkNotNull ( pathType ) ;
250263 this .legacyExternalRunfiles = legacyExternalRunfiles ;
251264 this .multiple = multiple ;
252265 }
@@ -257,10 +270,13 @@ static final class LocationFunction {
257270 * using the {@code repositoryMapping}.
258271 *
259272 * @param arg The label-like string to be expanded, e.g. ":foo" or "//foo:bar"
260- * @param repositoryMapping map of {@code RepositoryName}s defined in the main workspace
273+ * @param repositoryMapping map of apparent repository names to {@code RepositoryName}s
274+ * @param workspaceRunfilesDirectory name of the runfiles directory corresponding to the main
275+ * repository
261276 * @return The expanded value
262277 */
263- public String apply (String arg , RepositoryMapping repositoryMapping ) {
278+ public String apply (
279+ String arg , RepositoryMapping repositoryMapping , String workspaceRunfilesDirectory ) {
264280 Label label ;
265281 try {
266282 label = root .getRelativeWithRemapping (arg , repositoryMapping );
@@ -269,14 +285,13 @@ public String apply(String arg, RepositoryMapping repositoryMapping) {
269285 String .format (
270286 "invalid label in %s expression: %s" , functionName (), e .getMessage ()), e );
271287 }
272- Collection <String > paths = resolveLabel (label );
288+ Set <String > paths = resolveLabel (label , workspaceRunfilesDirectory );
273289 return joinPaths (paths );
274290 }
275291
276- /**
277- * Returns all target location(s) of the given label.
278- */
279- private Collection <String > resolveLabel (Label unresolved ) throws IllegalStateException {
292+ /** Returns all target location(s) of the given label. */
293+ private Set <String > resolveLabel (Label unresolved , String workspaceRunfilesDirectory )
294+ throws IllegalStateException {
280295 Collection <Artifact > artifacts = locationMapSupplier .get ().get (unresolved );
281296
282297 if (artifacts == null ) {
@@ -286,7 +301,7 @@ private Collection<String> resolveLabel(Label unresolved) throws IllegalStateExc
286301 unresolved , functionName ()));
287302 }
288303
289- Set <String > paths = getPaths (artifacts );
304+ Set <String > paths = getPaths (artifacts , workspaceRunfilesDirectory );
290305 if (paths .isEmpty ()) {
291306 throw new IllegalStateException (
292307 String .format (
@@ -311,24 +326,41 @@ private Collection<String> resolveLabel(Label unresolved) throws IllegalStateExc
311326 * Extracts list of all executables associated with given collection of label artifacts.
312327 *
313328 * @param artifacts to get the paths of
329+ * @param workspaceRunfilesDirectory name of the runfiles directory corresponding to the main
330+ * repository
314331 * @return all associated executable paths
315332 */
316- private Set <String > getPaths (Collection <Artifact > artifacts ) {
333+ private Set <String > getPaths (
334+ Collection <Artifact > artifacts , String workspaceRunfilesDirectory ) {
317335 TreeSet <String > paths = Sets .newTreeSet ();
318336 for (Artifact artifact : artifacts ) {
319- PathFragment execPath =
320- execPaths
321- ? artifact .getExecPath ()
322- : legacyExternalRunfiles
323- ? artifact .getPathForLocationExpansion ()
324- : artifact .getRunfilesPath ();
325- if (execPath != null ) { // omit middlemen etc
326- paths .add (execPath .getCallablePathString ());
337+ PathFragment path = getPath (artifact , workspaceRunfilesDirectory );
338+ if (path != null ) { // omit middlemen etc
339+ paths .add (path .getCallablePathString ());
327340 }
328341 }
329342 return paths ;
330343 }
331344
345+ private PathFragment getPath (Artifact artifact , String workspaceRunfilesDirectory ) {
346+ switch (pathType ) {
347+ case LOCATION :
348+ return legacyExternalRunfiles
349+ ? artifact .getPathForLocationExpansion ()
350+ : artifact .getRunfilesPath ();
351+ case EXEC :
352+ return artifact .getExecPath ();
353+ case RLOCATION :
354+ PathFragment runfilesPath = artifact .getRunfilesPath ();
355+ if (runfilesPath .startsWith (LabelConstants .EXTERNAL_RUNFILES_PATH_PREFIX )) {
356+ return runfilesPath .relativeTo (LabelConstants .EXTERNAL_RUNFILES_PATH_PREFIX );
357+ } else {
358+ return PathFragment .create (workspaceRunfilesDirectory ).getRelative (runfilesPath );
359+ }
360+ }
361+ throw new IllegalStateException ("Unexpected PathType: " + pathType );
362+ }
363+
332364 private String joinPaths (Collection <String > paths ) {
333365 return paths .stream ().map (ShellEscaper ::escapeString ).collect (joining (" " ));
334366 }
@@ -346,27 +378,44 @@ static ImmutableMap<String, LocationFunction> allLocationFunctions(
346378 return new ImmutableMap .Builder <String , LocationFunction >()
347379 .put (
348380 "location" ,
349- new LocationFunction (root , locationMap , execPaths , legacyExternalRunfiles , EXACTLY_ONE ))
381+ new LocationFunction (
382+ root ,
383+ locationMap ,
384+ execPaths ? PathType .EXEC : PathType .LOCATION ,
385+ legacyExternalRunfiles ,
386+ EXACTLY_ONE ))
350387 .put (
351388 "locations" ,
352389 new LocationFunction (
353- root , locationMap , execPaths , legacyExternalRunfiles , ALLOW_MULTIPLE ))
390+ root ,
391+ locationMap ,
392+ execPaths ? PathType .EXEC : PathType .LOCATION ,
393+ legacyExternalRunfiles ,
394+ ALLOW_MULTIPLE ))
354395 .put (
355396 "rootpath" ,
356397 new LocationFunction (
357- root , locationMap , USE_LOCATION_PATHS , legacyExternalRunfiles , EXACTLY_ONE ))
398+ root , locationMap , PathType . LOCATION , legacyExternalRunfiles , EXACTLY_ONE ))
358399 .put (
359400 "rootpaths" ,
360401 new LocationFunction (
361- root , locationMap , USE_LOCATION_PATHS , legacyExternalRunfiles , ALLOW_MULTIPLE ))
402+ root , locationMap , PathType . LOCATION , legacyExternalRunfiles , ALLOW_MULTIPLE ))
362403 .put (
363404 "execpath" ,
364405 new LocationFunction (
365- root , locationMap , USE_EXEC_PATHS , legacyExternalRunfiles , EXACTLY_ONE ))
406+ root , locationMap , PathType . EXEC , legacyExternalRunfiles , EXACTLY_ONE ))
366407 .put (
367408 "execpaths" ,
368409 new LocationFunction (
369- root , locationMap , USE_EXEC_PATHS , legacyExternalRunfiles , ALLOW_MULTIPLE ))
410+ root , locationMap , PathType .EXEC , legacyExternalRunfiles , ALLOW_MULTIPLE ))
411+ .put (
412+ "rlocationpath" ,
413+ new LocationFunction (
414+ root , locationMap , PathType .RLOCATION , legacyExternalRunfiles , EXACTLY_ONE ))
415+ .put (
416+ "rlocationpaths" ,
417+ new LocationFunction (
418+ root , locationMap , PathType .RLOCATION , legacyExternalRunfiles , ALLOW_MULTIPLE ))
370419 .build ();
371420 }
372421
0 commit comments