add on_leave_scope to BuildOptions. This is pretty much the same with the StarlarkOptions map in BuildOptions.
PiperOrigin-RevId: 846001362
Change-Id: If804a47ffcac73063eee766849c3573c478d8ff6
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 067cdae..458d49a 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
@@ -116,6 +116,7 @@
.addStarlarkOptions(labelizeStarlarkOptions(provider.getStarlarkOptions()))
.addScopeTypeMap(
convertScopesAttributes(provider.getScopesAttributes(), provider.getStarlarkOptions()))
+ .addOnLeaveScopeValues(labelizeStarlarkOptions(provider.getOnLeaveScopeValues()))
.build();
}
@@ -189,6 +190,7 @@
}
fingerprint.addString(OptionsBase.mapToCacheKey(starlarkOptionsMap));
fingerprint.addString(OptionsBase.mapToCacheKey(scopes));
+ fingerprint.addString(OptionsBase.mapToCacheKey(onLeaveScopeValuesMap));
checksum = fingerprint.hexDigestAndReset();
}
}
@@ -217,6 +219,7 @@
.add("fragmentOptions", fragmentOptionsMap.values())
.add("starlarkOptions", starlarkOptionsMap)
.add("scopes", scopes)
+ .add("onLeaveScopeValues", onLeaveScopeValuesMap)
.toString();
}
@@ -249,6 +252,11 @@
return scopes;
}
+ /** Starlark on-leave scope values, sorted lexicographically by name. */
+ public ImmutableMap<Label, Object> getOnLeaveScopeValues() {
+ return onLeaveScopeValuesMap;
+ }
+
/**
* Creates a copy of the BuildOptions object that contains copies of the FragmentOptions and
* Starlark options.
@@ -265,7 +273,8 @@
// Note that this assumes that starlark option values are immutable.
ImmutableMap<Label, Object> starlarkOptions = ImmutableMap.copyOf(starlarkOptionsMap);
ImmutableMap<Label, Scope.ScopeType> scopes = this.scopes;
- return new BuildOptions(nativeOptions, starlarkOptions, scopes);
+ ImmutableMap<Label, Object> onLeaveScopeValues = ImmutableMap.copyOf(onLeaveScopeValuesMap);
+ return new BuildOptions(nativeOptions, starlarkOptions, scopes, onLeaveScopeValues);
}
@Override
@@ -299,6 +308,9 @@
/** Maps Starlark options names to {@link Scope} information */
private final ImmutableMap<Label, Scope.ScopeType> scopes;
+ /** Maps Starlark options names to their on-leave scope values. */
+ private final ImmutableMap<Label, Object> onLeaveScopeValuesMap;
+
// Lazily initialized both for performance and correctness - BuildOptions instances may be mutated
// after construction but before consumption. Access via checksum() to ensure initialization. This
// field is volatile as per https://errorprone.info/bugpattern/DoubleCheckedLocking, which
@@ -308,10 +320,12 @@
private BuildOptions(
ImmutableMap<Class<? extends FragmentOptions>, FragmentOptions> fragmentOptionsMap,
ImmutableMap<Label, Object> starlarkOptionsMap,
- ImmutableMap<Label, Scope.ScopeType> scopes) {
+ ImmutableMap<Label, Scope.ScopeType> scopes,
+ ImmutableMap<Label, Object> onLeaveScopeValuesMap) {
this.fragmentOptionsMap = fragmentOptionsMap;
this.starlarkOptionsMap = starlarkOptionsMap;
this.scopes = scopes;
+ this.onLeaveScopeValuesMap = onLeaveScopeValuesMap;
}
/**
@@ -391,6 +405,7 @@
}
this.addStarlarkOptions(options.getStarlarkOptions());
this.addScopeTypeMap(options.getScopeTypeMap());
+ this.addOnLeaveScopeValues(options.getOnLeaveScopeValues());
return this;
}
@@ -469,6 +484,29 @@
public Builder removeStarlarkOption(Label key) {
starlarkOptions.remove(key);
removeScope(key);
+ onLeaveScopeValues.remove(key);
+ return this;
+ }
+
+ /**
+ * Adds multiple Starlark on-leave scope values to the builder. Overrides previous instances of
+ * the same key.
+ */
+ @CanIgnoreReturnValue
+ public Builder addOnLeaveScopeValues(Map<Label, Object> options) {
+ onLeaveScopeValues.putAll(options);
+ return this;
+ }
+
+ @CanIgnoreReturnValue
+ public Builder addOnLeaveScopeValue(Label key, Object value) {
+ onLeaveScopeValues.put(key, value);
+ return this;
+ }
+
+ @CanIgnoreReturnValue
+ public Builder removeOnLeaveScopeValue(Label key) {
+ onLeaveScopeValues.remove(key);
return this;
}
@@ -476,7 +514,8 @@
return new BuildOptions(
sortedImmutableHashMap(fragmentOptions, LEXICAL_FRAGMENT_OPTIONS_COMPARATOR),
sortedImmutableHashMap(starlarkOptions, naturalOrder()),
- sortedImmutableHashMap(scopes, naturalOrder()));
+ sortedImmutableHashMap(scopes, naturalOrder()),
+ sortedImmutableHashMap(onLeaveScopeValues, naturalOrder()));
}
/**
@@ -500,6 +539,7 @@
// TODO: b/377559852 - Merge scopes into starlarkOptionsMap
private final LinkedHashMap<Label, Scope.ScopeType> scopes = new LinkedHashMap<>();
+ private final LinkedHashMap<Label, Object> onLeaveScopeValues = new LinkedHashMap<>();
private Builder() {}
}
@@ -534,6 +574,7 @@
context.putSharedValue(options.fragmentOptionsMap, null, IMMUTABLE_MAP_CODEC, codedOut);
context.putSharedValue(options.starlarkOptionsMap, null, IMMUTABLE_MAP_CODEC, codedOut);
context.putSharedValue(options.scopes, null, IMMUTABLE_MAP_CODEC, codedOut);
+ context.putSharedValue(options.onLeaveScopeValuesMap, null, IMMUTABLE_MAP_CODEC, codedOut);
}
@Override
@@ -555,6 +596,12 @@
DeserializationBuilder::setStarlarkOptionsMap);
context.getSharedValue(
codedIn, null, IMMUTABLE_MAP_CODEC, builder, DeserializationBuilder::setScopes);
+ context.getSharedValue(
+ codedIn,
+ null,
+ IMMUTABLE_MAP_CODEC,
+ builder,
+ DeserializationBuilder::setOnLeaveScopeValuesMap);
return builder;
}
@@ -565,10 +612,12 @@
ImmutableMap<Label, Object> starlarkOptionsMap;
// TODO: b/377559852 - Merge scopes into starlarkOptionsMap
ImmutableMap<Label, Scope.ScopeType> scopes;
+ ImmutableMap<Label, Object> onLeaveScopeValuesMap;
@Override
public BuildOptions call() {
- return new BuildOptions(fragmentOptionsMap, starlarkOptionsMap, scopes);
+ return new BuildOptions(
+ fragmentOptionsMap, starlarkOptionsMap, scopes, onLeaveScopeValuesMap);
}
@SuppressWarnings("unchecked")
@@ -586,6 +635,11 @@
private static void setScopes(DeserializationBuilder builder, Object value) {
builder.scopes = (ImmutableMap<Label, Scope.ScopeType>) value;
}
+
+ @SuppressWarnings("unchecked")
+ private static void setOnLeaveScopeValuesMap(DeserializationBuilder builder, Object value) {
+ builder.onLeaveScopeValuesMap = (ImmutableMap<Label, Object>) value;
+ }
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java
index c43f79d..d75e296 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java
@@ -185,6 +185,7 @@
private final LoadingCache<Class<? extends OptionsBase>, Optional<OptionsBase>> optionsCache;
private final Map<String, Object> starlarkOptions;
private final Map<String, String> scopesAttributes;
+ private final Map<String, Object> onLeaveScopeValues;
/** A human-readable description of all the non-default option settings. */
private final String optionsDescription;
@@ -237,6 +238,7 @@
});
this.starlarkOptions = options.getStarlarkOptions();
this.scopesAttributes = options.getScopesAttributes();
+ this.onLeaveScopeValues = options.getOnLeaveScopeValues();
this.needsInstrumentationFilter = needsInstrumentationFilter;
this.runTests = runTests;
this.checkForActionConflicts = checkForActionConflicts;
@@ -278,6 +280,11 @@
}
@Override
+ public Map<String, Object> getOnLeaveScopeValues() {
+ return onLeaveScopeValues;
+ }
+
+ @Override
public Map<String, Object> getExplicitStarlarkOptions(
Predicate<? super ParsedOptionDescription> filter) {
throw new UnsupportedOperationException("No known callers to this implementation");
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/StarlarkOptionsParser.java b/src/main/java/com/google/devtools/build/lib/runtime/StarlarkOptionsParser.java
index c68fdb8..0f6ddcc 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/StarlarkOptionsParser.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/StarlarkOptionsParser.java
@@ -114,6 +114,9 @@
// Map of starlark options to their {@link Scope.ScopeType}.
private final Map<String, String> scopes = new TreeMap<>();
+ // Map of starlark options to their on-leave scope values.
+ private final Map<String, Object> onLeaveScopeValues = new TreeMap<>();
+
// Map of parsed starlark options to their loaded BuildSetting objects (used for canonicalization)
private final Map<String, BuildSetting> parsedBuildSettings = new LinkedHashMap<>();
@@ -226,6 +229,7 @@
Map<String, Object> parsedOptions = new HashMap<>();
Map<String, String> scopeTypeMap = new HashMap<>();
+ Map<String, Object> onLeaveScopeMap = new HashMap<>();
for (String buildSetting : buildSettingWithTargetAndValue.keySet()) {
Pair<Target, Object> buildSettingAndFinalValue =
buildSettingWithTargetAndValue.get(buildSetting);
@@ -272,11 +276,19 @@
}
scopeTypeMap.put(buildSetting, scopeType);
nativeOptionsParser.setScopesAttributes(ImmutableMap.copyOf(scopeTypeMap));
+
+ if (attrMap.isAttributeValueExplicitlySpecified("on_leave_scope")) {
+ var onLeaveScopeValue = attrMap.get("on_leave_scope", buildSettingObject.getType());
+ if (onLeaveScopeValue != null) {
+ onLeaveScopeMap.put(buildSetting, onLeaveScopeValue);
+ }
+ }
}
nativeOptionsParser.setStarlarkOptions(ImmutableMap.copyOf(parsedOptions));
this.starlarkOptions.putAll(parsedOptions);
this.scopes.putAll(scopeTypeMap);
+ this.onLeaveScopeValues.putAll(onLeaveScopeMap);
return true;
}
@@ -432,6 +444,10 @@
return ImmutableMap.copyOf(this.buildSettingDefaults);
}
+ public ImmutableMap<String, Object> getOnLeaveScopeValues() {
+ return ImmutableMap.copyOf(this.onLeaveScopeValues);
+ }
+
public boolean checkIfParsedOptionAllowsMultiple(String option) {
BuildSetting setting = parsedBuildSettings.get(option);
return setting.allowsMultiple() || setting.isRepeatableFlag();
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 ba558ce..44dd9d2 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
@@ -64,18 +64,25 @@
LinkedHashMap<Label, Scope> scopes = new LinkedHashMap<>();
for (Label scopedFlag : key.getFlagsWithIncompleteScopeInfo()) {
Scope.ScopeType scopeType = key.getBuildOptions().getScopeTypeMap().get(scopedFlag);
+ Object onLeaveScopeValue = key.getBuildOptions().getOnLeaveScopeValues().get(scopedFlag);
if (scopeType == null) {
- scopeType = getScopeType(env, scopedFlag, scopedFlag.getPackageIdentifier());
- if (scopeType == null) {
+ Target target = getTarget(env, scopedFlag, scopedFlag.getPackageIdentifier());
+ if (target == null) {
return null;
}
+ scopeType = getScopeType(target);
+ onLeaveScopeValue = getOnleaveScopeValue(target);
}
scopes.put(scopedFlag, new Scope(scopeType, null));
// this is needed because the final BuildOptions used to create the BuildConfigurationKey
// needs to have the scopeType set for all starlark flags.
fullyResolvedBuildOptionsBuilder =
- fullyResolvedBuildOptionsBuilder.addScopeType(scopedFlag, scopeType);
+ onLeaveScopeValue != null
+ ? fullyResolvedBuildOptionsBuilder
+ .addScopeType(scopedFlag, scopeType)
+ .addOnLeaveScopeValue(scopedFlag, onLeaveScopeValue)
+ : fullyResolvedBuildOptionsBuilder.addScopeType(scopedFlag, scopeType);
}
// get PROJECT.scl files for each scoped flag that is not universal
@@ -160,9 +167,7 @@
return projectFiles.build();
}
- @Nullable
- private Scope.ScopeType getScopeType(
- Environment env, Label label, PackageIdentifier packageIdentifier)
+ private Target getTarget(Environment env, Label label, PackageIdentifier packageIdentifier)
throws BuildOptionsScopeFunctionException, InterruptedException {
PackageContext packageContext = PackageContext.of(packageIdentifier, RepositoryMapping.EMPTY);
SkyframeTargetLoader targetLoader = new SkyframeTargetLoader(env, packageContext);
@@ -178,6 +183,11 @@
return null;
}
+ return target;
+ }
+
+ private Scope.ScopeType getScopeType(Target target) {
+
var attrs = RawAttributeMapper.of(target.getAssociatedRule());
if (!attrs.has("scope", Type.STRING)
// TODO: https://github.com/bazelbuild/bazel/issues/26909 - Honor the rule's actual
@@ -189,6 +199,19 @@
return new Scope.ScopeType(attrs.get("scope", Type.STRING));
}
+ @Nullable
+ private Object getOnleaveScopeValue(Target target) {
+ var attrs = RawAttributeMapper.of(target.getAssociatedRule());
+ if (!attrs.has("on_leave_scope")) {
+ // do nothing if on_leave_scope is not set.
+ return null;
+ }
+
+ return attrs.get(
+ "on_leave_scope",
+ target.getAssociatedRule().getRuleClassObject().getBuildSetting().getType());
+ }
+
/**
* Same as {@link ParsedFlagsFunction.SkyframeTargetLoader} but forking it here to avoid circular
* dependencies.
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index f4ba7d5..89bd852 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -3620,6 +3620,11 @@
}
@Override
+ public ImmutableMap<String, Object> getOnLeaveScopeValues() {
+ return ImmutableMap.of();
+ }
+
+ @Override
public ImmutableMap<String, Object> getExplicitStarlarkOptions(
java.util.function.Predicate<? super ParsedOptionDescription> filter) {
return ImmutableMap.of();
diff --git a/src/main/java/com/google/devtools/build/lib/testing/common/FakeOptions.java b/src/main/java/com/google/devtools/build/lib/testing/common/FakeOptions.java
index 043ad5e..982ea03 100644
--- a/src/main/java/com/google/devtools/build/lib/testing/common/FakeOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/testing/common/FakeOptions.java
@@ -115,6 +115,11 @@
}
@Override
+ public ImmutableMap<String, Object> getOnLeaveScopeValues() {
+ return ImmutableMap.of();
+ }
+
+ @Override
public Map<String, Object> getExplicitStarlarkOptions(
Predicate<? super ParsedOptionDescription> filter) {
return ImmutableMap.of();
diff --git a/src/main/java/com/google/devtools/common/options/OptionsParser.java b/src/main/java/com/google/devtools/common/options/OptionsParser.java
index 87298c3..59dff45 100644
--- a/src/main/java/com/google/devtools/common/options/OptionsParser.java
+++ b/src/main/java/com/google/devtools/common/options/OptionsParser.java
@@ -285,6 +285,7 @@
private ImmutableSortedMap<String, Object> starlarkOptions = ImmutableSortedMap.of();
// scopes for starlark options
private ImmutableSortedMap<String, String> scopesAttributes = ImmutableSortedMap.of();
+ private final ImmutableSortedMap<String, Object> onLeaveScopeValues = ImmutableSortedMap.of();
private final Map<String, String> aliases = new HashMap<>();
private boolean success = true;
@@ -309,6 +310,11 @@
}
@Override
+ public ImmutableMap<String, Object> getOnLeaveScopeValues() {
+ return onLeaveScopeValues;
+ }
+
+ @Override
public ImmutableSortedMap<String, Object> getExplicitStarlarkOptions(
Predicate<? super ParsedOptionDescription> filter) {
ImmutableSet<String> explicitOptions =
diff --git a/src/main/java/com/google/devtools/common/options/OptionsProvider.java b/src/main/java/com/google/devtools/common/options/OptionsProvider.java
index 09420b9..3fcb2ac 100644
--- a/src/main/java/com/google/devtools/common/options/OptionsProvider.java
+++ b/src/main/java/com/google/devtools/common/options/OptionsProvider.java
@@ -42,6 +42,11 @@
}
@Override
+ public ImmutableMap<String, Object> getOnLeaveScopeValues() {
+ return ImmutableMap.of();
+ }
+
+ @Override
public ImmutableMap<String, Object> getExplicitStarlarkOptions(
Predicate<? super ParsedOptionDescription> filter) {
return ImmutableMap.of();
@@ -87,4 +92,6 @@
ImmutableMap<String, String> getUserOptions();
Map<String, String> getScopesAttributes();
+
+ Map<String, Object> getOnLeaveScopeValues();
}