Make crosstool to starlark converter error out if it comes across multiple expand_if_all_available or expand_if_none_available in a single flag_group
PiperOrigin-RevId: 232499399
diff --git a/tools/migration/crosstool_to_starlark_lib.go b/tools/migration/crosstool_to_starlark_lib.go
index a3e230c..01fe45e 100644
--- a/tools/migration/crosstool_to_starlark_lib.go
+++ b/tools/migration/crosstool_to_starlark_lib.go
@@ -8,6 +8,7 @@
import (
"bytes"
+ "errors"
"fmt"
"sort"
"strings"
@@ -352,7 +353,7 @@
}
func getFeatures(crosstool *crosstoolpb.CrosstoolRelease) (
- map[string][]string, map[string]map[string][]string) {
+ map[string][]string, map[string]map[string][]string, error) {
featureNameToFeature := make(map[string]map[string][]string)
toolchainToFeatures := make(map[string][]string)
for _, toolchain := range crosstool.GetToolchain() {
@@ -364,7 +365,11 @@
featureName := strings.ToLower(feature.GetName()) + "_feature"
featureName = strings.Replace(featureName, "+", "p", -1)
featureName = strings.Replace(featureName, ".", "_", -1)
- stringFeature := parseFeature(feature, 1)
+ stringFeature, err := parseFeature(feature, 1)
+ if err != nil {
+ return nil, nil, fmt.Errorf(
+ "Error in feature '%s': %v", feature.GetName(), err)
+ }
if _, ok := featureNameToFeature[featureName]; !ok {
featureNameToFeature[featureName] = make(map[string][]string)
}
@@ -373,7 +378,7 @@
toolchainToFeatures[id] = append(toolchainToFeatures[id], featureName)
}
}
- return toolchainToFeatures, featureNameToFeature
+ return toolchainToFeatures, featureNameToFeature, nil
}
func getFeaturesDeclaration(crosstool *crosstoolpb.CrosstoolRelease,
@@ -412,7 +417,7 @@
}
func getActions(crosstool *crosstoolpb.CrosstoolRelease) (
- map[string][]string, map[string]map[string][]string) {
+ map[string][]string, map[string]map[string][]string, error) {
actionNameToAction := make(map[string]map[string][]string)
toolchainToActions := make(map[string][]string)
for _, toolchain := range crosstool.GetToolchain() {
@@ -429,7 +434,11 @@
actionName = strings.Replace(actionName, "+", "p", -1)
actionName = strings.Replace(actionName, ".", "_", -1)
}
- stringAction := parseAction(action, 1)
+ stringAction, err := parseAction(action, 1)
+ if err != nil {
+ return nil, nil, fmt.Errorf(
+ "Error in action_config '%s': %v", action.GetActionName(), err)
+ }
if _, ok := actionNameToAction[actionName]; !ok {
actionNameToAction[actionName] = make(map[string][]string)
}
@@ -440,7 +449,7 @@
strings.TrimPrefix(strings.ToLower(actionName), "action_names.")+"_action")
}
}
- return toolchainToActions, actionNameToAction
+ return toolchainToActions, actionNameToAction, nil
}
func getActionConfigsDeclaration(
@@ -482,7 +491,7 @@
return strings.Join(res, "\n")
}
-func parseAction(action *crosstoolpb.CToolchain_ActionConfig, depth int) string {
+func parseAction(action *crosstoolpb.CToolchain_ActionConfig, depth int) (string, error) {
actionName := action.GetActionName()
aName := ""
if val, ok := actionNames[actionName]; ok {
@@ -496,9 +505,11 @@
fields = append(fields, "enabled = True")
}
if len(action.GetFlagSet()) != 0 {
- flagSets := "flag_sets = " +
- parseFlagSets(action.GetFlagSet(), depth+1)
- fields = append(fields, flagSets)
+ flagSets, err := parseFlagSets(action.GetFlagSet(), depth+1)
+ if err != nil {
+ return "", err
+ }
+ fields = append(fields, "flag_sets = "+flagSets)
}
if len(action.GetImplies()) != 0 {
implies := "implies = " +
@@ -509,7 +520,7 @@
tools := "tools = " + parseTools(action.GetTool(), depth+1)
fields = append(fields, tools)
}
- return createObject("action_config", fields, depth)
+ return createObject("action_config", fields, depth), nil
}
func getStringArrStatement(attr string, arrValToIds map[string][]string,
@@ -660,7 +671,7 @@
return createObject("artifact_name_pattern", fields, depth)
}
-func parseFeature(feature *crosstoolpb.CToolchain_Feature, depth int) string {
+func parseFeature(feature *crosstoolpb.CToolchain_Feature, depth int) (string, error) {
name := fmt.Sprintf("name = \"%s\"", feature.GetName())
fields := []string{name}
@@ -669,9 +680,11 @@
}
if len(feature.GetFlagSet()) > 0 {
- flagSets := "flag_sets = " +
- parseFlagSets(feature.GetFlagSet(), depth+1)
- fields = append(fields, flagSets)
+ flagSets, err := parseFlagSets(feature.GetFlagSet(), depth+1)
+ if err != nil {
+ return "", err
+ }
+ fields = append(fields, "flag_sets = "+flagSets)
}
if len(feature.GetEnvSet()) > 0 {
envSets := "env_sets = " + parseEnvSets(feature.GetEnvSet(), depth+1)
@@ -691,19 +704,22 @@
makeStringArr(feature.GetProvides(), depth+1 /* isPlainString= */, true)
fields = append(fields, provides)
}
- return createObject("feature", fields, depth)
+ return createObject("feature", fields, depth), nil
}
-func parseFlagSets(flagSets []*crosstoolpb.CToolchain_FlagSet, depth int) string {
+func parseFlagSets(flagSets []*crosstoolpb.CToolchain_FlagSet, depth int) (string, error) {
var res []string
for _, flagSet := range flagSets {
- parsedFlagset := parseFlagSet(flagSet, depth+1)
+ parsedFlagset, err := parseFlagSet(flagSet, depth+1)
+ if err != nil {
+ return "", err
+ }
res = append(res, parsedFlagset)
}
- return makeStringArr(res, depth /* isPlainString= */, false)
+ return makeStringArr(res, depth /* isPlainString= */, false), nil
}
-func parseFlagSet(flagSet *crosstoolpb.CToolchain_FlagSet, depth int) string {
+func parseFlagSet(flagSet *crosstoolpb.CToolchain_FlagSet, depth int) (string, error) {
var fields []string
if len(flagSet.GetAction()) > 0 {
actionArr := processActions(flagSet.GetAction(), depth)
@@ -711,27 +727,33 @@
fields = append(fields, actions)
}
if len(flagSet.GetFlagGroup()) > 0 {
- flagGroups := "flag_groups = " +
- parseFlagGroups(flagSet.GetFlagGroup(), depth+1)
- fields = append(fields, flagGroups)
+ flagGroups, err := parseFlagGroups(flagSet.GetFlagGroup(), depth+1)
+ if err != nil {
+ return "", err
+ }
+ fields = append(fields, "flag_groups = "+flagGroups)
}
if len(flagSet.GetWithFeature()) > 0 {
withFeatures := "with_features = " +
parseWithFeatureSets(flagSet.GetWithFeature(), depth+1)
fields = append(fields, withFeatures)
}
- return createObject("flag_set", fields, depth)
+ return createObject("flag_set", fields, depth), nil
}
-func parseFlagGroups(flagGroups []*crosstoolpb.CToolchain_FlagGroup, depth int) string {
+func parseFlagGroups(flagGroups []*crosstoolpb.CToolchain_FlagGroup, depth int) (string, error) {
var res []string
for _, flagGroup := range flagGroups {
- res = append(res, parseFlagGroup(flagGroup, depth+1))
+ flagGroupString, err := parseFlagGroup(flagGroup, depth+1)
+ if err != nil {
+ return "", err
+ }
+ res = append(res, flagGroupString)
}
- return makeStringArr(res, depth /* isPlainString= */, false)
+ return makeStringArr(res, depth /* isPlainString= */, false), nil
}
-func parseFlagGroup(flagGroup *crosstoolpb.CToolchain_FlagGroup, depth int) string {
+func parseFlagGroup(flagGroup *crosstoolpb.CToolchain_FlagGroup, depth int) (string, error) {
var res []string
if len(flagGroup.GetFlag()) != 0 {
res = append(res, "flags = "+makeStringArr(flagGroup.GetFlag(), depth+1, true))
@@ -740,7 +762,14 @@
res = append(res, fmt.Sprintf("iterate_over = \"%s\"", flagGroup.GetIterateOver()))
}
if len(flagGroup.GetFlagGroup()) != 0 {
- res = append(res, "flag_groups = "+parseFlagGroups(flagGroup.GetFlagGroup(), depth+1))
+ flagGroupString, err := parseFlagGroups(flagGroup.GetFlagGroup(), depth+1)
+ if err != nil {
+ return "", err
+ }
+ res = append(res, "flag_groups = "+flagGroupString)
+ }
+ if len(flagGroup.GetExpandIfAllAvailable()) > 1 {
+ return "", errors.New("Flag group must not have more than one 'expand_if_all_available' field")
}
if len(flagGroup.GetExpandIfAllAvailable()) != 0 {
res = append(res,
@@ -748,6 +777,9 @@
"expand_if_available = \"%s\"",
flagGroup.GetExpandIfAllAvailable()[0]))
}
+ if len(flagGroup.GetExpandIfNoneAvailable()) > 1 {
+ return "", errors.New("Flag group must not have more than one 'expand_if_none_available' field")
+ }
if len(flagGroup.GetExpandIfNoneAvailable()) != 0 {
res = append(res,
fmt.Sprintf(
@@ -767,7 +799,7 @@
"expand_if_equal = "+parseVariableWithValue(
flagGroup.GetExpandIfEqual(), depth+1))
}
- return createObject("flag_group", res, depth)
+ return createObject("flag_group", res, depth), nil
}
func parseVariableWithValue(variable *crosstoolpb.CToolchain_VariableWithValue, depth int) string {
@@ -1242,9 +1274,15 @@
cToolchainIdentifiers := toolchainToCToolchainIdentifier(crosstool)
- toolchainToFeatures, featureNameToFeature := getFeatures(crosstool)
+ toolchainToFeatures, featureNameToFeature, err := getFeatures(crosstool)
+ if err != nil {
+ return "", err
+ }
- toolchainToActions, actionNameToAction := getActions(crosstool)
+ toolchainToActions, actionNameToAction, err := getActions(crosstool)
+ if err != nil {
+ return "", err
+ }
header := getCcToolchainConfigHeader()
if _, err := b.WriteString(header); err != nil {
diff --git a/tools/migration/crosstool_to_starlark_lib_test.go b/tools/migration/crosstool_to_starlark_lib_test.go
index ddb082b..f8c2c48 100644
--- a/tools/migration/crosstool_to_starlark_lib_test.go
+++ b/tools/migration/crosstool_to_starlark_lib_test.go
@@ -992,106 +992,90 @@
}
}
-func TestFeatureAssignment(t *testing.T) {
- toolchainEmpty1 := getCToolchain("1", "cpuA", "compilerA", []string{})
- toolchainEmpty2 := getCToolchain("2", "cpuB", "compilerA", []string{})
- toolchainA1 := getCToolchain("3", "cpuC", "compilerA",
- []string{
- getActionConfig([]string{"action_name: 'A'", "config_name: 'A'"}),
- },
+func TestAllAndNoneAvailableErrorsWhenMoreThanOneElement(t *testing.T) {
+ toolchainFeatureAllAvailable := getCToolchain("1", "cpu", "compiler",
+ []string{getFeature([]string{
+ "name: 'A'",
+ "flag_set {",
+ " action: 'A'",
+ " flag_group {",
+ " flag: 'f'",
+ " expand_if_all_available: 'e1'",
+ " expand_if_all_available: 'e2'",
+ " }",
+ "}",
+ })},
)
- toolchainA2 := getCToolchain("4", "cpuC", "compilerB",
- []string{
- getActionConfig([]string{"action_name: 'A'", "config_name: 'A'"}),
- },
+ toolchainFeatureNoneAvailable := getCToolchain("1", "cpu", "compiler",
+ []string{getFeature([]string{
+ "name: 'A'",
+ "flag_set {",
+ " action: 'A'",
+ " flag_group {",
+ " flag: 'f'",
+ " expand_if_none_available: 'e1'",
+ " expand_if_none_available: 'e2'",
+ " }",
+ "}",
+ })},
)
- toolchainAB := getCToolchain("5", "cpuC", "compilerC",
- []string{
- getActionConfig([]string{"action_name: 'A'", "config_name: 'A'"}),
- getActionConfig([]string{"action_name: 'B'", "config_name: 'B'"}),
- },
+ toolchainActionConfigAllAvailable := getCToolchain("1", "cpu", "compiler",
+ []string{getActionConfig([]string{
+ "config_name: 'A'",
+ "action_name: 'A'",
+ "flag_set {",
+ " action: 'A'",
+ " flag_group {",
+ " flag: 'f'",
+ " expand_if_all_available: 'e1'",
+ " expand_if_all_available: 'e2'",
+ " }",
+ "}",
+ })},
)
- toolchainBA := getCToolchain("6", "cpuD", "compilerA",
- []string{
- getActionConfig([]string{"action_name: 'B'", "config_name: 'B'"}),
- getActionConfig([]string{"action_name: 'A'", "config_name: 'A'"}),
- },
+ toolchainActionConfigNoneAvailable := getCToolchain("1", "cpu", "compiler",
+ []string{getActionConfig([]string{
+ "config_name: 'A'",
+ "action_name: 'A'",
+ "flag_set {",
+ " action: 'A'",
+ " flag_group {",
+ " flag: 'f'",
+ " expand_if_none_available: 'e1'",
+ " expand_if_none_available: 'e2'",
+ " }",
+ "}",
+ })},
)
- toolchainsEmpty := []string{toolchainEmpty1, toolchainEmpty2}
-
- toolchainsOneNonempty := []string{toolchainEmpty1, toolchainA1}
-
- toolchainsSameNonempty := []string{toolchainA1, toolchainA2}
-
- toolchainsDifferentOrder := []string{toolchainAB, toolchainBA}
-
- allToolchains := []string{
- toolchainEmpty1,
- toolchainEmpty2,
- toolchainA1,
- toolchainA2,
- toolchainAB,
- toolchainBA,
- }
testCases := []struct {
field string
- toolchains []string
+ toolchain string
expectedText string
}{
+ {field: "features",
+ toolchain: toolchainFeatureAllAvailable,
+ expectedText: "Error in feature 'A': Flag group must not have more " +
+ "than one 'expand_if_all_available' field"},
+ {field: "features",
+ toolchain: toolchainFeatureNoneAvailable,
+ expectedText: "Error in feature 'A': Flag group must not have more " +
+ "than one 'expand_if_none_available' field"},
{field: "action_configs",
- toolchains: toolchainsEmpty,
- expectedText: `
- action_configs = []`},
+ toolchain: toolchainActionConfigAllAvailable,
+ expectedText: "Error in action_config 'A': Flag group must not have more " +
+ "than one 'expand_if_all_available' field"},
{field: "action_configs",
- toolchains: toolchainsOneNonempty,
- expectedText: `
- if (ctx.attr.cpu == "cpuA"):
- action_configs = []
- elif (ctx.attr.cpu == "cpuC"):
- action_configs = [a_action]
- else:
- fail("Unreachable")`},
- {field: "action_configs",
- toolchains: toolchainsSameNonempty,
- expectedText: `
- action_configs = [a_action]`},
- {field: "action_configs",
- toolchains: toolchainsDifferentOrder,
- expectedText: `
- if (ctx.attr.cpu == "cpuC"):
- action_configs = [a_action, b_action]
- elif (ctx.attr.cpu == "cpuD"):
- action_configs = [b_action, a_action]
- else:
- fail("Unreachable")`},
- {field: "action_configs",
- toolchains: allToolchains,
- expectedText: `
- if (ctx.attr.cpu == "cpuA"
- or ctx.attr.cpu == "cpuB"):
- action_configs = []
- elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerA"
- or ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerB"):
- action_configs = [a_action]
- elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerC"):
- action_configs = [a_action, b_action]
- elif (ctx.attr.cpu == "cpuD"):
- action_configs = [b_action, a_action]
- else:
- fail("Unreachable")`}}
+ toolchain: toolchainActionConfigNoneAvailable,
+ expectedText: "Error in action_config 'A': Flag group must not have more " +
+ "than one 'expand_if_none_available' field"},
+ }
for _, tc := range testCases {
- crosstool := makeCrosstool(tc.toolchains)
- got, err := Transform(crosstool)
- if err != nil {
- t.Fatalf("CROSSTOOL conversion failed: %v", err)
- }
- if !strings.Contains(got, tc.expectedText) {
- t.Errorf("Failed to correctly convert '%s' field, expected to contain:\n%v\n",
- tc.field, tc.expectedText)
- t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n",
- strings.Join(tc.toolchains, "\n"), got)
+ crosstool := makeCrosstool([]string{tc.toolchain})
+ _, err := Transform(crosstool)
+ if err == nil || !strings.Contains(err.Error(), tc.expectedText) {
+ t.Errorf("Expected error: %s, got: %v", tc.expectedText, err)
}
}
}