Skip to content

Commit 1dea68c

Browse files
committed
Stringify Labels in display form in Args
1 parent a5d2499 commit 1dea68c

File tree

11 files changed

+192
-39
lines changed

11 files changed

+192
-39
lines changed

src/main/java/com/google/devtools/build/lib/analysis/BUILD

+2
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,7 @@ java_library(
411411
"//src/main/java/com/google/devtools/build/lib/skyframe:configured_target_and_data",
412412
"//src/main/java/com/google/devtools/build/lib/skyframe:configured_target_key",
413413
"//src/main/java/com/google/devtools/build/lib/skyframe:configured_value_creation_exception",
414+
"//src/main/java/com/google/devtools/build/lib/skyframe:repository_mapping_value",
414415
"//src/main/java/com/google/devtools/build/lib/skyframe:starlark_builtins_value",
415416
"//src/main/java/com/google/devtools/build/lib/skyframe:workspace_status_value",
416417
"//src/main/java/com/google/devtools/build/lib/skyframe/config",
@@ -2442,6 +2443,7 @@ java_library(
24422443
"//src/main/java/com/google/devtools/build/lib/actions",
24432444
"//src/main/java/com/google/devtools/build/lib/actions:artifacts",
24442445
"//src/main/java/com/google/devtools/build/lib/actions:commandline_item",
2446+
"//src/main/java/com/google/devtools/build/lib/cmdline",
24452447
"//src/main/java/com/google/devtools/build/lib/collect/nestedset",
24462448
"//src/main/java/com/google/devtools/build/lib/concurrent",
24472449
"//src/main/java/com/google/devtools/build/lib/starlarkbuildapi",

src/main/java/com/google/devtools/build/lib/analysis/starlark/Args.java

+32-7
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import com.google.devtools.build.lib.actions.ParamFileInfo;
2424
import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType;
2525
import com.google.devtools.build.lib.actions.SingleStringArgFormatter;
26+
import com.google.devtools.build.lib.cmdline.Label;
27+
import com.google.devtools.build.lib.cmdline.RepositoryMapping;
2628
import com.google.devtools.build.lib.collect.nestedset.Depset;
2729
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
2830
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
@@ -70,7 +72,8 @@ public void repr(Printer printer) {
7072
@Override
7173
public void debugPrint(Printer printer, StarlarkSemantics semantics) {
7274
try {
73-
printer.append(Joiner.on(" ").join(build().arguments()));
75+
printer.append(
76+
Joiner.on(" ").join(build(/* mainRepoMappingSupplier */ () -> null).arguments()));
7477
} catch (CommandLineExpansionException e) {
7578
printer.append("Cannot expand command line: " + e.getMessage());
7679
} catch (InterruptedException e) {
@@ -101,8 +104,13 @@ public void debugPrint(Printer printer, StarlarkSemantics semantics) {
101104
*/
102105
public abstract ImmutableSet<Artifact> getDirectoryArtifacts();
103106

107+
public interface InterruptibleRepoMappingSupplier {
108+
RepositoryMapping get() throws InterruptedException;
109+
}
110+
104111
/** Returns the command line built by this {@link Args} object. */
105-
public abstract CommandLine build();
112+
public abstract CommandLine build(InterruptibleRepoMappingSupplier mainRepoMappingSupplier)
113+
throws InterruptedException;
106114

107115
/**
108116
* Returns a frozen {@link Args} representation corresponding to an already-registered action.
@@ -157,7 +165,7 @@ public ImmutableSet<Artifact> getDirectoryArtifacts() {
157165
}
158166

159167
@Override
160-
public CommandLine build() {
168+
public CommandLine build(InterruptibleRepoMappingSupplier mainRepoMappingSupplier) {
161169
return commandLine;
162170
}
163171

@@ -259,6 +267,12 @@ private static class MutableArgs extends Args implements StarlarkValue, Mutabili
259267
*/
260268
private boolean flagPerLine = false;
261269

270+
/**
271+
* True if the command line needs to stringify any {@link Label}s without an explicit 'map_each'
272+
* function.
273+
*/
274+
private boolean mayStringifyExternalLabel = false;
275+
262276
// May be set explicitly once -- if unset defaults to ParameterFileType.SHELL_QUOTED.
263277
private ParameterFileType parameterFileType = null;
264278
private String flagFormatString;
@@ -307,6 +321,9 @@ public CommandLineArgsApi addArgument(
307321
"Args.add() doesn't accept vectorized arguments. Please use Args.add_all() or"
308322
+ " Args.add_joined() instead.");
309323
}
324+
if (value instanceof Label label && !label.getRepository().isMain()) {
325+
mayStringifyExternalLabel = true;
326+
}
310327
addSingleArg(value, format != Starlark.NONE ? (String) format : null);
311328
return this;
312329
}
@@ -436,8 +453,10 @@ private void addVectorArg(
436453
validateFormatString("format_each", formatEach);
437454
validateFormatString("format_joined", formatJoined);
438455
StarlarkCustomCommandLine.VectorArg.Builder vectorArg;
439-
if (value instanceof Depset) {
440-
Depset starlarkNestedSet = (Depset) value;
456+
if (value instanceof Depset starlarkNestedSet) {
457+
if (mapEach == null && Label.class.equals(starlarkNestedSet.getElementClass())) {
458+
mayStringifyExternalLabel = true;
459+
}
441460
NestedSet<?> nestedSet = starlarkNestedSet.getSet();
442461
if (nestedSet.isEmpty() && omitIfEmpty) {
443462
return;
@@ -454,6 +473,10 @@ private void addVectorArg(
454473
if (expandDirectories) {
455474
scanForDirectories(starlarkList);
456475
}
476+
mayStringifyExternalLabel |=
477+
(mapEach != null)
478+
&& starlarkList.stream()
479+
.anyMatch(o -> o instanceof Label label && !label.getRepository().isMain());
457480
vectorArg = new StarlarkCustomCommandLine.VectorArg.Builder(starlarkList);
458481
}
459482
commandLine.recordArgStart();
@@ -573,8 +596,10 @@ private MutableArgs(@Nullable Mutability mutability, StarlarkSemantics starlarkS
573596
}
574597

575598
@Override
576-
public CommandLine build() {
577-
return commandLine.build(flagPerLine);
599+
public CommandLine build(InterruptibleRepoMappingSupplier mainRepoMappingSupplier)
600+
throws InterruptedException {
601+
return commandLine.build(
602+
flagPerLine, mayStringifyExternalLabel ? mainRepoMappingSupplier.get() : null);
578603
}
579604

580605
@Override

src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkActionFactory.java

+13-9
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,8 @@ public void symlink(
332332
}
333333

334334
@Override
335-
public void write(FileApi output, Object content, Boolean isExecutable) throws EvalException {
335+
public void write(FileApi output, Object content, Boolean isExecutable)
336+
throws EvalException, InterruptedException {
336337
context.checkMutable("actions.write");
337338
RuleContext ruleContext = getRuleContext();
338339

@@ -347,7 +348,7 @@ public void write(FileApi output, Object content, Boolean isExecutable) throws E
347348
ruleContext.getActionOwner(),
348349
NestedSetBuilder.wrap(Order.STABLE_ORDER, args.getDirectoryArtifacts()),
349350
(Artifact) output,
350-
args.build(),
351+
args.build(context.getRuleContext().getAnalysisEnvironment()::getMainRepoMapping),
351352
args.getParameterFileType());
352353
} else {
353354
throw new AssertionError("Unexpected type: " + content.getClass().getSimpleName());
@@ -373,7 +374,7 @@ public void run(
373374
Object shadowedActionUnchecked,
374375
Object resourceSetUnchecked,
375376
Object toolchainUnchecked)
376-
throws EvalException {
377+
throws EvalException, InterruptedException {
377378
context.checkMutable("actions.run");
378379
execGroupUnchecked = context.maybeOverrideExecGroup(execGroupUnchecked);
379380
toolchainUnchecked = context.maybeOverrideToolchain(toolchainUnchecked);
@@ -382,7 +383,7 @@ public void run(
382383
boolean useAutoExecGroups = ruleContext.useAutoExecGroups();
383384

384385
StarlarkAction.Builder builder = new StarlarkAction.Builder();
385-
buildCommandLine(builder, arguments);
386+
buildCommandLine(builder, arguments, ruleContext.getAnalysisEnvironment()::getMainRepoMapping);
386387
if (executableUnchecked instanceof Artifact) {
387388
Artifact executable = (Artifact) executableUnchecked;
388389
FilesToRunProvider provider = context.getExecutableRunfiles(executable, "executable");
@@ -560,15 +561,15 @@ public void runShell(
560561
Object shadowedActionUnchecked,
561562
Object resourceSetUnchecked,
562563
Object toolchainUnchecked)
563-
throws EvalException {
564+
throws EvalException, InterruptedException {
564565
context.checkMutable("actions.run_shell");
565566
execGroupUnchecked = context.maybeOverrideExecGroup(execGroupUnchecked);
566567
toolchainUnchecked = context.maybeOverrideToolchain(toolchainUnchecked);
567568

568569
RuleContext ruleContext = getRuleContext();
569570

570571
StarlarkAction.Builder builder = new StarlarkAction.Builder();
571-
buildCommandLine(builder, arguments);
572+
buildCommandLine(builder, arguments, ruleContext.getAnalysisEnvironment()::getMainRepoMapping);
572573

573574
// When we use a shell command, add an empty argument before other arguments.
574575
// e.g. bash -c "cmd" '' 'arg1' 'arg2'
@@ -631,8 +632,11 @@ public void runShell(
631632
builder);
632633
}
633634

634-
private static void buildCommandLine(SpawnAction.Builder builder, Sequence<?> argumentsList)
635-
throws EvalException {
635+
private static void buildCommandLine(
636+
SpawnAction.Builder builder,
637+
Sequence<?> argumentsList,
638+
Args.InterruptibleRepoMappingSupplier repoMappingSupplier)
639+
throws EvalException, InterruptedException {
636640
ImmutableList.Builder<String> stringArgs = null;
637641
for (Object value : argumentsList) {
638642
if (value instanceof String) {
@@ -647,7 +651,7 @@ private static void buildCommandLine(SpawnAction.Builder builder, Sequence<?> ar
647651
}
648652
Args args = (Args) value;
649653
ParamFileInfo paramFileInfo = args.getParamFileInfo();
650-
builder.addCommandLine(args.build(), paramFileInfo);
654+
builder.addCommandLine(args.build(repoMappingSupplier), paramFileInfo);
651655
} else {
652656
throw Starlark.errorf(
653657
"expected list of strings or ctx.actions.args() for arguments instead of %s",

src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkCustomCommandLine.java

+66-15
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.google.common.collect.ImmutableList;
2121
import com.google.common.collect.ImmutableMap;
2222
import com.google.common.collect.Interner;
23+
import com.google.common.collect.Maps;
2324
import com.google.common.collect.Sets;
2425
import com.google.devtools.build.lib.actions.AbstractCommandLine;
2526
import com.google.devtools.build.lib.actions.ActionKeyContext;
@@ -36,6 +37,8 @@
3637
import com.google.devtools.build.lib.actions.PathMapper;
3738
import com.google.devtools.build.lib.actions.SingleStringArgFormatter;
3839
import com.google.devtools.build.lib.cmdline.Label;
40+
import com.google.devtools.build.lib.cmdline.RepositoryMapping;
41+
import com.google.devtools.build.lib.cmdline.RepositoryName;
3942
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
4043
import com.google.devtools.build.lib.concurrent.BlazeInterners;
4144
import com.google.devtools.build.lib.skyframe.serialization.VisibleForSerialization;
@@ -182,7 +185,8 @@ private int eval(
182185
int argi,
183186
List<String> builder,
184187
@Nullable ArtifactExpander artifactExpander,
185-
PathMapper pathMapper)
188+
PathMapper pathMapper,
189+
@Nullable RepositoryMapping mainRepoMapping)
186190
throws CommandLineExpansionException, InterruptedException {
187191
StarlarkCallable mapEach = null;
188192
StarlarkSemantics starlarkSemantics = null;
@@ -219,7 +223,7 @@ private int eval(
219223
int count = expandedValues.size();
220224
stringValues = new ArrayList<>(expandedValues.size());
221225
for (int i = 0; i < count; ++i) {
222-
stringValues.add(expandToCommandLine(expandedValues.get(i), pathMapper));
226+
stringValues.add(expandToCommandLine(expandedValues.get(i), pathMapper, mainRepoMapping));
223227
}
224228
}
225229
// It's safe to uniquify at this stage, any transformations after this
@@ -607,9 +611,15 @@ static void push(List<Object> arguments, Object object, String format) {
607611
arguments.add(format);
608612
}
609613

610-
static int eval(List<Object> arguments, int argi, List<String> builder, PathMapper pathMapper) {
614+
static int eval(
615+
List<Object> arguments,
616+
int argi,
617+
List<String> builder,
618+
PathMapper pathMapper,
619+
@Nullable RepositoryMapping mainRepoMapping) {
611620
Object object = arguments.get(argi++);
612-
String stringValue = StarlarkCustomCommandLine.expandToCommandLine(object, pathMapper);
621+
String stringValue =
622+
StarlarkCustomCommandLine.expandToCommandLine(object, pathMapper, mainRepoMapping);
613623
String formatStr = (String) arguments.get(argi++);
614624
builder.add(SingleStringArgFormatter.format(formatStr, stringValue));
615625
return argi;
@@ -662,10 +672,13 @@ Builder addFormatted(Object object, String format) {
662672
return this;
663673
}
664674

665-
CommandLine build(boolean flagPerLine) {
675+
CommandLine build(boolean flagPerLine, @Nullable RepositoryMapping mainRepoMapping) {
666676
if (arguments.isEmpty()) {
667677
return CommandLine.empty();
668678
}
679+
if (mainRepoMapping != null) {
680+
arguments.add(mainRepoMapping);
681+
}
669682
Object[] args = arguments.toArray();
670683
return flagPerLine
671684
? new StarlarkCustomCommandLineWithIndexes(args, argStartIndexes.build())
@@ -700,20 +713,37 @@ public Iterable<String> arguments(
700713
List<String> result = new ArrayList<>();
701714
List<Object> arguments = rawArgsAsList();
702715

703-
for (int argi = 0; argi < arguments.size(); ) {
716+
RepositoryMapping mainRepoMapping;
717+
int size;
718+
if (arguments.getLast() instanceof RepositoryMapping) {
719+
mainRepoMapping = (RepositoryMapping) arguments.getLast();
720+
size = arguments.size() - 1;
721+
} else {
722+
mainRepoMapping = null;
723+
size = arguments.size();
724+
}
725+
726+
for (int argi = 0; argi < size; ) {
704727
Object arg = arguments.get(argi++);
705728
if (arg instanceof VectorArg) {
706-
argi = ((VectorArg) arg).eval(arguments, argi, result, artifactExpander, pathMapper);
729+
argi =
730+
((VectorArg) arg)
731+
.eval(arguments, argi, result, artifactExpander, pathMapper, mainRepoMapping);
707732
} else if (arg == SingleFormattedArg.MARKER) {
708-
argi = SingleFormattedArg.eval(arguments, argi, result, pathMapper);
733+
argi = SingleFormattedArg.eval(arguments, argi, result, pathMapper, mainRepoMapping);
709734
} else {
710-
result.add(expandToCommandLine(arg, pathMapper));
735+
result.add(expandToCommandLine(arg, pathMapper, mainRepoMapping));
711736
}
712737
}
713738
return ImmutableList.copyOf(pathMapper.mapCustomStarlarkArgs(result));
714739
}
715740

716-
private static String expandToCommandLine(Object object, PathMapper pathMapper) {
741+
private static String expandToCommandLine(
742+
Object object, PathMapper pathMapper, @Nullable RepositoryMapping mainRepoMapping) {
743+
if (mainRepoMapping != null && object instanceof Label label) {
744+
return label.getDisplayForm(mainRepoMapping);
745+
}
746+
717747
// It'd be nice to build this into DerivedArtifact's CommandLine interface so we don't have
718748
// to explicitly check if an object is a DerivedArtifact. Unfortunately that would require
719749
// a lot more dependencies on the Java library DerivedArtifact is built into.
@@ -751,7 +781,17 @@ public Iterable<String> arguments(
751781
Iterator<Integer> startIndexIterator = argStartIndexes.iterator();
752782
int nextStartIndex = startIndexIterator.hasNext() ? startIndexIterator.next() : -1;
753783

754-
for (int argi = 0; argi < arguments.size(); ) {
784+
RepositoryMapping mainRepoMapping;
785+
int size;
786+
if (arguments.getLast() instanceof RepositoryMapping) {
787+
mainRepoMapping = (RepositoryMapping) arguments.getLast();
788+
size = arguments.size() - 1;
789+
} else {
790+
mainRepoMapping = null;
791+
size = arguments.size();
792+
}
793+
794+
for (int argi = 0; argi < size; ) {
755795

756796
// Record the actual beginning of each group.
757797
if (argi == nextStartIndex) {
@@ -761,11 +801,14 @@ public Iterable<String> arguments(
761801

762802
Object arg = arguments.get(argi++);
763803
if (arg instanceof VectorArg) {
764-
argi = ((VectorArg) arg).eval(arguments, argi, result, artifactExpander, pathMapper);
804+
argi =
805+
((VectorArg) arg)
806+
.eval(arguments, argi, result, artifactExpander, pathMapper, mainRepoMapping);
765807
} else if (arg == SingleFormattedArg.MARKER) {
766-
argi = SingleFormattedArg.eval(arguments, argi, result, pathMapper);
808+
argi = SingleFormattedArg.eval(arguments, argi, result, pathMapper, mainRepoMapping);
767809
} else {
768-
result.add(StarlarkCustomCommandLine.expandToCommandLine(arg, pathMapper));
810+
result.add(
811+
StarlarkCustomCommandLine.expandToCommandLine(arg, pathMapper, mainRepoMapping));
769812
}
770813
}
771814

@@ -796,7 +839,15 @@ public void addToFingerprint(
796839
Fingerprint fingerprint)
797840
throws CommandLineExpansionException, InterruptedException {
798841
List<Object> arguments = rawArgsAsList();
799-
for (int argi = 0; argi < arguments.size(); ) {
842+
int size;
843+
if (arguments.getLast() instanceof RepositoryMapping mainRepoMapping) {
844+
fingerprint.addStringMap(
845+
Maps.transformValues(mainRepoMapping.entries(), RepositoryName::getName));
846+
size = arguments.size() - 1;
847+
} else {
848+
size = arguments.size();
849+
}
850+
for (int argi = 0; argi < size; ) {
800851
Object arg = arguments.get(argi++);
801852
if (arg instanceof VectorArg) {
802853
argi =

src/main/java/com/google/devtools/build/lib/cmdline/RepositoryMapping.java

+4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
* <p>For repositories from the WORKSPACE file, if the requested repo doesn't exist in the mapping,
3232
* we fallback to the requested name. For repositories from Bzlmod, we return null to let the caller
3333
* decide what to do.
34+
*
35+
* <p>This class must not implement {@link net.starlark.java.eval.StarlarkValue} since instances of
36+
* this class are used as markers by {@link
37+
* com.google.devtools.build.lib.analysis.starlark.StarlarkCustomCommandLine}.
3438
*/
3539
public class RepositoryMapping {
3640
/* A repo mapping that always falls back to using the apparent name as the canonical name. */

src/main/java/com/google/devtools/build/lib/starlarkbuildapi/CommandLineArgsApi.java

+8
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@
6666
+ "<li>Values that are already strings are left as-is." //
6767
+ "<li><a href='../builtins/File.html'><code>File</code></a> objects are turned into"
6868
+ " their <code>File.path</code> values." //
69+
+ "<li><a href='../builtins/Label.html'><code>Label</code></a> objects are turned into"
70+
+ " a string representation that resolves back to the same object when resolved in the"
71+
+ " context of the main repository. If possible, the string representation uses the"
72+
+ " apparent name of a repository in favor of the repository's canonical name, which"
73+
+ " makes this representation suited for use in BUILD files. While the exact form of"
74+
+ " the representation is not guaranteed, typical examples are"
75+
+ " <code>//foo:bar</code>, <code>@repo//foo:bar</code> and"
76+
+ " <code>@@canonical_name~//foo:bar.bzl</code>."
6977
+ "<li>All other types are turned into strings in an <i>unspecified</i> manner. For "
7078
+ " this reason, you should avoid passing values that are not of string or "
7179
+ " <code>File</code> type to <code>add()</code>, and if you pass them to "

0 commit comments

Comments
 (0)