changing the structure of ScopeType to support custom exec behavior. The valid scopes are: `universal`, `project`, `default`, `target`, and values in the form of `exec:<foo>`. Here `foo` could be a specific value of the label to a flag that has the value we need.
PiperOrigin-RevId: 839954752
Change-Id: I8b9250041a40db0405ea8c757ceeaf350926a2ff
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BUILD b/src/main/java/com/google/devtools/build/lib/analysis/config/BUILD
index 4a0cd17..085a3a5 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BUILD
@@ -509,6 +509,7 @@
name = "scope",
srcs = ["Scope.java"],
deps = [
+ "//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec",
"//third_party:guava",
"//third_party:jsr305",
],
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java
index d5eb043..067cdae 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java
@@ -90,7 +90,7 @@
.collect(
toImmutableMap(
e -> Label.parseCanonicalUnchecked(e.getKey()),
- e -> Scope.ScopeType.valueOfIgnoreCase(e.getValue())));
+ e -> new Scope.ScopeType(e.getValue())));
}
public static BuildOptions getDefaultBuildOptionsForFragments(
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/Scope.java b/src/main/java/com/google/devtools/build/lib/analysis/config/Scope.java
index 08e3960..10b423e 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/Scope.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/Scope.java
@@ -13,13 +13,10 @@
// limitations under the License.
package com.google.devtools.build.lib.analysis.config;
-import static com.google.common.collect.ImmutableList.toImmutableList;
-import static java.util.Arrays.stream;
-
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
-import java.util.Locale;
+import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import javax.annotation.Nullable;
/**
@@ -28,27 +25,34 @@
*/
public class Scope {
/** Type of supported scopes. */
- public enum ScopeType {
- /** The flag's value never changes except explicitly by a configuraiton transition. * */
- UNIVERSAL,
- /** The flag's value resets on exec transitions. * */
- TARGET,
- /** The flag resets on targets outside the flag's project. See PROJECT.scl. * */
- PROJECT,
- /** Placeholder for flags that don't explicitly specify scope. Shouldn't be set directly. * */
- DEFAULT;
+ @AutoCodec
+ public record ScopeType(String scopeType) {
+ /** The flag's value never changes except explicitly by a configuration transition. */
+ public static final String UNIVERSAL = "universal";
- /** Returns the enum of a {@code scope = "<string>"} value. */
- public static ScopeType valueOfIgnoreCase(String scopeType) throws IllegalArgumentException {
- return ScopeType.valueOf(scopeType.toUpperCase(Locale.ROOT));
+ /** The flag's value resets on exec transitions. */
+ public static final String TARGET = "target";
+
+ /** The flag resets on targets outside the flag's project. See PROJECT.scl. */
+ public static final String PROJECT = "project";
+
+ /** Placeholder for flags that don't explicitly specify scope. Shouldn't be set directly. */
+ public static final String DEFAULT = "default";
+
+ public ScopeType {
+ if (!(scopeType.equals(DEFAULT)
+ || scopeType.equals(UNIVERSAL)
+ || scopeType.equals(TARGET)
+ || scopeType.equals(PROJECT)
+ || scopeType.startsWith("exec:"))) {
+ // TODO: don't let blaze crash for an invalid scope type.
+ throw new IllegalArgumentException("Invalid scope type: " + scopeType);
+ }
}
/** Which values can a rule's {@code scope} attribute have? */
public static ImmutableList<String> allowedAttributeValues() {
- return stream(ScopeType.values())
- .map(e -> e.name().toLowerCase(Locale.ROOT))
- .filter(e -> !e.equals("default")) // "default" is an internal value for unset attributes.
- .collect(toImmutableList());
+ return ImmutableList.of(UNIVERSAL, TARGET, PROJECT);
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/BuildConfigurationKeyProducer.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/BuildConfigurationKeyProducer.java
index 5982ba9..78efc7a 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/producers/BuildConfigurationKeyProducer.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/BuildConfigurationKeyProducer.java
@@ -183,7 +183,7 @@
this.postPlatformProcessedOptions.getScopeTypeMap().get(entry.getKey());
// scope is null is applicable for cases where a transition applies starlark flags that are
// not already part of the baseline configuration.
- if (scopeType == null || scopeType == Scope.ScopeType.PROJECT) {
+ if (scopeType == null || scopeType.scopeType().equals(Scope.ScopeType.PROJECT)) {
flagsWithIncompleteScopeInfo.add(entry.getKey());
}
}
@@ -275,7 +275,7 @@
boolean shouldApplyScopes =
buildOptionsScopeValue.getFullyResolvedScopes().values().stream()
- .anyMatch(scope -> scope.getScopeType() == Scope.ScopeType.PROJECT);
+ .anyMatch(scope -> scope.getScopeType().scopeType().equals(Scope.ScopeType.PROJECT));
if (!shouldApplyScopes) {
return finishConfigurationKeyProcessing(
@@ -342,9 +342,12 @@
Scope scope = buildOptionsScopeValue.getFullyResolvedScopes().get(flagLabel);
if (scope == null) {
Verify.verify(
- transitionedOptionsWithScopeType.getScopeTypeMap().get(flagLabel)
- != Scope.ScopeType.PROJECT);
- } else if (scope.getScopeType() == Scope.ScopeType.PROJECT) {
+ !transitionedOptionsWithScopeType
+ .getScopeTypeMap()
+ .get(flagLabel)
+ .scopeType()
+ .equals(Scope.ScopeType.PROJECT));
+ } else if (scope.getScopeType().scopeType().equals(Scope.ScopeType.PROJECT)) {
Object flagValue = flagEntry.getValue();
Object baselineValue = baselineConfiguration.getStarlarkOptions().get(flagLabel);
if (flagValue != baselineValue && !isInScope(label, scope.getScopeDefinition())) {
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/starlark/FunctionTransitionUtil.java b/src/main/java/com/google/devtools/build/lib/analysis/starlark/FunctionTransitionUtil.java
index d667c0d..c0e4a2d 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/starlark/FunctionTransitionUtil.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/starlark/FunctionTransitionUtil.java
@@ -236,9 +236,11 @@
// setting "scope = 'target'".
return starlarkOptions.entrySet().stream()
.filter(
- entry ->
- options.getScopeTypeMap().get(entry.getKey()) == Scope.ScopeType.UNIVERSAL
- || options.getScopeTypeMap().get(entry.getKey()) == Scope.ScopeType.DEFAULT)
+ entry -> {
+ String scopeType = options.getScopeTypeMap().get(entry.getKey()).scopeType();
+ return scopeType.equals(Scope.ScopeType.UNIVERSAL)
+ || scopeType.equals(Scope.ScopeType.DEFAULT);
+ })
.collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
}
@@ -256,9 +258,10 @@
ImmutableMap.Builder<Label, Object> ans = ImmutableMap.builder();
for (Map.Entry<Label, Object> entry : starlarkOptions.entrySet()) {
- if (options.getScopeTypeMap().get(entry.getKey()) == Scope.ScopeType.UNIVERSAL) {
+ String scopeType = options.getScopeTypeMap().get(entry.getKey()).scopeType();
+ if (scopeType.equals(Scope.ScopeType.UNIVERSAL)) {
ans.put(entry);
- } else if (options.getScopeTypeMap().get(entry.getKey()) == Scope.ScopeType.TARGET) {
+ } else if (scopeType.equals(Scope.ScopeType.TARGET)) {
// Don't propagate this flag.
} else if (customPropagatingFlags.contains(entry.getKey().getUnambiguousCanonicalForm())) {
ans.put(entry);
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BuildOptionsScopeFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/BuildOptionsScopeFunction.java
index 5d786d6..ba558ce 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BuildOptionsScopeFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BuildOptionsScopeFunction.java
@@ -134,7 +134,7 @@
Map<Label, ProjectFilesLookupValue.Key> targetsToSkyKeys = new HashMap<>();
for (Label starlarkOption : scopes.keySet()) {
- if (scopes.get(starlarkOption).getScopeType() == Scope.ScopeType.PROJECT) {
+ if (scopes.get(starlarkOption).getScopeType().scopeType().equals(Scope.ScopeType.PROJECT)) {
targetsToSkyKeys.put(
starlarkOption, ProjectFilesLookupValue.key(starlarkOption.getPackageIdentifier()));
}
@@ -184,9 +184,9 @@
// value when --incompatible_exclude_starlark_flags_from_exec_config is stably enabled
// and existing rules like skylib's have updated to TARGET.
|| !attrs.isAttributeValueExplicitlySpecified("scope")) {
- return Scope.ScopeType.DEFAULT;
+ return new Scope.ScopeType(Scope.ScopeType.DEFAULT);
}
- return Scope.ScopeType.valueOfIgnoreCase(attrs.get("scope", Type.STRING));
+ return new Scope.ScopeType(attrs.get("scope", Type.STRING));
}
/**
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/producers/BuildConfigurationKeyProducerTest.java b/src/test/java/com/google/devtools/build/lib/analysis/producers/BuildConfigurationKeyProducerTest.java
index 0d3570f..61055f7 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/producers/BuildConfigurationKeyProducerTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/producers/BuildConfigurationKeyProducerTest.java
@@ -552,9 +552,9 @@
ImmutableMap<Label, Scope.ScopeType> expectedScopeTypeMap =
ImmutableMap.of(
Label.parseCanonicalUnchecked("//flag:foo"),
- Scope.ScopeType.PROJECT,
+ new Scope.ScopeType(Scope.ScopeType.PROJECT),
Label.parseCanonicalUnchecked("//flag:bar"),
- Scope.ScopeType.UNIVERSAL);
+ new Scope.ScopeType(Scope.ScopeType.UNIVERSAL));
assertThat(result.getOptions().getScopeTypeMap())
.containsExactlyEntriesIn(expectedScopeTypeMap);
}
@@ -660,11 +660,11 @@
ImmutableMap<Label, Scope.ScopeType> expectedScopeTypeMap =
ImmutableMap.of(
Label.parseCanonicalUnchecked("//flag:foo"),
- Scope.ScopeType.PROJECT,
+ new Scope.ScopeType(Scope.ScopeType.PROJECT),
Label.parseCanonicalUnchecked("//flag:bar"),
- Scope.ScopeType.UNIVERSAL,
+ new Scope.ScopeType(Scope.ScopeType.UNIVERSAL),
Label.parseCanonicalUnchecked("//out_of_scope_flag:baz"),
- Scope.ScopeType.PROJECT);
+ new Scope.ScopeType(Scope.ScopeType.PROJECT));
assertThat(result.getOptions().getScopeTypeMap())
.containsExactlyEntriesIn(expectedScopeTypeMap);
}
@@ -698,9 +698,9 @@
ImmutableMap<Label, Scope.ScopeType> expectedScopeTypeMap =
ImmutableMap.of(
Label.parseCanonicalUnchecked("//flag:foo"),
- Scope.ScopeType.UNIVERSAL,
+ new Scope.ScopeType(Scope.ScopeType.UNIVERSAL),
Label.parseCanonicalUnchecked("//flag:bar"),
- Scope.ScopeType.UNIVERSAL);
+ new Scope.ScopeType(Scope.ScopeType.UNIVERSAL));
assertThat(result.getOptions().getScopeTypeMap())
.containsExactlyEntriesIn(expectedScopeTypeMap);
}
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/BuildOptionsScopeFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/BuildOptionsScopeFunctionTest.java
index 50170de..ac16ad0 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/BuildOptionsScopeFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/BuildOptionsScopeFunctionTest.java
@@ -25,7 +25,6 @@
import com.google.devtools.build.lib.analysis.config.FragmentOptions;
import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
import com.google.devtools.build.lib.analysis.config.Scope;
-import com.google.devtools.build.lib.analysis.config.Scope.ScopeType;
import com.google.devtools.build.lib.analysis.util.AnalysisMock;
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.cmdline.Label;
@@ -170,19 +169,19 @@
ImmutableMap.of(
Label.parseCanonical("//test_flags:foo"),
new Scope(
- Scope.ScopeType.PROJECT,
+ new Scope.ScopeType(Scope.ScopeType.PROJECT),
new Scope.ScopeDefinition(ImmutableSet.of("//my_project/"))),
Label.parseCanonical("//test_flags:bar"),
- new Scope(ScopeType.UNIVERSAL, null))));
+ new Scope(new Scope.ScopeType(Scope.ScopeType.UNIVERSAL), null))));
// verify that the BuildOptionsScopeValue.getResolvedBuildOptionsWithScopeTypes() has the
// correct ScopeType map for all flags.
assertThat(buildOptionsScopeValue.getResolvedBuildOptionsWithScopeTypes().getScopeTypeMap())
.containsExactly(
Label.parseCanonical("//test_flags:foo"),
- Scope.ScopeType.PROJECT,
+ new Scope.ScopeType(Scope.ScopeType.PROJECT),
Label.parseCanonical("//test_flags:bar"),
- Scope.ScopeType.UNIVERSAL);
+ new Scope.ScopeType(Scope.ScopeType.UNIVERSAL));
}
@Test
@@ -223,7 +222,7 @@
.equals(
ImmutableMap.of(
Label.parseCanonical("//test_flags:foo"),
- new Scope(Scope.ScopeType.PROJECT, null))));
+ new Scope(new Scope.ScopeType(Scope.ScopeType.PROJECT), null))));
}
private BuildOptionsScopeValue executeFunction(BuildOptionsScopeValue.Key key) throws Exception {