Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1a8906d9 authored by Cole Faust's avatar Cole Faust Committed by Gerrit Code Review
Browse files

Merge "Update the ConfigurableEvaluator for typed selects" into main

parents 9a8255f4 fdbf5d47
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ import (
	"strings"

	"github.com/google/blueprint"
	"github.com/google/blueprint/parser"
	"github.com/google/blueprint/proptools"
)

// BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns
@@ -219,7 +219,7 @@ type BaseModuleContext interface {

	// EvaluateConfiguration makes ModuleContext a valid proptools.ConfigurableEvaluator, so this context
	// can be used to evaluate the final value of Configurable properties.
	EvaluateConfiguration(parser.SelectType, string, string) (string, bool)
	EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue
}

type baseModuleContext struct {
@@ -577,6 +577,6 @@ func (b *baseModuleContext) GetPathString(skipFirst bool) string {
	return sb.String()
}

func (m *baseModuleContext) EvaluateConfiguration(ty parser.SelectType, property, condition string) (string, bool) {
	return m.Module().ConfigurableEvaluator(m).EvaluateConfiguration(ty, property, condition)
func (m *baseModuleContext) EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue {
	return m.Module().ConfigurableEvaluator(m).EvaluateConfiguration(condition, property)
}
+55 −22
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ import (
	"android/soong/bazel"

	"github.com/google/blueprint"
	"github.com/google/blueprint/parser"
	"github.com/google/blueprint/proptools"
)

@@ -2140,41 +2139,75 @@ func (e configurationEvalutor) PropertyErrorf(property string, fmt string, args
	e.ctx.OtherModulePropertyErrorf(e.m, property, fmt, args)
}

func (e configurationEvalutor) EvaluateConfiguration(ty parser.SelectType, property, condition string) (string, bool) {
func (e configurationEvalutor) EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue {
	ctx := e.ctx
	m := e.m
	switch ty {
	case parser.SelectTypeReleaseVariable:
		if v, ok := ctx.Config().productVariables.BuildFlags[condition]; ok {
			return v, true
	switch condition.FunctionName {
	case "release_variable":
		if len(condition.Args) != 1 {
			ctx.OtherModulePropertyErrorf(m, property, "release_variable requires 1 argument, found %d", len(condition.Args))
			return proptools.ConfigurableValueUndefined()
		}
		return "", false
	case parser.SelectTypeProductVariable:
		if v, ok := ctx.Config().productVariables.BuildFlags[condition.Args[0]]; ok {
			return proptools.ConfigurableValueString(v)
		}
		return proptools.ConfigurableValueUndefined()
	case "product_variable":
		// TODO(b/323382414): Might add these on a case-by-case basis
		ctx.OtherModulePropertyErrorf(m, property, "TODO(b/323382414): Product variables are not yet supported in selects")
		return "", false
	case parser.SelectTypeSoongConfigVariable:
		parts := strings.Split(condition, ":")
		namespace := parts[0]
		variable := parts[1]
		return proptools.ConfigurableValueUndefined()
	case "soong_config_variable":
		if len(condition.Args) != 2 {
			ctx.OtherModulePropertyErrorf(m, property, "soong_config_variable requires 2 arguments, found %d", len(condition.Args))
			return proptools.ConfigurableValueUndefined()
		}
		namespace := condition.Args[0]
		variable := condition.Args[1]
		if n, ok := ctx.Config().productVariables.VendorVars[namespace]; ok {
			if v, ok := n[variable]; ok {
				return v, true
				return proptools.ConfigurableValueString(v)
			}
		}
		return proptools.ConfigurableValueUndefined()
	case "variant":
		if len(condition.Args) != 1 {
			ctx.OtherModulePropertyErrorf(m, property, "variant requires 1 argument, found %d", len(condition.Args))
			return proptools.ConfigurableValueUndefined()
		}
		return "", false
	case parser.SelectTypeVariant:
		if condition == "arch" {
		if condition.Args[0] == "arch" {
			if !m.base().ArchReady() {
				ctx.OtherModulePropertyErrorf(m, property, "A select on arch was attempted before the arch mutator ran")
				return "", false
				return proptools.ConfigurableValueUndefined()
			}
			return proptools.ConfigurableValueString(m.base().Arch().ArchType.Name)
		}
		ctx.OtherModulePropertyErrorf(m, property, "Unknown variant %s", condition.Args[0])
		return proptools.ConfigurableValueUndefined()
	case "boolean_var_for_testing":
		// We currently don't have any other boolean variables (we should add support for typing
		// the soong config variables), so add this fake one for testing the boolean select
		// functionality.
		if len(condition.Args) != 0 {
			ctx.OtherModulePropertyErrorf(m, property, "boolean_var_for_testing requires 0 arguments, found %d", len(condition.Args))
			return proptools.ConfigurableValueUndefined()
		}

		if n, ok := ctx.Config().productVariables.VendorVars["boolean_var"]; ok {
			if v, ok := n["for_testing"]; ok {
				switch v {
				case "true":
					return proptools.ConfigurableValueBool(true)
				case "false":
					return proptools.ConfigurableValueBool(false)
				default:
					ctx.OtherModulePropertyErrorf(m, property, "testing:my_boolean_var can only be true or false, found %q", v)
				}
			}
			return m.base().Arch().ArchType.Name, true
		}
		ctx.OtherModulePropertyErrorf(m, property, "Unknown variant %s", condition)
		return "", false
		return proptools.ConfigurableValueUndefined()
	default:
		panic("Should be unreachable")
		ctx.OtherModulePropertyErrorf(m, property, "Unknown select condition %s", condition.FunctionName)
		return proptools.ConfigurableValueUndefined()
	}
}

+166 −0
Original line number Diff line number Diff line
@@ -327,8 +327,10 @@ func TestSelects(t *testing.T) {
			my_module_type {
				name: "foo",
				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
					"foo": "bar",
					default: unset,
				}) + select(soong_config_variable("my_namespace", "my_variable2"), {
					"baz": "qux",
					default: unset,
				})
			}
@@ -341,6 +343,7 @@ func TestSelects(t *testing.T) {
			my_module_type {
				name: "foo",
				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
					"foo": "bar",
					default: unset,
				}) + select(soong_config_variable("my_namespace", "my_variable2"), {
					default: "a",
@@ -414,6 +417,169 @@ func TestSelects(t *testing.T) {
				replacing_string_list: &[]string{"b1"},
			},
		},
		{
			name: "Multi-condition string 1",
			bp: `
			my_module_type {
				name: "foo",
				my_string: select((
					soong_config_variable("my_namespace", "my_variable"),
					soong_config_variable("my_namespace", "my_variable2"),
				), {
					("a", "b"): "a+b",
					("a", default): "a+default",
					(default, default): "default",
				}),
			}
			`,
			vendorVars: map[string]map[string]string{
				"my_namespace": {
					"my_variable":  "a",
					"my_variable2": "b",
				},
			},
			provider: selectsTestProvider{
				my_string: proptools.StringPtr("a+b"),
			},
		},
		{
			name: "Multi-condition string 2",
			bp: `
			my_module_type {
				name: "foo",
				my_string: select((
					soong_config_variable("my_namespace", "my_variable"),
					soong_config_variable("my_namespace", "my_variable2"),
				), {
					("a", "b"): "a+b",
					("a", default): "a+default",
					(default, default): "default",
				}),
			}
			`,
			vendorVars: map[string]map[string]string{
				"my_namespace": {
					"my_variable":  "a",
					"my_variable2": "c",
				},
			},
			provider: selectsTestProvider{
				my_string: proptools.StringPtr("a+default"),
			},
		},
		{
			name: "Multi-condition string 3",
			bp: `
			my_module_type {
				name: "foo",
				my_string: select((
					soong_config_variable("my_namespace", "my_variable"),
					soong_config_variable("my_namespace", "my_variable2"),
				), {
					("a", "b"): "a+b",
					("a", default): "a+default",
					(default, default): "default",
				}),
			}
			`,
			vendorVars: map[string]map[string]string{
				"my_namespace": {
					"my_variable":  "c",
					"my_variable2": "b",
				},
			},
			provider: selectsTestProvider{
				my_string: proptools.StringPtr("default"),
			},
		},
		{
			name: "Select on boolean",
			bp: `
			my_module_type {
				name: "foo",
				my_string: select(boolean_var_for_testing(), {
					true: "t",
					false: "f",
				}),
			}
			`,
			vendorVars: map[string]map[string]string{
				"boolean_var": {
					"for_testing": "true",
				},
			},
			provider: selectsTestProvider{
				my_string: proptools.StringPtr("t"),
			},
		},
		{
			name: "Select on boolean false",
			bp: `
			my_module_type {
				name: "foo",
				my_string: select(boolean_var_for_testing(), {
					true: "t",
					false: "f",
				}),
			}
			`,
			vendorVars: map[string]map[string]string{
				"boolean_var": {
					"for_testing": "false",
				},
			},
			provider: selectsTestProvider{
				my_string: proptools.StringPtr("f"),
			},
		},
		{
			name: "Select on boolean undefined",
			bp: `
			my_module_type {
				name: "foo",
				my_string: select(boolean_var_for_testing(), {
					true: "t",
					false: "f",
				}),
			}
			`,
			expectedError: "foo",
		},
		{
			name: "Select on boolean undefined with default",
			bp: `
			my_module_type {
				name: "foo",
				my_string: select(boolean_var_for_testing(), {
					true: "t",
					false: "f",
					default: "default",
				}),
			}
			`,
			provider: selectsTestProvider{
				my_string: proptools.StringPtr("default"),
			},
		},
		{
			name: "Mismatched condition types",
			bp: `
			my_module_type {
				name: "foo",
				my_string: select(boolean_var_for_testing(), {
					"true": "t",
					"false": "f",
					default: "default",
				}),
			}
			`,
			vendorVars: map[string]map[string]string{
				"boolean_var": {
					"for_testing": "false",
				},
			},
			expectedError: "Expected all branches of a select on condition boolean_var_for_testing\\(\\) to have type bool, found string",
		},
	}

	for _, tc := range testCases {