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,7 @@ 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 = functions .get (fname ).apply (functionValue , repositoryMapping , workspaceRunfilesDirectory );
208
212
result .append (replacement );
209
213
} catch (IllegalStateException ise ) {
210
214
reporter .report (ise .getMessage ());
@@ -232,23 +236,29 @@ public String expandAttribute(String attrName, String attrValue) {
232
236
233
237
@ VisibleForTesting
234
238
static final class LocationFunction {
239
+ enum PathType {
240
+ LOCATION ,
241
+ EXEC ,
242
+ RLOCATION ,
243
+ }
244
+
235
245
private static final int MAX_PATHS_SHOWN = 5 ;
236
246
237
247
private final Label root ;
238
248
private final Supplier <Map <Label , Collection <Artifact >>> locationMapSupplier ;
239
- private final boolean execPaths ;
249
+ private final PathType pathType ;
240
250
private final boolean legacyExternalRunfiles ;
241
251
private final boolean multiple ;
242
252
243
253
LocationFunction (
244
- Label root ,
245
- Supplier <Map <Label , Collection <Artifact >>> locationMapSupplier ,
246
- boolean execPaths ,
247
- boolean legacyExternalRunfiles ,
248
- boolean multiple ) {
254
+ Label root ,
255
+ Supplier <Map <Label , Collection <Artifact >>> locationMapSupplier ,
256
+ PathType pathType ,
257
+ boolean legacyExternalRunfiles ,
258
+ boolean multiple ) {
249
259
this .root = root ;
250
260
this .locationMapSupplier = locationMapSupplier ;
251
- this .execPaths = execPaths ;
261
+ this .pathType = Preconditions . checkNotNull ( pathType ) ;
252
262
this .legacyExternalRunfiles = legacyExternalRunfiles ;
253
263
this .multiple = multiple ;
254
264
}
@@ -259,10 +269,11 @@ static final class LocationFunction {
259
269
* using the {@code repositoryMapping}.
260
270
*
261
271
* @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
272
+ * @param repositoryMapping map of apparent repository names to {@code RepositoryName}s
273
+ * @param workspaceRunfilesDirectory name of the runfiles directory corresponding to the main repository
263
274
* @return The expanded value
264
275
*/
265
- public String apply (String arg , RepositoryMapping repositoryMapping ) {
276
+ public String apply (String arg , RepositoryMapping repositoryMapping , String workspaceRunfilesDirectory ) {
266
277
Label label ;
267
278
try {
268
279
label = root .getRelativeWithRemapping (arg , repositoryMapping );
@@ -271,14 +282,14 @@ public String apply(String arg, RepositoryMapping repositoryMapping) {
271
282
String .format (
272
283
"invalid label in %s expression: %s" , functionName (), e .getMessage ()), e );
273
284
}
274
- Collection <String > paths = resolveLabel (label );
285
+ Collection <String > paths = resolveLabel (label , workspaceRunfilesDirectory );
275
286
return joinPaths (paths );
276
287
}
277
288
278
289
/**
279
290
* Returns all target location(s) of the given label.
280
291
*/
281
- private Collection <String > resolveLabel (Label unresolved ) throws IllegalStateException {
292
+ private Collection <String > resolveLabel (Label unresolved , String workspaceRunfilesDirectory ) throws IllegalStateException {
282
293
Collection <Artifact > artifacts = locationMapSupplier .get ().get (unresolved );
283
294
284
295
if (artifacts == null ) {
@@ -288,7 +299,7 @@ private Collection<String> resolveLabel(Label unresolved) throws IllegalStateExc
288
299
unresolved , functionName ()));
289
300
}
290
301
291
- Set <String > paths = getPaths (artifacts );
302
+ Set <String > paths = getPaths (artifacts , workspaceRunfilesDirectory );
292
303
if (paths .isEmpty ()) {
293
304
throw new IllegalStateException (
294
305
String .format (
@@ -313,24 +324,37 @@ private Collection<String> resolveLabel(Label unresolved) throws IllegalStateExc
313
324
* Extracts list of all executables associated with given collection of label artifacts.
314
325
*
315
326
* @param artifacts to get the paths of
327
+ * @param workspaceRunfilesDirectory name of the runfiles directory corresponding to the main repository
316
328
* @return all associated executable paths
317
329
*/
318
- private Set <String > getPaths (Collection <Artifact > artifacts ) {
330
+ private Set <String > getPaths (Collection <Artifact > artifacts , String workspaceRunfilesDirectory ) {
319
331
TreeSet <String > paths = Sets .newTreeSet ();
320
332
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 ());
333
+ PathFragment path = getPath (artifact , workspaceRunfilesDirectory );
334
+ if (path != null ) { // omit middlemen etc
335
+ paths .add (path .getCallablePathString ());
329
336
}
330
337
}
331
338
return paths ;
332
339
}
333
340
341
+ private PathFragment getPath (Artifact artifact , String workspaceRunfilesDirectory ) {
342
+ switch (pathType ) {
343
+ case LOCATION :
344
+ return legacyExternalRunfiles ? artifact .getPathForLocationExpansion () : artifact .getRunfilesPath ();
345
+ case EXEC :
346
+ return artifact .getExecPath ();
347
+ case RLOCATION :
348
+ PathFragment runfilesPath = artifact .getRunfilesPath ();
349
+ if (runfilesPath .startsWith (LabelConstants .EXTERNAL_RUNFILES_PATH_PREFIX )) {
350
+ return runfilesPath .relativeTo (LabelConstants .EXTERNAL_RUNFILES_PATH_PREFIX );
351
+ } else {
352
+ return PathFragment .create (workspaceRunfilesDirectory ).getRelative (runfilesPath );
353
+ }
354
+ }
355
+ throw new IllegalStateException ("Unexpected PathType: " + pathType );
356
+ }
357
+
334
358
private String joinPaths (Collection <String > paths ) {
335
359
return paths .stream ().map (ShellEscaper ::escapeString ).collect (joining (" " ));
336
360
}
@@ -348,27 +372,35 @@ static ImmutableMap<String, LocationFunction> allLocationFunctions(
348
372
return new ImmutableMap .Builder <String , LocationFunction >()
349
373
.put (
350
374
"location" ,
351
- new LocationFunction (root , locationMap , execPaths , legacyExternalRunfiles , EXACTLY_ONE ))
375
+ new LocationFunction (root , locationMap , execPaths ? PathType . EXEC : PathType . LOCATION , legacyExternalRunfiles , EXACTLY_ONE ))
352
376
.put (
353
377
"locations" ,
354
378
new LocationFunction (
355
- root , locationMap , execPaths , legacyExternalRunfiles , ALLOW_MULTIPLE ))
379
+ root , locationMap , execPaths ? PathType . EXEC : PathType . LOCATION , legacyExternalRunfiles , ALLOW_MULTIPLE ))
356
380
.put (
357
381
"rootpath" ,
358
382
new LocationFunction (
359
- root , locationMap , USE_LOCATION_PATHS , legacyExternalRunfiles , EXACTLY_ONE ))
383
+ root , locationMap , PathType . LOCATION , legacyExternalRunfiles , EXACTLY_ONE ))
360
384
.put (
361
385
"rootpaths" ,
362
386
new LocationFunction (
363
- root , locationMap , USE_LOCATION_PATHS , legacyExternalRunfiles , ALLOW_MULTIPLE ))
387
+ root , locationMap , PathType . LOCATION , legacyExternalRunfiles , ALLOW_MULTIPLE ))
364
388
.put (
365
389
"execpath" ,
366
390
new LocationFunction (
367
- root , locationMap , USE_EXEC_PATHS , legacyExternalRunfiles , EXACTLY_ONE ))
391
+ root , locationMap , PathType . EXEC , legacyExternalRunfiles , EXACTLY_ONE ))
368
392
.put (
369
393
"execpaths" ,
370
394
new LocationFunction (
371
- root , locationMap , USE_EXEC_PATHS , legacyExternalRunfiles , ALLOW_MULTIPLE ))
395
+ root , locationMap , PathType .EXEC , legacyExternalRunfiles , ALLOW_MULTIPLE ))
396
+ .put (
397
+ "rlocationpath" ,
398
+ new LocationFunction (
399
+ root , locationMap , PathType .RLOCATION , legacyExternalRunfiles , EXACTLY_ONE ))
400
+ .put (
401
+ "rlocationpaths" ,
402
+ new LocationFunction (
403
+ root , locationMap , PathType .RLOCATION , legacyExternalRunfiles , ALLOW_MULTIPLE ))
372
404
.buildOrThrow ();
373
405
}
374
406
0 commit comments