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
/**
@@ -215,7 +219,10 @@ private String expand(String value, ErrorReporter reporter) {
215
219
// (2) Call appropriate function to obtain string replacement.
216
220
String functionValue = value .substring (nextWhitespace + 1 , end ).trim ();
217
221
try {
218
- String replacement = functions .get (fname ).apply (functionValue , repositoryMapping );
222
+ String replacement =
223
+ functions
224
+ .get (fname )
225
+ .apply (functionValue , repositoryMapping , workspaceRunfilesDirectory );
219
226
result .append (replacement );
220
227
} catch (IllegalStateException ise ) {
221
228
reporter .report (ise .getMessage ());
@@ -230,23 +237,29 @@ private String expand(String value, ErrorReporter reporter) {
230
237
231
238
@ VisibleForTesting
232
239
static final class LocationFunction {
240
+ enum PathType {
241
+ LOCATION ,
242
+ EXEC ,
243
+ RLOCATION ,
244
+ }
245
+
233
246
private static final int MAX_PATHS_SHOWN = 5 ;
234
247
235
248
private final Label root ;
236
249
private final Supplier <Map <Label , Collection <Artifact >>> locationMapSupplier ;
237
- private final boolean execPaths ;
250
+ private final PathType pathType ;
238
251
private final boolean legacyExternalRunfiles ;
239
252
private final boolean multiple ;
240
253
241
254
LocationFunction (
242
255
Label root ,
243
256
Supplier <Map <Label , Collection <Artifact >>> locationMapSupplier ,
244
- boolean execPaths ,
257
+ PathType pathType ,
245
258
boolean legacyExternalRunfiles ,
246
259
boolean multiple ) {
247
260
this .root = root ;
248
261
this .locationMapSupplier = locationMapSupplier ;
249
- this .execPaths = execPaths ;
262
+ this .pathType = Preconditions . checkNotNull ( pathType ) ;
250
263
this .legacyExternalRunfiles = legacyExternalRunfiles ;
251
264
this .multiple = multiple ;
252
265
}
@@ -257,10 +270,13 @@ static final class LocationFunction {
257
270
* using the {@code repositoryMapping}.
258
271
*
259
272
* @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
261
276
* @return The expanded value
262
277
*/
263
- public String apply (String arg , RepositoryMapping repositoryMapping ) {
278
+ public String apply (
279
+ String arg , RepositoryMapping repositoryMapping , String workspaceRunfilesDirectory ) {
264
280
Label label ;
265
281
try {
266
282
label = root .getRelativeWithRemapping (arg , repositoryMapping );
@@ -269,14 +285,13 @@ public String apply(String arg, RepositoryMapping repositoryMapping) {
269
285
String .format (
270
286
"invalid label in %s expression: %s" , functionName (), e .getMessage ()), e );
271
287
}
272
- Collection <String > paths = resolveLabel (label );
288
+ Set <String > paths = resolveLabel (label , workspaceRunfilesDirectory );
273
289
return joinPaths (paths );
274
290
}
275
291
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 {
280
295
Collection <Artifact > artifacts = locationMapSupplier .get ().get (unresolved );
281
296
282
297
if (artifacts == null ) {
@@ -286,7 +301,7 @@ private Collection<String> resolveLabel(Label unresolved) throws IllegalStateExc
286
301
unresolved , functionName ()));
287
302
}
288
303
289
- Set <String > paths = getPaths (artifacts );
304
+ Set <String > paths = getPaths (artifacts , workspaceRunfilesDirectory );
290
305
if (paths .isEmpty ()) {
291
306
throw new IllegalStateException (
292
307
String .format (
@@ -311,24 +326,41 @@ private Collection<String> resolveLabel(Label unresolved) throws IllegalStateExc
311
326
* Extracts list of all executables associated with given collection of label artifacts.
312
327
*
313
328
* @param artifacts to get the paths of
329
+ * @param workspaceRunfilesDirectory name of the runfiles directory corresponding to the main
330
+ * repository
314
331
* @return all associated executable paths
315
332
*/
316
- private Set <String > getPaths (Collection <Artifact > artifacts ) {
333
+ private Set <String > getPaths (
334
+ Collection <Artifact > artifacts , String workspaceRunfilesDirectory ) {
317
335
TreeSet <String > paths = Sets .newTreeSet ();
318
336
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 ());
327
340
}
328
341
}
329
342
return paths ;
330
343
}
331
344
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
+
332
364
private String joinPaths (Collection <String > paths ) {
333
365
return paths .stream ().map (ShellEscaper ::escapeString ).collect (joining (" " ));
334
366
}
@@ -346,27 +378,44 @@ static ImmutableMap<String, LocationFunction> allLocationFunctions(
346
378
return new ImmutableMap .Builder <String , LocationFunction >()
347
379
.put (
348
380
"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 ))
350
387
.put (
351
388
"locations" ,
352
389
new LocationFunction (
353
- root , locationMap , execPaths , legacyExternalRunfiles , ALLOW_MULTIPLE ))
390
+ root ,
391
+ locationMap ,
392
+ execPaths ? PathType .EXEC : PathType .LOCATION ,
393
+ legacyExternalRunfiles ,
394
+ ALLOW_MULTIPLE ))
354
395
.put (
355
396
"rootpath" ,
356
397
new LocationFunction (
357
- root , locationMap , USE_LOCATION_PATHS , legacyExternalRunfiles , EXACTLY_ONE ))
398
+ root , locationMap , PathType . LOCATION , legacyExternalRunfiles , EXACTLY_ONE ))
358
399
.put (
359
400
"rootpaths" ,
360
401
new LocationFunction (
361
- root , locationMap , USE_LOCATION_PATHS , legacyExternalRunfiles , ALLOW_MULTIPLE ))
402
+ root , locationMap , PathType . LOCATION , legacyExternalRunfiles , ALLOW_MULTIPLE ))
362
403
.put (
363
404
"execpath" ,
364
405
new LocationFunction (
365
- root , locationMap , USE_EXEC_PATHS , legacyExternalRunfiles , EXACTLY_ONE ))
406
+ root , locationMap , PathType . EXEC , legacyExternalRunfiles , EXACTLY_ONE ))
366
407
.put (
367
408
"execpaths" ,
368
409
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 ))
370
419
.build ();
371
420
}
372
421
0 commit comments