Allow starlark string flags to mark themselves as allowMultiple.
Duplicate values are not proactively removed. Order is maintained. Values are stored in the BuildOptions starlark options map as a list of strings.
Along the way implement a local cache of build setting targets so we don't repeatedly load them if they're set more than once.
PiperOrigin-RevId: 346798536
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 97cbb46..73ee4bf 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
@@ -33,6 +33,8 @@
import com.google.devtools.common.options.Option;
import com.google.devtools.common.options.OptionDocumentationCategory;
import com.google.devtools.common.options.OptionEffectTag;
+import java.util.List;
+import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -1491,4 +1493,105 @@
"Output directory name '//bad:cpu' specified by CppConfiguration is invalid as part of a "
+ "path: must not contain /");
}
+
+ @Test
+ public void testTransitionOnAllowMultiplesBuildSettingRequiresList() throws Exception {
+ setBuildLanguageOptions("--experimental_starlark_config_transitions=true");
+ 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 = [],",
+ " outputs = ['//test:cute-animal-fact']",
+ ")");
+ writeAllowlistFile();
+ 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 = {",
+ " '_allowlist_function_transition': attr.label(",
+ " default = '//tools/allowlists/function_transition_allowlist',",
+ " ),",
+ " },",
+ ")");
+ scratch.file(
+ "test/build_settings.bzl",
+ "def _impl(ctx):",
+ " return []",
+ "string_flag = rule(implementation = _impl, build_setting = config.string(flag=True,"
+ + " allow_multiple=True))");
+ scratch.file(
+ "test/BUILD",
+ "load('//test:rules.bzl', 'my_rule')",
+ "load('//test:build_settings.bzl', 'string_flag')",
+ "my_rule(name = 'test')",
+ "string_flag(",
+ " name = 'cute-animal-fact',",
+ " build_setting_default = \"cats can't taste sugar\",",
+ ")");
+
+ reporter.removeHandler(failFastHandler);
+ getConfiguredTarget("//test");
+ assertContainsEvent(
+ "'//test:cute-animal-fact' allows multiple values and must be set in transition using a"
+ + " starlark list instead of single value");
+ }
+
+ @Test
+ public void testTransitionOnAllowMultiplesBuildSetting() throws Exception {
+ setBuildLanguageOptions("--experimental_starlark_config_transitions=true");
+ 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 = [],",
+ " outputs = ['//test:cute-animal-fact']",
+ ")");
+ writeAllowlistFile();
+ 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 = {",
+ " '_allowlist_function_transition': attr.label(",
+ " default = '//tools/allowlists/function_transition_allowlist',",
+ " ),",
+ " },",
+ ")");
+ scratch.file(
+ "test/build_settings.bzl",
+ "def _impl(ctx):",
+ " return []",
+ "string_flag = rule(implementation = _impl, build_setting = config.string(flag=True,"
+ + " allow_multiple=True))");
+ scratch.file(
+ "test/BUILD",
+ "load('//test:rules.bzl', 'my_rule')",
+ "load('//test:build_settings.bzl', 'string_flag')",
+ "my_rule(name = 'test')",
+ "string_flag(",
+ " name = 'cute-animal-fact',",
+ " build_setting_default = \"cats can't taste sugar\",",
+ ")");
+
+ Map<Label, Object> starlarkOptions =
+ getConfiguration(getConfiguredTarget("//test")).getOptions().getStarlarkOptions();
+ assertNoEvents();
+ assertThat(
+ (List<?>) starlarkOptions.get(Label.parseAbsoluteUnchecked("//test:cute-animal-fact")))
+ .containsExactly("puffins mate for life");
+ }
}