17
17
import static java .util .stream .Collectors .joining ;
18
18
19
19
import com .google .common .annotations .VisibleForTesting ;
20
+ import com .google .common .base .Preconditions ;
20
21
import com .google .common .base .Supplier ;
21
22
import com .google .common .base .Suppliers ;
22
23
import com .google .common .collect .ImmutableCollection ;
26
27
import com .google .common .collect .Maps ;
27
28
import com .google .common .collect .Sets ;
28
29
import com .google .devtools .build .lib .actions .Artifact ;
30
+ import com .google .devtools .build .lib .analysis .LocationExpander .LocationFunction .PathType ;
29
31
import com .google .devtools .build .lib .cmdline .Label ;
32
+ import com .google .devtools .build .lib .cmdline .LabelConstants ;
30
33
import com .google .devtools .build .lib .cmdline .LabelSyntaxException ;
31
34
import com .google .devtools .build .lib .cmdline .RepositoryMapping ;
32
35
import com .google .devtools .build .lib .packages .BuildType ;
@@ -63,34 +66,35 @@ public final class LocationExpander {
63
66
private static final boolean EXACTLY_ONE = false ;
64
67
private static final boolean ALLOW_MULTIPLE = true ;
65
68
66
- private static final boolean USE_LOCATION_PATHS = false ;
67
- private static final boolean USE_EXEC_PATHS = true ;
68
-
69
69
private final RuleErrorConsumer ruleErrorConsumer ;
70
70
private final ImmutableMap <String , LocationFunction > functions ;
71
71
private final RepositoryMapping repositoryMapping ;
72
+ private final String workspaceRunfilesDirectory ;
72
73
73
74
@ VisibleForTesting
74
75
LocationExpander (
75
76
RuleErrorConsumer ruleErrorConsumer ,
76
77
Map <String , LocationFunction > functions ,
77
- RepositoryMapping repositoryMapping ) {
78
+ RepositoryMapping repositoryMapping ,
79
+ String workspaceRunfilesDirectory ) {
78
80
this .ruleErrorConsumer = ruleErrorConsumer ;
79
81
this .functions = ImmutableMap .copyOf (functions );
80
82
this .repositoryMapping = repositoryMapping ;
83
+ this .workspaceRunfilesDirectory = workspaceRunfilesDirectory ;
81
84
}
82
85
83
86
private LocationExpander (
84
- RuleErrorConsumer ruleErrorConsumer ,
87
+ RuleContext ruleContext ,
85
88
Label root ,
86
89
Supplier <Map <Label , Collection <Artifact >>> locationMap ,
87
90
boolean execPaths ,
88
91
boolean legacyExternalRunfiles ,
89
92
RepositoryMapping repositoryMapping ) {
90
93
this (
91
- ruleErrorConsumer ,
94
+ ruleContext ,
92
95
allLocationFunctions (root , locationMap , execPaths , legacyExternalRunfiles ),
93
- repositoryMapping );
96
+ repositoryMapping ,
97
+ ruleContext .getWorkspaceName ());
94
98
}
95
99
96
100
/**
@@ -204,7 +208,10 @@ private String expand(String value, ErrorReporter reporter) {
204
208
// (2) Call appropriate function to obtain string replacement.
205
209
String functionValue = value .substring (nextWhitespace + 1 , end ).trim ();
206
210
try {
207
- String replacement = functions .get (fname ).apply (functionValue , repositoryMapping );
211
+ String replacement =
212
+ functions
213
+ .get (fname )
214
+ .apply (functionValue , repositoryMapping , workspaceRunfilesDirectory );
208
215
result .append (replacement );
209
216
} catch (IllegalStateException ise ) {
210
217
reporter .report (ise .getMessage ());
@@ -232,23 +239,29 @@ public String expandAttribute(String attrName, String attrValue) {
232
239
233
240
@ VisibleForTesting
234
241
static final class LocationFunction {
242
+ enum PathType {
243
+ LOCATION ,
244
+ EXEC ,
245
+ RLOCATION ,
246
+ }
247
+
235
248
private static final int MAX_PATHS_SHOWN = 5 ;
236
249
237
250
private final Label root ;
238
251
private final Supplier <Map <Label , Collection <Artifact >>> locationMapSupplier ;
239
- private final boolean execPaths ;
252
+ private final PathType pathType ;
240
253
private final boolean legacyExternalRunfiles ;
241
254
private final boolean multiple ;
242
255
243
256
LocationFunction (
244
257
Label root ,
245
258
Supplier <Map <Label , Collection <Artifact >>> locationMapSupplier ,
246
- boolean execPaths ,
259
+ PathType pathType ,
247
260
boolean legacyExternalRunfiles ,
248
261
boolean multiple ) {
249
262
this .root = root ;
250
263
this .locationMapSupplier = locationMapSupplier ;
251
- this .execPaths = execPaths ;
264
+ this .pathType = Preconditions . checkNotNull ( pathType ) ;
252
265
this .legacyExternalRunfiles = legacyExternalRunfiles ;
253
266
this .multiple = multiple ;
254
267
}
@@ -259,10 +272,13 @@ static final class LocationFunction {
259
272
* using the {@code repositoryMapping}.
260
273
*
261
274
* @param arg The label-like string to be expanded, e.g. ":foo" or "//foo:bar"
262
- * @param repositoryMapping map of {@code RepositoryName}s defined in the main workspace
275
+ * @param repositoryMapping map of apparent repository names to {@code RepositoryName}s
276
+ * @param workspaceRunfilesDirectory name of the runfiles directory corresponding to the main
277
+ * repository
263
278
* @return The expanded value
264
279
*/
265
- public String apply (String arg , RepositoryMapping repositoryMapping ) {
280
+ public String apply (
281
+ String arg , RepositoryMapping repositoryMapping , String workspaceRunfilesDirectory ) {
266
282
Label label ;
267
283
try {
268
284
label = root .getRelativeWithRemapping (arg , repositoryMapping );
@@ -271,14 +287,13 @@ public String apply(String arg, RepositoryMapping repositoryMapping) {
271
287
String .format (
272
288
"invalid label in %s expression: %s" , functionName (), e .getMessage ()), e );
273
289
}
274
- Collection <String > paths = resolveLabel (label );
290
+ Set <String > paths = resolveLabel (label , workspaceRunfilesDirectory );
275
291
return joinPaths (paths );
276
292
}
277
293
278
- /**
279
- * Returns all target location(s) of the given label.
280
- */
281
- private Collection <String > resolveLabel (Label unresolved ) throws IllegalStateException {
294
+ /** Returns all target location(s) of the given label. */
295
+ private Set <String > resolveLabel (Label unresolved , String workspaceRunfilesDirectory )
296
+ throws IllegalStateException {
282
297
Collection <Artifact > artifacts = locationMapSupplier .get ().get (unresolved );
283
298
284
299
if (artifacts == null ) {
@@ -288,7 +303,7 @@ private Collection<String> resolveLabel(Label unresolved) throws IllegalStateExc
288
303
unresolved , functionName ()));
289
304
}
290
305
291
- Set <String > paths = getPaths (artifacts );
306
+ Set <String > paths = getPaths (artifacts , workspaceRunfilesDirectory );
292
307
if (paths .isEmpty ()) {
293
308
throw new IllegalStateException (
294
309
String .format (
@@ -313,24 +328,41 @@ private Collection<String> resolveLabel(Label unresolved) throws IllegalStateExc
313
328
* Extracts list of all executables associated with given collection of label artifacts.
314
329
*
315
330
* @param artifacts to get the paths of
331
+ * @param workspaceRunfilesDirectory name of the runfiles directory corresponding to the main
332
+ * repository
316
333
* @return all associated executable paths
317
334
*/
318
- private Set <String > getPaths (Collection <Artifact > artifacts ) {
335
+ private Set <String > getPaths (
336
+ Collection <Artifact > artifacts , String workspaceRunfilesDirectory ) {
319
337
TreeSet <String > paths = Sets .newTreeSet ();
320
338
for (Artifact artifact : artifacts ) {
321
- PathFragment execPath =
322
- execPaths
323
- ? artifact .getExecPath ()
324
- : legacyExternalRunfiles
325
- ? artifact .getPathForLocationExpansion ()
326
- : artifact .getRunfilesPath ();
327
- if (execPath != null ) { // omit middlemen etc
328
- paths .add (execPath .getCallablePathString ());
339
+ PathFragment path = getPath (artifact , workspaceRunfilesDirectory );
340
+ if (path != null ) { // omit middlemen etc
341
+ paths .add (path .getCallablePathString ());
329
342
}
330
343
}
331
344
return paths ;
332
345
}
333
346
347
+ private PathFragment getPath (Artifact artifact , String workspaceRunfilesDirectory ) {
348
+ switch (pathType ) {
349
+ case LOCATION :
350
+ return legacyExternalRunfiles
351
+ ? artifact .getPathForLocationExpansion ()
352
+ : artifact .getRunfilesPath ();
353
+ case EXEC :
354
+ return artifact .getExecPath ();
355
+ case RLOCATION :
356
+ PathFragment runfilesPath = artifact .getRunfilesPath ();
357
+ if (runfilesPath .startsWith (LabelConstants .EXTERNAL_RUNFILES_PATH_PREFIX )) {
358
+ return runfilesPath .relativeTo (LabelConstants .EXTERNAL_RUNFILES_PATH_PREFIX );
359
+ } else {
360
+ return PathFragment .create (workspaceRunfilesDirectory ).getRelative (runfilesPath );
361
+ }
362
+ }
363
+ throw new IllegalStateException ("Unexpected PathType: " + pathType );
364
+ }
365
+
334
366
private String joinPaths (Collection <String > paths ) {
335
367
return paths .stream ().map (ShellEscaper ::escapeString ).collect (joining (" " ));
336
368
}
@@ -348,27 +380,44 @@ static ImmutableMap<String, LocationFunction> allLocationFunctions(
348
380
return new ImmutableMap .Builder <String , LocationFunction >()
349
381
.put (
350
382
"location" ,
351
- new LocationFunction (root , locationMap , execPaths , legacyExternalRunfiles , EXACTLY_ONE ))
383
+ new LocationFunction (
384
+ root ,
385
+ locationMap ,
386
+ execPaths ? PathType .EXEC : PathType .LOCATION ,
387
+ legacyExternalRunfiles ,
388
+ EXACTLY_ONE ))
352
389
.put (
353
390
"locations" ,
354
391
new LocationFunction (
355
- root , locationMap , execPaths , legacyExternalRunfiles , ALLOW_MULTIPLE ))
392
+ root ,
393
+ locationMap ,
394
+ execPaths ? PathType .EXEC : PathType .LOCATION ,
395
+ legacyExternalRunfiles ,
396
+ ALLOW_MULTIPLE ))
356
397
.put (
357
398
"rootpath" ,
358
399
new LocationFunction (
359
- root , locationMap , USE_LOCATION_PATHS , legacyExternalRunfiles , EXACTLY_ONE ))
400
+ root , locationMap , PathType . LOCATION , legacyExternalRunfiles , EXACTLY_ONE ))
360
401
.put (
361
402
"rootpaths" ,
362
403
new LocationFunction (
363
- root , locationMap , USE_LOCATION_PATHS , legacyExternalRunfiles , ALLOW_MULTIPLE ))
404
+ root , locationMap , PathType . LOCATION , legacyExternalRunfiles , ALLOW_MULTIPLE ))
364
405
.put (
365
406
"execpath" ,
366
407
new LocationFunction (
367
- root , locationMap , USE_EXEC_PATHS , legacyExternalRunfiles , EXACTLY_ONE ))
408
+ root , locationMap , PathType . EXEC , legacyExternalRunfiles , EXACTLY_ONE ))
368
409
.put (
369
410
"execpaths" ,
370
411
new LocationFunction (
371
- root , locationMap , USE_EXEC_PATHS , legacyExternalRunfiles , ALLOW_MULTIPLE ))
412
+ root , locationMap , PathType .EXEC , legacyExternalRunfiles , ALLOW_MULTIPLE ))
413
+ .put (
414
+ "rlocationpath" ,
415
+ new LocationFunction (
416
+ root , locationMap , PathType .RLOCATION , legacyExternalRunfiles , EXACTLY_ONE ))
417
+ .put (
418
+ "rlocationpaths" ,
419
+ new LocationFunction (
420
+ root , locationMap , PathType .RLOCATION , legacyExternalRunfiles , ALLOW_MULTIPLE ))
372
421
.buildOrThrow ();
373
422
}
374
423
0 commit comments