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 6dde833cdc0528..cabc315d9fe3be 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 @@ -27,8 +27,10 @@ import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.Dependency; import com.google.devtools.build.lib.analysis.TargetAndConfiguration; +import com.google.devtools.build.lib.analysis.config.transitions.ComposingTransition; import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition; import com.google.devtools.build.lib.analysis.config.transitions.NoTransition; +import com.google.devtools.build.lib.analysis.skylark.StarlarkTransition; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.concurrent.ThreadSafety; import com.google.devtools.build.lib.events.Event; @@ -217,6 +219,8 @@ public static OrderedSetMultimap resolveConfigurations( transitionsMap.put(transitionKey, toOptions); } + postProcessStarlarkTransitions(env, transition); + // If the transition doesn't change the configuration, trivially re-use the original // configuration. if (sameFragments && toOptions.size() == 1 @@ -296,6 +300,16 @@ public static OrderedSetMultimap resolveConfigurations( return sortResolvedDeps(originalDeps, resolvedDeps, attributesAndLabels); } + private static void postProcessStarlarkTransitions( + SkyFunction.Environment env, ConfigurationTransition transition) { + ImmutableList transitions = + ComposingTransition.decomposeTransition(transition); + ExtendedEventHandler eventHandler = env.getListener(); + transitions.stream() + .filter(t -> t instanceof StarlarkTransition) + .forEach(t -> ((StarlarkTransition) t).replayOn(eventHandler)); + } + /** * Encapsulates a set of config fragments and a config transition. This can be used to determine * the exact build options needed to set a configuration. @@ -322,6 +336,9 @@ public boolean equals(Object o) { } else if (o == null) { return false; } else { + if (!(o instanceof FragmentsAndTransition)) { + return false; + } FragmentsAndTransition other = (FragmentsAndTransition) o; return other.transition.equals(transition) && other.fragments.equals(fragments); } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/StarlarkDefinedConfigTransition.java b/src/main/java/com/google/devtools/build/lib/analysis/config/StarlarkDefinedConfigTransition.java index 62509db0ad8811..44b4f9690ecd57 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/config/StarlarkDefinedConfigTransition.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/config/StarlarkDefinedConfigTransition.java @@ -16,8 +16,8 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.devtools.build.lib.events.EventHandler; import com.google.devtools.build.lib.events.Location; +import com.google.devtools.build.lib.events.StoredEventHandler; import com.google.devtools.build.lib.packages.StructImpl; import com.google.devtools.build.lib.skylarkbuildapi.config.ConfigurationTransitionApi; import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter; @@ -30,6 +30,7 @@ import com.google.devtools.build.lib.syntax.SkylarkSemantics; import java.util.List; import java.util.Map; +import java.util.Objects; /** * Implementation of {@link ConfigurationTransitionApi}. @@ -41,12 +42,14 @@ public abstract class StarlarkDefinedConfigTransition implements ConfigurationTr private final List inputs; private final List outputs; private final Location location; + private final StoredEventHandler eventHandler; private StarlarkDefinedConfigTransition( List inputs, List outputs, Location location) { this.inputs = inputs; this.outputs = outputs; this.location = location; + this.eventHandler = new StoredEventHandler(); } /** @@ -56,17 +59,16 @@ private StarlarkDefinedConfigTransition( public abstract Boolean isForAnalysisTesting(); /** - * Returns the input option keys for this transition. Only option keys contained in this - * list will be provided in the 'settings' argument given to the transition implementation - * function. + * Returns the input option keys for this transition. Only option keys contained in this list will + * be provided in the 'settings' argument given to the transition implementation function. */ public List getInputs() { return inputs; } /** - * Returns the output option keys for this transition. The transition implementation function - * must return a dictionary where the option keys exactly match the elements of this list. + * Returns the output option keys for this transition. The transition implementation function must + * return a dictionary where the option keys exactly match the elements of this list. */ public List getOutputs() { return outputs; @@ -80,6 +82,10 @@ public Location getLocationForErrorReporting() { return location; } + public StoredEventHandler getEventHandler() { + return eventHandler; + } + /** * Given a map of a subset of the "previous" build settings, returns the changed build settings as * a result of applying this transition. @@ -101,9 +107,8 @@ public static StarlarkDefinedConfigTransition newRegularTransition( List inputs, List outputs, SkylarkSemantics semantics, - EventHandler eventHandler, StarlarkContext context) { - return new RegularTransition(impl, inputs, outputs, semantics, eventHandler, context); + return new RegularTransition(impl, inputs, outputs, semantics, context); } public static StarlarkDefinedConfigTransition newAnalysisTestTransition( @@ -134,12 +139,30 @@ public ImmutableList> getChangedSettings( public void repr(SkylarkPrinter printer) { printer.append(""); } + + @Override + public boolean equals(Object object) { + if (object == this) { + return true; + } + if (object instanceof AnalysisTestTransition) { + AnalysisTestTransition otherTransition = (AnalysisTestTransition) object; + return Objects.equals(otherTransition.getInputs(), this.getInputs()) + && Objects.equals(otherTransition.getOutputs(), this.getOutputs()) + && Objects.equals(otherTransition.changedSettings, this.changedSettings); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(this.getInputs(), this.getOutputs(), this.changedSettings); + } } private static class RegularTransition extends StarlarkDefinedConfigTransition { private final BaseFunction impl; private final SkylarkSemantics semantics; - private final EventHandler eventHandler; private final StarlarkContext starlarkContext; public RegularTransition( @@ -147,12 +170,10 @@ public RegularTransition( List inputs, List outputs, SkylarkSemantics semantics, - EventHandler eventHandler, StarlarkContext context) { super(inputs, outputs, impl.getLocation()); this.impl = impl; this.semantics = semantics; - this.eventHandler = eventHandler; this.starlarkContext = context; } @@ -233,12 +254,31 @@ private Object evalFunction(BaseFunction function, ImmutableList args) Environment env = Environment.builder(mutability) .setSemantics(semantics) - .setEventHandler(eventHandler) + .setEventHandler(getEventHandler()) .setStarlarkContext(starlarkContext) .build(); return function.call(args, ImmutableMap.of(), null, env); } } + + @Override + public boolean equals(Object object) { + if (object == this) { + return true; + } + if (object instanceof RegularTransition) { + RegularTransition otherTransition = (RegularTransition) object; + return Objects.equals(otherTransition.getInputs(), this.getInputs()) + && Objects.equals(otherTransition.getOutputs(), this.getOutputs()) + && Objects.equals(otherTransition.impl, this.impl); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(this.getInputs(), this.getOutputs(), this.impl); + } } } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/transitions/ComposingTransition.java b/src/main/java/com/google/devtools/build/lib/analysis/config/transitions/ComposingTransition.java index 9e0f770a1fdbf4..be38d6ee6417bc 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/config/transitions/ComposingTransition.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/config/transitions/ComposingTransition.java @@ -17,6 +17,7 @@ import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.analysis.config.BuildOptions; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; +import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -82,4 +83,29 @@ public boolean equals(Object other) { && ((ComposingTransition) other).transition1.equals(this.transition1) && ((ComposingTransition) other).transition2.equals(this.transition2); } + + /** + * Recursively decompose a composing transition into all the {@link ConfigurationTransition} + * instances that it holds. + * + * @param root {@link ComposingTransition} to decompose + */ + public static ImmutableList decomposeTransition( + ConfigurationTransition root) { + ArrayList toBeInspected = new ArrayList<>(); + ImmutableList.Builder transitions = new ImmutableList.Builder<>(); + toBeInspected.add(root); + ConfigurationTransition current; + while (!toBeInspected.isEmpty()) { + current = toBeInspected.remove(0); + if (current instanceof ComposingTransition) { + ComposingTransition composingCurrent = (ComposingTransition) current; + toBeInspected.addAll( + ImmutableList.of(composingCurrent.transition1, composingCurrent.transition2)); + } else { + transitions.add(current); + } + } + return transitions.build(); + } } 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 9014d6e7601a8d..ba62b0491df9f4 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 @@ -55,7 +55,7 @@ public class FunctionTransitionUtil { * incoming {@link BuildOptions}. For native options, this involves a preprocess step of * converting options to their "command line form". * - * Also Validate that transitions output sensical results. + *

