Allow starlark transitions to read starlark-defined options.
Calculate and supply defaults for all read starlark options before transitions are applied. Future work includes:
- combining skyfunction calls for inputs and outputs of starlark transitions
- enforcing that BuildOptions.starlarkOptions will never hold default values (opposite of native options which always hold default values) in order to make BuildConfigurationWithDefault == BuildConfigurationWithNoValue
- Making sure BuildConfiguration properly reflects StarlarkOptions
Work towards #5574, #5577, #5578
RELNOTES: None.
PiperOrigin-RevId: 242681946
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
index 0c50d85..6bc26ec 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
@@ -1090,13 +1090,14 @@
private final Supplier<BuildConfigurationEvent> buildEventSupplier;
/**
- * Returns true if this configuration is semantically equal to the other, with
- * the possible exception that the other has fewer fragments.
+ * Returns true if this configuration is semantically equal to the other, with the possible
+ * exception that the other has fewer fragments.
*
* <p>This is useful for trimming: as the same configuration gets "trimmed" while going down a
* dependency chain, it's still the same configuration but loses some of its fragments. So we need
* a more nuanced concept of "equality" than simple reference equality.
*/
+ // TODO(b/121048710): make this reflect starlark options
public boolean equalsOrIsSupersetOf(BuildConfiguration other) {
return this.equals(other)
|| (other != null
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 6a2bc62..870116a0 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
@@ -496,6 +496,11 @@
return this;
}
+ /** Returns whether the builder contains a particular Starlark option. */
+ boolean contains(Label key) {
+ return starlarkOptions.containsKey(key);
+ }
+
/** Removes the value for the Starlark option with the given key. */
public Builder removeStarlarkOption(Label key) {
starlarkOptions.remove(key);
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java
index af1b663..c155b51 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java
@@ -20,6 +20,7 @@
import com.google.common.base.Verify;
import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedHashMultimap;
@@ -218,13 +219,21 @@
FragmentsAndTransition transitionKey = new FragmentsAndTransition(depFragments, transition);
List<BuildOptions> toOptions = transitionsMap.get(transitionKey);
if (toOptions == null) {
+ // Default values for all build settings read in {@code transition}
+ ImmutableMap<Label, Object> defaultBuildSettingValues;
+ try {
+ defaultBuildSettingValues = StarlarkTransition.getDefaultInputValues(env, transition);
+ } catch (TransitionException e) {
+ throw new ConfiguredTargetFunction.DependencyEvaluationException(e);
+ }
toOptions =
applyTransition(
currentConfiguration.getOptions(),
transition,
depFragments,
ruleClassProvider,
- !sameFragments);
+ !sameFragments,
+ defaultBuildSettingValues);
transitionsMap.put(transitionKey, toOptions);
}
@@ -233,7 +242,7 @@
// configured target.
try {
ImmutableSet<SkyKey> buildSettingPackageKeys =
- StarlarkTransition.getBuildSettingPackageKeys(transition);
+ StarlarkTransition.getBuildSettingPackageKeys(transition, "outputs");
Map<SkyKey, SkyValue> buildSettingPackages = env.getValues(buildSettingPackageKeys);
if (env.valuesMissing()) {
return null;
@@ -458,18 +467,22 @@
/**
* Applies a configuration transition over a set of build options.
*
- * @return the build options for the transitioned configuration. If trimResults is true,
- * only options needed by the required fragments are included. Else the same options as the
+ * @return the build options for the transitioned configuration. If trimResults is true, only
+ * options needed by the required fragments are included. Else the same options as the
* original input are included (with different possible values, of course).
*/
@VisibleForTesting
- public static List<BuildOptions> applyTransition(BuildOptions fromOptions,
+ public static List<BuildOptions> applyTransition(
+ BuildOptions fromOptions,
ConfigurationTransition transition,
Iterable<Class<? extends BuildConfiguration.Fragment>> requiredFragments,
- RuleClassProvider ruleClassProvider, boolean trimResults) {
+ RuleClassProvider ruleClassProvider,
+ boolean trimResults,
+ ImmutableMap<Label, Object> buildSettingDefaults) {
+ BuildOptions fromOptionsWithDefaults =
+ addDefaultStarlarkOptions(fromOptions, buildSettingDefaults);
// TODO(bazel-team): safety-check that this never mutates fromOptions.
- List<BuildOptions> result = transition.apply(fromOptions);
-
+ List<BuildOptions> result = transition.apply(fromOptionsWithDefaults);
if (!trimResults) {
return result;
} else {
@@ -482,6 +495,18 @@
}
}
+ private static BuildOptions addDefaultStarlarkOptions(
+ BuildOptions fromOptions, ImmutableMap<Label, Object> buildSettingDefaults) {
+ BuildOptions.Builder optionsWithDefaults = fromOptions.toBuilder();
+ for (Map.Entry<Label, Object> buildSettingDefault : buildSettingDefaults.entrySet()) {
+ Label buildSetting = buildSettingDefault.getKey();
+ if (!optionsWithDefaults.contains(buildSetting)) {
+ optionsWithDefaults.addStarlarkOption(buildSetting, buildSettingDefault.getValue());
+ }
+ }
+ return optionsWithDefaults.build();
+ }
+
/**
* Checks the config fragments required by a dep against the fragments in its actual
* configuration. If any are missing, triggers a descriptive "missing fragments" error.
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/FunctionTransitionUtil.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/FunctionTransitionUtil.java
index 0237af7..07f2649 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/FunctionTransitionUtil.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/FunctionTransitionUtil.java
@@ -160,6 +160,7 @@
try (Mutability mutability = Mutability.create("build_settings")) {
SkylarkDict<String, Object> dict = SkylarkDict.withMutability(mutability);
+ // Add native options
for (Map.Entry<String, OptionInfo> entry : optionInfoMap.entrySet()) {
String optionName = entry.getKey();
String optionKey = COMMAND_LINE_OPTION_PREFIX + optionName;
@@ -182,7 +183,14 @@
}
}
- // TODO(juliexxia): Allowing reading of starlark-defined build settings.
+ // Add Starlark options
+ for (Map.Entry<Label, Object> starlarkOption : buildOptions.getStarlarkOptions().entrySet()) {
+ if (!remainingInputs.remove(starlarkOption.getKey().toString())) {
+ continue;
+ }
+ dict.put(starlarkOption.getKey().toString(), starlarkOption.getValue(), null, mutability);
+ }
+
if (!remainingInputs.isEmpty()) {
throw new EvalException(
starlarkTransition.getLocationForErrorReporting(),
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/StarlarkTransition.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/StarlarkTransition.java
index 46974c0..1c8ad1b 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/StarlarkTransition.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/StarlarkTransition.java
@@ -14,7 +14,10 @@
package com.google.devtools.build.lib.analysis.skylark;
import static com.google.devtools.build.lib.analysis.skylark.FunctionTransitionUtil.COMMAND_LINE_OPTION_PREFIX;
+import static com.google.devtools.build.lib.packages.RuleClass.Builder.SKYLARK_BUILD_SETTING_DEFAULT_ATTR_NAME;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
@@ -29,6 +32,7 @@
import com.google.devtools.build.lib.skyframe.PackageValue;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.syntax.Type.ConversionException;
+import com.google.devtools.build.skyframe.SkyFunction.Environment;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import java.util.List;
@@ -54,6 +58,10 @@
return starlarkDefinedConfigTransition.getEventHandler().hasErrors();
}
+ private List<String> getInputs() {
+ return starlarkDefinedConfigTransition.getInputs();
+ }
+
private List<String> getOutputs() {
return starlarkDefinedConfigTransition.getOutputs();
}
@@ -78,23 +86,27 @@
}
/**
- * For a given transition, find all Starlark-defined build settings that were set by that
- * transition. Then return all package keys for those flags.
+ * For a given transition, find all relevant Starlark-defined build settings. Then return all
+ * package keys for those flags.
*
* <p>Currently this method does not handle the possibility of aliased build settings. We may not
* actually load the package that actually contains the build setting but we won't know until we
* fetch the actual target.
+ *
+ * @param root transition to inspect
+ * @param inputsOrOutputs whether to return inputs or outputs
*/
// TODO(juliexxia): handle the possibility of aliased build settings.
- public static ImmutableSet<SkyKey> getBuildSettingPackageKeys(ConfigurationTransition root) {
+ public static ImmutableSet<SkyKey> getBuildSettingPackageKeys(
+ ConfigurationTransition root, String inputsOrOutputs) {
ImmutableSet.Builder<SkyKey> keyBuilder = new ImmutableSet.Builder<>();
try {
root.visit(
(StarlarkTransitionVisitor)
transition -> {
- for (Label setting : getChangedStarlarkSettings(transition)) {
- keyBuilder.add(PackageValue.key(setting.getPackageIdentifier()));
- }
+ keyBuilder.addAll(
+ getBuildSettingPackageKeys(
+ getRelevantStarlarkSettingsFromTransition(transition, inputsOrOutputs)));
});
} catch (TransitionException e) {
// Not actually thrown in the visitor, but declared.
@@ -102,6 +114,15 @@
return keyBuilder.build();
}
+ private static ImmutableSet<SkyKey> getBuildSettingPackageKeys(
+ ImmutableSet<Label> buildSettings) {
+ ImmutableSet.Builder<SkyKey> keyBuilder = new ImmutableSet.Builder<>();
+ for (Label setting : buildSettings) {
+ keyBuilder.add(PackageValue.key(setting.getPackageIdentifier()));
+ }
+ return keyBuilder.build();
+ }
+
/**
* Method to be called after Starlark-transitions are applied. Handles events and checks outputs.
*
@@ -138,27 +159,11 @@
root.visit(
(StarlarkTransitionVisitor)
transition -> {
- List<Label> changedSettings = getChangedStarlarkSettings(transition);
+ ImmutableSet<Label> changedSettings =
+ getRelevantStarlarkSettingsFromTransition(transition, "outputs");
for (Label setting : changedSettings) {
- Package buildSettingPackage =
- ((PackageValue)
- buildSettingPackages.get(
- PackageValue.key(setting.getPackageIdentifier())))
- .getPackage();
- Target buildSettingTarget;
- try {
- buildSettingTarget = buildSettingPackage.getTarget(setting.getName());
- } catch (NoSuchTargetException e) {
- throw new TransitionException(e);
- }
- if (buildSettingTarget.getAssociatedRule() == null
- || buildSettingTarget.getAssociatedRule().getRuleClassObject().getBuildSetting()
- == null) {
- throw new TransitionException(
- String.format(
- "attempting to transition on '%s' which is not a build setting",
- setting));
- }
+ Target buildSettingTarget =
+ getAndCheckBuildSettingTarget(buildSettingPackages, setting);
changedSettingToType.put(
setting,
buildSettingTarget
@@ -183,11 +188,79 @@
}
}
- private static List<Label> getChangedStarlarkSettings(StarlarkTransition transition) {
- return transition.getOutputs().stream()
- .filter(setting -> !setting.startsWith(COMMAND_LINE_OPTION_PREFIX))
- .map(Label::parseAbsoluteUnchecked)
- .collect(Collectors.toList());
+ /**
+ * For a given transition, find all Starlark build settings that are read while applying it, then
+ * return a map of their label to their default values.
+ */
+ public static ImmutableMap<Label, Object> getDefaultInputValues(
+ Environment env, ConfigurationTransition root)
+ throws TransitionException, InterruptedException {
+ ImmutableSet<SkyKey> buildSettingInputPackageKeys = getBuildSettingPackageKeys(root, "inputs");
+ Map<SkyKey, SkyValue> buildSettingPackages = env.getValues(buildSettingInputPackageKeys);
+ if (env.valuesMissing()) {
+ return null;
+ }
+ return getDefaultInputValues(buildSettingPackages, root);
+ }
+
+ /**
+ * For a given transition, find all Starlark build settings that are read while applying it, then
+ * return a map of their label to their default values.
+ */
+ public static ImmutableMap<Label, Object> getDefaultInputValues(
+ Map<SkyKey, SkyValue> buildSettingPackages, ConfigurationTransition root)
+ throws TransitionException {
+ ImmutableMap.Builder<Label, Object> defaultValues = new ImmutableMap.Builder<>();
+ root.visit(
+ (StarlarkTransitionVisitor)
+ transition -> {
+ ImmutableSet<Label> settings =
+ getRelevantStarlarkSettingsFromTransition(transition, "inputs");
+ for (Label setting : settings) {
+ Target buildSettingTarget =
+ getAndCheckBuildSettingTarget(buildSettingPackages, setting);
+ defaultValues.put(
+ setting,
+ buildSettingTarget
+ .getAssociatedRule()
+ .getAttributeContainer()
+ .getAttr(SKYLARK_BUILD_SETTING_DEFAULT_ATTR_NAME));
+ }
+ });
+ return defaultValues.build();
+ }
+
+ private static Target getAndCheckBuildSettingTarget(
+ Map<SkyKey, SkyValue> buildSettingPackages, Label setting) throws TransitionException {
+ Package buildSettingPackage =
+ ((PackageValue) buildSettingPackages.get(PackageValue.key(setting.getPackageIdentifier())))
+ .getPackage();
+ Preconditions.checkNotNull(
+ buildSettingPackage, "Reading build setting for which we don't have a package");
+ Target buildSettingTarget;
+ try {
+ buildSettingTarget = buildSettingPackage.getTarget(setting.getName());
+ } catch (NoSuchTargetException e) {
+ throw new TransitionException(e);
+ }
+ if (buildSettingTarget.getAssociatedRule() == null
+ || buildSettingTarget.getAssociatedRule().getRuleClassObject().getBuildSetting() == null) {
+ throw new TransitionException(
+ String.format("attempting to transition on '%s' which is not a build setting", setting));
+ }
+ return buildSettingTarget;
+ }
+
+ // TODO(juliexxia): use an enum for "inputs"/"outputs" here and elsewhere in starlark transitions.
+ private static ImmutableSet<Label> getRelevantStarlarkSettingsFromTransition(
+ StarlarkTransition transition, String inputOrOutput) {
+ List<String> toGet =
+ inputOrOutput.equals("inputs") ? transition.getInputs() : transition.getOutputs();
+ return ImmutableSet.copyOf(
+ toGet.stream()
+ .filter(setting -> !setting.startsWith(COMMAND_LINE_OPTION_PREFIX))
+ .map(Label::parseAbsoluteUnchecked)
+ .collect(Collectors.toSet()));
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseFunction.java
index c714150..4d7cd1f 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseFunction.java
@@ -16,6 +16,7 @@
import com.google.common.base.Predicates;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Multimap;
@@ -304,23 +305,34 @@
ImmutableSortedSet<Class<? extends BuildConfiguration.Fragment>> depFragments =
fragmentsMap.get(key.getLabel());
if (depFragments != null) {
+ ImmutableMap<Label, Object> defaultBuildSettingValues =
+ StarlarkTransition.getDefaultInputValues(env, key.getTransition());
+ if (env.valuesMissing()) {
+ return null;
+ }
List<BuildOptions> toOptions =
ConfigurationResolver.applyTransition(
- fromOptions, key.getTransition(), depFragments, ruleClassProvider, true);
+ fromOptions,
+ key.getTransition(),
+ depFragments,
+ ruleClassProvider,
+ true,
+ defaultBuildSettingValues);
for (BuildOptions toOption : toOptions) {
configSkyKeys.add(
BuildConfigurationValue.key(
depFragments, BuildOptions.diffForReconstruction(defaultBuildOptions, toOption)));
}
// Post-process transitions on starlark build settings
- ImmutableSet<SkyKey> buildSettingPackageKeys =
- StarlarkTransition.getBuildSettingPackageKeys(key.getTransition());
- Map<SkyKey, SkyValue> buildSettingPackages = env.getValues(buildSettingPackageKeys);
+ ImmutableSet<SkyKey> buildSettingOutputPackageKeys =
+ StarlarkTransition.getBuildSettingPackageKeys(key.getTransition(), "outputs");
+ Map<SkyKey, SkyValue> buildSettingOutputPackages =
+ env.getValues(buildSettingOutputPackageKeys);
if (env.valuesMissing()) {
return null;
}
StarlarkTransition.validate(
- key.getTransition(), buildSettingPackages, toOptions, env.getListener());
+ key.getTransition(), buildSettingOutputPackages, toOptions, env.getListener());
}
}
Map<SkyKey, SkyValue> configsResult = env.getValues(configSkyKeys);
@@ -337,11 +349,23 @@
ImmutableSortedSet<Class<? extends BuildConfiguration.Fragment>> depFragments =
fragmentsMap.get(key.getLabel());
if (depFragments != null) {
- for (BuildOptions toOptions : ConfigurationResolver.applyTransition(
- fromOptions, key.getTransition(), depFragments, ruleClassProvider, true)) {
+ ImmutableMap<Label, Object> defaultBuildSettingValues =
+ StarlarkTransition.getDefaultInputValues(env, key.getTransition());
+ if (env.valuesMissing()) {
+ return null;
+ }
+ List<BuildOptions> toOptions =
+ ConfigurationResolver.applyTransition(
+ fromOptions,
+ key.getTransition(),
+ depFragments,
+ ruleClassProvider,
+ true,
+ defaultBuildSettingValues);
+ for (BuildOptions toOption : toOptions) {
SkyKey configKey =
BuildConfigurationValue.key(
- depFragments, BuildOptions.diffForReconstruction(defaultBuildOptions, toOptions));
+ depFragments, BuildOptions.diffForReconstruction(defaultBuildOptions, toOption));
BuildConfigurationValue configValue =
((BuildConfigurationValue) configsResult.get(configKey));
// configValue will be null here if there was an exception thrown during configuration
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 ffdb8f9..c1bfd34 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
@@ -1905,23 +1905,36 @@
if (key.getTransition() == NullTransition.INSTANCE) {
continue;
}
+ ImmutableMap<Label, Object> defaultInputValues;
+ try {
+ defaultInputValues =
+ StarlarkTransition.getDefaultInputValues(
+ collectBuildSettingValues(key.getTransition(), eventHandler, "inputs"),
+ key.getTransition());
+ } catch (TransitionException e) {
+ eventHandler.handle(Event.error(e.getMessage()));
+ continue;
+ }
+
List<BuildOptions> toOptions =
ConfigurationResolver.applyTransition(
- fromOptions, key.getTransition(), depFragments, ruleClassProvider, true);
+ fromOptions,
+ key.getTransition(),
+ depFragments,
+ ruleClassProvider,
+ true,
+ defaultInputValues);
for (BuildOptions toOption : toOptions) {
configSkyKeys.add(
BuildConfigurationValue.key(
depFragments, BuildOptions.diffForReconstruction(defaultBuildOptions, toOption)));
}
- ImmutableSet<SkyKey> buildSettingPackageKeys =
- StarlarkTransition.getBuildSettingPackageKeys(key.getTransition());
- EvaluationResult<SkyValue> buildSettingsResult =
- evaluateSkyKeys(eventHandler, buildSettingPackageKeys, true);
- ImmutableMap.Builder<SkyKey, SkyValue> buildSettingValues = new ImmutableMap.Builder<>();
- buildSettingPackageKeys.forEach(k -> buildSettingValues.put(k, buildSettingsResult.get(k)));
try {
StarlarkTransition.validate(
- key.getTransition(), buildSettingValues.build(), toOptions, eventHandler);
+ key.getTransition(),
+ collectBuildSettingValues(key.getTransition(), eventHandler, "outputs"),
+ toOptions,
+ eventHandler);
} catch (TransitionException e) {
eventHandler.handle(Event.error(e.getMessage()));
}
@@ -1940,13 +1953,28 @@
builder.put(key, null);
continue;
}
-
- for (BuildOptions toOptions :
+ ImmutableMap<Label, Object> defaultInputValues;
+ try {
+ defaultInputValues =
+ StarlarkTransition.getDefaultInputValues(
+ collectBuildSettingValues(key.getTransition(), eventHandler, "inputs"),
+ key.getTransition());
+ } catch (TransitionException e) {
+ eventHandler.handle(Event.error(e.getMessage()));
+ continue;
+ }
+ List<BuildOptions> toOptions =
ConfigurationResolver.applyTransition(
- fromOptions, key.getTransition(), depFragments, ruleClassProvider, true)) {
+ fromOptions,
+ key.getTransition(),
+ depFragments,
+ ruleClassProvider,
+ true,
+ defaultInputValues);
+ for (BuildOptions toOption : toOptions) {
SkyKey configKey =
BuildConfigurationValue.key(
- depFragments, BuildOptions.diffForReconstruction(defaultBuildOptions, toOptions));
+ depFragments, BuildOptions.diffForReconstruction(defaultBuildOptions, toOption));
BuildConfigurationValue configValue =
((BuildConfigurationValue) configsResult.get(configKey));
// configValue will be null here if there was an exception thrown during configuration
@@ -1960,6 +1988,20 @@
return builder;
}
+ private Map<SkyKey, SkyValue> collectBuildSettingValues(
+ ConfigurationTransition transition,
+ ExtendedEventHandler eventHandler,
+ String inputsOrOutputs) {
+ ImmutableSet<SkyKey> buildSettingInputPackageKeys =
+ StarlarkTransition.getBuildSettingPackageKeys(transition, inputsOrOutputs);
+ EvaluationResult<SkyValue> buildSettingsResult =
+ evaluateSkyKeys(eventHandler, buildSettingInputPackageKeys, true);
+ ImmutableMap.Builder<SkyKey, SkyValue> buildSettingInputValues = new ImmutableMap.Builder<>();
+ buildSettingInputPackageKeys.forEach(
+ k -> buildSettingInputValues.put(k, buildSettingsResult.get(k)));
+ return buildSettingInputValues.build();
+ }
+
/**
* Returns whether configurations should trim their fragments to only those needed by targets and
* their transitive dependencies.
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/StarlarkRuleTransitionProviderTest.java b/src/test/java/com/google/devtools/build/lib/analysis/StarlarkRuleTransitionProviderTest.java
index 4fa0585..c5bf9d0 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/StarlarkRuleTransitionProviderTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/StarlarkRuleTransitionProviderTest.java
@@ -35,9 +35,7 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-/**
- * Tests for StarlarkRuleTransitionProvider.
- */
+/** Tests for StarlarkRuleTransitionProvider. */
@RunWith(JUnit4.class)
public class StarlarkRuleTransitionProviderTest extends BuildViewTestCase {
@@ -541,26 +539,122 @@
"attempting to transition on '//test:cute-animal-fact' which is not a build setting");
}
- // TODO(juliexxia): flip this test when we can read build settings.
@Test
- public void testCantReadNonNativeBuildSetting() throws Exception {
+ public void testTransitionReadsBuildSetting_fromDefault() throws Exception {
setSkylarkSemanticsOptions(
"--experimental_starlark_config_transitions=true", "--experimental_build_setting_api");
scratch.file(
"test/transitions.bzl",
"def _transition_impl(settings, attr):",
- " return {'//test:cute-animal-fact': settings['//test:cute-animal-fact']+' ADDED'}",
+ " return {'//test:cute-animal-fact': settings['//test:cute-animal-fact']+' <- TRUE'}",
"my_transition = transition(",
" implementation = _transition_impl,",
" inputs = ['//test:cute-animal-fact'],",
- " outputs = ['//test:i-am-not-real']",
+ " outputs = ['//test:cute-animal-fact']",
+ ")");
+ writeRulesBuildSettingsAndBUILDforBuildSettingTransitionTests();
+
+ BuildConfiguration configuration = getConfiguration(getConfiguredTarget("//test"));
+ assertThat(
+ configuration
+ .getOptions()
+ .getStarlarkOptions()
+ .get(Label.parseAbsoluteUnchecked("//test:cute-animal-fact")))
+ .isEqualTo("cows produce more milk when they listen to soothing music <- TRUE");
+ }
+
+ @Test
+ public void testTransitionReadsBuildSetting_fromCommandLine() throws Exception {
+ setSkylarkSemanticsOptions(
+ "--experimental_starlark_config_transitions=true", "--experimental_build_setting_api");
+ scratch.file(
+ "test/transitions.bzl",
+ "def _transition_impl(settings, attr):",
+ " return {'//test:cute-animal-fact': settings['//test:cute-animal-fact']+' <- TRUE'}",
+ "my_transition = transition(",
+ " implementation = _transition_impl,",
+ " inputs = ['//test:cute-animal-fact'],",
+ " outputs = ['//test:cute-animal-fact']",
+ ")");
+ writeRulesBuildSettingsAndBUILDforBuildSettingTransitionTests();
+
+ useConfiguration(ImmutableMap.of("//test:cute-animal-fact", "rats are ticklish"));
+
+ BuildConfiguration configuration = getConfiguration(getConfiguredTarget("//test"));
+ assertThat(
+ configuration
+ .getOptions()
+ .getStarlarkOptions()
+ .get(Label.parseAbsoluteUnchecked("//test:cute-animal-fact")))
+ .isEqualTo("rats are ticklish <- TRUE");
+ }
+
+ @Test
+ public void testTransitionReadsBuildSetting_notABuildSetting() throws Exception {
+ setSkylarkSemanticsOptions(
+ "--experimental_starlark_config_transitions=true", "--experimental_build_setting_api");
+ writeWhitelistFile();
+ scratch.file(
+ "test/transitions.bzl",
+ "def _transition_impl(settings, attr):",
+ " return {'//test:cute-animal-fact': 'puffins mate for life'}",
+ "my_transition = transition(",
+ " implementation = _transition_impl,",
+ " inputs = ['//test:cute-animal-fact'],",
+ " outputs = ['//test:cute-animal-fact']",
+ ")");
+ scratch.file(
+ "test/rules.bzl",
+ "load('//test:transitions.bzl', 'my_transition')",
+ "def _rule_impl(ctx):",
+ " return []",
+ "my_rule = rule(",
+ " implementation = _rule_impl,",
+ " cfg = my_transition,",
+ " attrs = {",
+ " '_whitelist_function_transition': attr.label(",
+ " default = '//tools/whitelists/function_transition_whitelist',",
+ " ),",
+ " },",
+ ")");
+ scratch.file(
+ "test/build_settings.bzl",
+ "def _impl(ctx):",
+ " return []",
+ "non_build_setting = rule(implementation = _impl)");
+ scratch.file(
+ "test/BUILD",
+ "load('//test:rules.bzl', 'my_rule')",
+ "load('//test:build_settings.bzl', 'non_build_setting')",
+ "my_rule(name = 'test')",
+ "non_build_setting(name = 'cute-animal-fact')");
+
+ reporter.removeHandler(failFastHandler);
+ getConfiguredTarget("//test");
+ assertContainsEvent(
+ "attempting to transition on '//test:cute-animal-fact' which is not a build setting");
+ }
+
+ @Test
+ public void testTransitionReadsBuildSetting_noSuchTarget() throws Exception {
+ setSkylarkSemanticsOptions(
+ "--experimental_starlark_config_transitions=true", "--experimental_build_setting_api");
+ scratch.file(
+ "test/transitions.bzl",
+ "def _transition_impl(settings, attr):",
+ " return {'//test:cute-animal-fact': settings['//test:cute-animal-fact']+' <- TRUE'}",
+ "my_transition = transition(",
+ " implementation = _transition_impl,",
+ " inputs = ['//test:i-am-not-real'],",
+ " outputs = ['//test:cute-animal-fact']",
")");
writeRulesBuildSettingsAndBUILDforBuildSettingTransitionTests();
reporter.removeHandler(failFastHandler);
getConfiguredTarget("//test");
assertContainsEvent(
- "transition inputs [//test:cute-animal-fact] do not correspond to valid settings");
+ "no such target '//test:i-am-not-real': target "
+ + "'i-am-not-real' not declared in package 'test'");
}
@Test
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ConfigurationsForTargetsWithTrimmedConfigurationsTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/ConfigurationsForTargetsWithTrimmedConfigurationsTest.java
index b5d1ec49..dc57cd7 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/ConfigurationsForTargetsWithTrimmedConfigurationsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/ConfigurationsForTargetsWithTrimmedConfigurationsTest.java
@@ -23,6 +23,7 @@
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -579,9 +580,14 @@
private List<String> getTestFilterOptionValue(ConfigurationTransition transition)
throws Exception {
ImmutableList.Builder<String> outValues = ImmutableList.builder();
- for (BuildOptions toOptions : ConfigurationResolver.applyTransition(
- getTargetConfiguration().getOptions(), transition,
- ruleClassProvider.getAllFragments(), ruleClassProvider, false)) {
+ for (BuildOptions toOptions :
+ ConfigurationResolver.applyTransition(
+ getTargetConfiguration().getOptions(),
+ transition,
+ ruleClassProvider.getAllFragments(),
+ ruleClassProvider,
+ false,
+ ImmutableMap.of())) {
outValues.add(toOptions.get(TestConfiguration.TestOptions.class).testFilter);
}
return outValues.build();