Also validate that transitions output sensical results. * * @param buildOptions the pre-transition build options * @param starlarkTransition the transition to apply diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/StarlarkAttributeTransitionProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/StarlarkAttributeTransitionProvider.java index ae86e86ab396f1..d369223b439e6a 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/StarlarkAttributeTransitionProvider.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/StarlarkAttributeTransitionProvider.java @@ -17,6 +17,7 @@ import static com.google.devtools.build.lib.analysis.skylark.FunctionTransitionUtil.applyAndValidate; import static com.google.devtools.build.lib.analysis.skylark.SkylarkAttributesCollection.ERROR_MESSAGE_FOR_NO_ATTR; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.devtools.build.lib.analysis.config.BuildOptions; import com.google.devtools.build.lib.analysis.config.StarlarkDefinedConfigTransition; @@ -52,6 +53,11 @@ public class StarlarkAttributeTransitionProvider implements SplitTransitionProvi this.starlarkDefinedConfigTransition = starlarkDefinedConfigTransition; } + @VisibleForTesting + public StarlarkDefinedConfigTransition getStarlarkDefinedConfigTransitionForTesting() { + return starlarkDefinedConfigTransition; + } + @Override public SplitTransition apply(AttributeMap attributeMap) { Preconditions.checkArgument(attributeMap instanceof ConfiguredAttributeMapper); @@ -59,14 +65,13 @@ public SplitTransition apply(AttributeMap attributeMap) { starlarkDefinedConfigTransition, (ConfiguredAttributeMapper) attributeMap); } - private static class FunctionSplitTransition implements SplitTransition { - private final StarlarkDefinedConfigTransition starlarkDefinedConfigTransition; + class FunctionSplitTransition extends StarlarkTransition implements SplitTransition { private final StructImpl attrObject; FunctionSplitTransition( StarlarkDefinedConfigTransition starlarkDefinedConfigTransition, ConfiguredAttributeMapper attributeMap) { - this.starlarkDefinedConfigTransition = starlarkDefinedConfigTransition; + super(starlarkDefinedConfigTransition); LinkedHashMap attributes = new LinkedHashMap<>(); for (String attribute : attributeMap.getAttributeNames()) { diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/StarlarkRuleTransitionProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/StarlarkRuleTransitionProvider.java index cc86ba320c855e..ef67bcd5438339 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/StarlarkRuleTransitionProvider.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/StarlarkRuleTransitionProvider.java @@ -16,6 +16,7 @@ import static com.google.devtools.build.lib.analysis.skylark.FunctionTransitionUtil.applyAndValidate; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.analysis.config.BuildOptions; import com.google.devtools.build.lib.analysis.config.StarlarkDefinedConfigTransition; @@ -53,19 +54,22 @@ public class StarlarkRuleTransitionProvider implements RuleTransitionFactory { this.starlarkDefinedConfigTransition = starlarkDefinedConfigTransition; } + @VisibleForTesting + public StarlarkDefinedConfigTransition getStarlarkDefinedConfigTransitionForTesting() { + return starlarkDefinedConfigTransition; + } + @Override public PatchTransition buildTransitionFor(Rule rule) { return new FunctionPatchTransition(starlarkDefinedConfigTransition, rule); } - private static class FunctionPatchTransition implements PatchTransition { - - private final StarlarkDefinedConfigTransition starlarkDefinedConfigTransition; + class FunctionPatchTransition extends StarlarkTransition implements PatchTransition { private final StructImpl attrObject; FunctionPatchTransition( StarlarkDefinedConfigTransition starlarkDefinedConfigTransition, Rule rule) { - this.starlarkDefinedConfigTransition = starlarkDefinedConfigTransition; + super(starlarkDefinedConfigTransition); LinkedHashMap attributes = new LinkedHashMap<>(); RawAttributeMapper attributeMapper = RawAttributeMapper.of(rule); 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 new file mode 100644 index 00000000000000..1543f0d68be5f8 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/StarlarkTransition.java @@ -0,0 +1,52 @@ +// Copyright 2019 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.lib.analysis.skylark; + +import com.google.devtools.build.lib.analysis.config.StarlarkDefinedConfigTransition; +import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition; +import com.google.devtools.build.lib.events.ExtendedEventHandler; +import java.util.Objects; + +/** A marker class for configuration transitions that are defined in Starlark. */ +public abstract class StarlarkTransition implements ConfigurationTransition { + + private final StarlarkDefinedConfigTransition starlarkDefinedConfigTransition; + + StarlarkTransition(StarlarkDefinedConfigTransition starlarkDefinedConfigTransition) { + this.starlarkDefinedConfigTransition = starlarkDefinedConfigTransition; + } + + public void replayOn(ExtendedEventHandler eventHandler) { + starlarkDefinedConfigTransition.getEventHandler().replayOn(eventHandler); + starlarkDefinedConfigTransition.getEventHandler().clear(); + } + + @Override + public boolean equals(Object object) { + if (object == this) { + return true; + } + if (object instanceof StarlarkTransition) { + StarlarkDefinedConfigTransition starlarkDefinedConfigTransition = + ((StarlarkTransition) object).starlarkDefinedConfigTransition; + return Objects.equals(starlarkDefinedConfigTransition, this.starlarkDefinedConfigTransition); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(starlarkDefinedConfigTransition); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java index 4d0d8659d2f0bc..ae6451d6ed2bc8 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java +++ b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java @@ -2150,6 +2150,11 @@ public SplitTransition getSplitTransition(AttributeMap attributeMapper) { return splitTransitionProvider.apply(attributeMapper); } + @VisibleForTesting + public SplitTransitionProvider getSplitTransitionProviderForTesting() { + return splitTransitionProvider; + } + /** * Returns true if this attribute transitions on a split transition. * See {@link SplitTransition}. diff --git a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigGlobalLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigGlobalLibrary.java index c46cfb7267b840..3c250fc131f919 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigGlobalLibrary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigGlobalLibrary.java @@ -59,7 +59,7 @@ public ConfigurationTransitionApi transition( validateBuildSettingKeys(inputs, "input", location); validateBuildSettingKeys(outputs, "output", location); return StarlarkDefinedConfigTransition.newRegularTransition( - implementation, inputs, outputs, semantics, env.getEventHandler(), context); + implementation, inputs, outputs, semantics, context); } @Override 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 323512dbed1900..941efa8d3d633f 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 @@ -77,10 +77,12 @@ import com.google.devtools.build.lib.analysis.config.FragmentClassSet; import com.google.devtools.build.lib.analysis.config.HostTransition; import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException; +import com.google.devtools.build.lib.analysis.config.transitions.ComposingTransition; import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition; import com.google.devtools.build.lib.analysis.config.transitions.NoTransition; import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget; import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget.DuplicateException; +import com.google.devtools.build.lib.analysis.skylark.StarlarkTransition; import com.google.devtools.build.lib.buildtool.BuildRequestOptions; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.LabelSyntaxException; @@ -1801,6 +1803,11 @@ public Multimap getConfigurations( depFragments, BuildOptions.diffForReconstruction(defaultBuildOptions, toOptions))); } + ImmutableList transitions = + ComposingTransition.decomposeTransition(key.getTransition()); + transitions.stream() + .filter(t -> t instanceof StarlarkTransition) + .forEach(t -> ((StarlarkTransition) t).replayOn(eventHandler)); } } EvaluationResult configsResult = diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/config/ConfigGlobalLibraryApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/config/ConfigGlobalLibraryApi.java index 6e139977b77e5a..35edd493fe1203 100644 --- a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/config/ConfigGlobalLibraryApi.java +++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/config/ConfigGlobalLibraryApi.java @@ -91,7 +91,7 @@ public interface ConfigGlobalLibraryApi { useEnvironment = true, useContext = true) @SkylarkConstructor(objectType = ConfigurationTransitionApi.class) - public ConfigurationTransitionApi transition( + ConfigurationTransitionApi transition( BaseFunction implementation, List inputs, List outputs, diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java index 77e12d99fcf8c4..3da0577cc32b16 100644 --- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java +++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java @@ -28,8 +28,11 @@ import com.google.devtools.build.lib.analysis.FilesToRunProvider; import com.google.devtools.build.lib.analysis.OutputGroupInfo; import com.google.devtools.build.lib.analysis.RunfilesProvider; +import com.google.devtools.build.lib.analysis.config.StarlarkDefinedConfigTransition; import com.google.devtools.build.lib.analysis.configuredtargets.FileConfiguredTarget; import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget; +import com.google.devtools.build.lib.analysis.skylark.StarlarkAttributeTransitionProvider; +import com.google.devtools.build.lib.analysis.skylark.StarlarkRuleTransitionProvider; import com.google.devtools.build.lib.analysis.test.AnalysisFailure; import com.google.devtools.build.lib.analysis.test.AnalysisFailureInfo; import com.google.devtools.build.lib.analysis.test.AnalysisTestResultInfo; @@ -2510,6 +2513,119 @@ public void testBadWhitelistTransition_noWhitelist() throws Exception { assertContainsEvent("Use of function-based split transition without whitelist"); } + @Test + public void testPrintFromTransitionImpl() throws Exception { + setSkylarkSemanticsOptions("--experimental_starlark_config_transitions"); + scratch.file( + "tools/whitelists/function_transition_whitelist/BUILD", + "package_group(", + " name = 'function_transition_whitelist',", + " packages = [", + " '//test/...',", + " ],", + ")"); + scratch.file( + "test/rules.bzl", + "def _transition_impl(settings, attr):", + " print('printing from transition impl', settings['//command_line_option:test_arg'])", + " return {'//command_line_option:test_arg': " + + "settings['//command_line_option:test_arg']+['meow']}", + "my_transition = transition(", + " implementation = _transition_impl,", + " inputs = ['//command_line_option:test_arg'],", + " outputs = ['//command_line_option:test_arg'],", + ")", + "def _rule_impl(ctx):", + " return []", + "my_rule = rule(", + " implementation = _rule_impl,", + " cfg = my_transition,", + " attrs = {", + " 'dep': attr.label(cfg = my_transition),", + " '_whitelist_function_transition': attr.label(", + " default = '//tools/whitelists/function_transition_whitelist',", + " ),", + " }", + ")"); + + scratch.file( + "test/BUILD", + "load('//test:rules.bzl', 'my_rule')", + "my_rule(name = 'test', dep = ':dep')", + "my_rule(name = 'dep')"); + + useConfiguration("--test_arg=meow"); + + getConfiguredTarget("//test"); + // Test print from top level transition + assertContainsEventWithFrequency("printing from transition impl [\"meow\"]", 1); + // Test print from dep transition + assertContainsEventWithFrequency("printing from transition impl [\"meow\", \"meow\"]", 1); + // Test print from (non-top level) rule class transition + assertContainsEventWithFrequency( + "printing from transition impl [\"meow\", \"meow\", \"meow\"]", 1); + } + + @Test + public void testTransitionEquality() throws Exception { + setSkylarkSemanticsOptions("--experimental_starlark_config_transitions"); + scratch.file( + "tools/whitelists/function_transition_whitelist/BUILD", + "package_group(", + " name = 'function_transition_whitelist',", + " packages = [", + " '//test/...',", + " ],", + ")"); + scratch.file( + "test/rules.bzl", + "def _transition_impl(settings, attr):", + " return {'//command_line_option:test_arg': ['meow']}", + "my_transition = transition(", + " implementation = _transition_impl,", + " inputs = [],", + " outputs = ['//command_line_option:test_arg'],", + ")", + "def _rule_impl(ctx):", + " return []", + "my_rule = rule(", + " implementation = _rule_impl,", + " cfg = my_transition,", + " attrs = {", + " 'dep': attr.label(cfg = my_transition),", + " '_whitelist_function_transition': attr.label(", + " default = '//tools/whitelists/function_transition_whitelist',", + " ),", + " }", + ")"); + + scratch.file( + "test/BUILD", + "load('//test:rules.bzl', 'my_rule')", + "my_rule(name = 'test', dep = ':dep')", + "my_rule(name = 'dep')"); + + useConfiguration("--test_arg=meow"); + + StarlarkDefinedConfigTransition ruleTransition = + ((StarlarkAttributeTransitionProvider) + getTarget("//test") + .getAssociatedRule() + .getRuleClassObject() + .getAttributeByName("dep") + .getSplitTransitionProviderForTesting()) + .getStarlarkDefinedConfigTransitionForTesting(); + + StarlarkDefinedConfigTransition attrTransition = + ((StarlarkRuleTransitionProvider) + getTarget("//test").getAssociatedRule().getRuleClassObject().getTransitionFactory()) + .getStarlarkDefinedConfigTransitionForTesting(); + + assertThat(ruleTransition).isEqualTo(attrTransition); + assertThat(attrTransition).isEqualTo(ruleTransition); + assertThat(ruleTransition.hashCode()).isEqualTo(attrTransition.hashCode()); + } + @Test public void testBadWhitelistTransition_whitelistNoCfg() throws Exception { scratch.file(