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

Commit bdd8aeeb authored by Cole Faust's avatar Cole Faust
Browse files

Make select statements work on path properties

Fixes: 329711542
Test: go test
Change-Id: I71f489c26c535174e226e4a9ab449cc2b4bee83a
parent ed9005b5
Loading
Loading
Loading
Loading
+36 −1
Original line number Original line Diff line number Diff line
@@ -16,9 +16,11 @@ package android


import (
import (
	"fmt"
	"fmt"
	"github.com/google/blueprint"
	"regexp"
	"regexp"
	"strings"
	"strings"

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


// BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns
// BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns
@@ -214,6 +216,10 @@ type BaseModuleContext interface {
	// getMissingDependencies returns the list of missing dependencies.
	// getMissingDependencies returns the list of missing dependencies.
	// Calling this function prevents adding new dependencies.
	// Calling this function prevents adding new dependencies.
	getMissingDependencies() []string
	getMissingDependencies() []string

	// 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, bool)
}
}


type baseModuleContext struct {
type baseModuleContext struct {
@@ -564,3 +570,32 @@ func (b *baseModuleContext) GetPathString(skipFirst bool) string {
	}
	}
	return sb.String()
	return sb.String()
}
}

func (m *baseModuleContext) EvaluateConfiguration(ty parser.SelectType, condition string) (string, bool) {
	switch ty {
	case parser.SelectTypeReleaseVariable:
		if v, ok := m.Config().productVariables.BuildFlags[condition]; ok {
			return v, true
		}
		return "", false
	case parser.SelectTypeProductVariable:
		// TODO(b/323382414): Might add these on a case-by-case basis
		m.ModuleErrorf("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]
		if n, ok := m.Config().productVariables.VendorVars[namespace]; ok {
			if v, ok := n[variable]; ok {
				return v, true
			}
		}
		return "", false
	case parser.SelectTypeVariant:
		m.ModuleErrorf("TODO(b/323382414): Variants are not yet supported in selects")
		return "", false
	default:
		panic("Should be unreachable")
	}
}
+0 −34
Original line number Original line Diff line number Diff line
@@ -21,7 +21,6 @@ import (
	"strings"
	"strings"


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


@@ -213,10 +212,6 @@ type ModuleContext interface {
	// GenerateAndroidBuildActions.  If it is called then the struct will be written out and included in
	// GenerateAndroidBuildActions.  If it is called then the struct will be written out and included in
	// the module-info.json generated by Make, and Make will not generate its own data for this module.
	// the module-info.json generated by Make, and Make will not generate its own data for this module.
	ModuleInfoJSON() *ModuleInfoJSON
	ModuleInfoJSON() *ModuleInfoJSON

	// 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, bool)
}
}


type moduleContext struct {
type moduleContext struct {
@@ -719,32 +714,3 @@ func (m *moduleContext) HostRequiredModuleNames() []string {
func (m *moduleContext) TargetRequiredModuleNames() []string {
func (m *moduleContext) TargetRequiredModuleNames() []string {
	return m.module.TargetRequiredModuleNames()
	return m.module.TargetRequiredModuleNames()
}
}

func (m *moduleContext) EvaluateConfiguration(ty parser.SelectType, condition string) (string, bool) {
	switch ty {
	case parser.SelectTypeReleaseVariable:
		if v, ok := m.Config().productVariables.BuildFlags[condition]; ok {
			return v, true
		}
		return "", false
	case parser.SelectTypeProductVariable:
		// TODO: Might add these on a case-by-case basis
		m.ModuleErrorf("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]
		if n, ok := m.Config().productVariables.VendorVars[namespace]; ok {
			if v, ok := n[variable]; ok {
				return v, true
			}
		}
		return "", false
	case parser.SelectTypeVariant:
		m.ModuleErrorf("TODO(b/323382414): Variants are not yet supported in selects")
		return "", false
	default:
		panic("Should be unreachable")
	}
}
+12 −2
Original line number Original line Diff line number Diff line
@@ -47,7 +47,7 @@ func addPathDepsForProps(ctx BottomUpMutatorContext, props []interface{}) {
	// tagged with `android:"path"`.
	// tagged with `android:"path"`.
	var pathProperties []string
	var pathProperties []string
	for _, ps := range props {
	for _, ps := range props {
		pathProperties = append(pathProperties, pathPropertiesForPropertyStruct(ps)...)
		pathProperties = append(pathProperties, pathPropertiesForPropertyStruct(ctx, ps)...)
	}
	}


	// Remove duplicates to avoid multiple dependencies.
	// Remove duplicates to avoid multiple dependencies.
@@ -64,7 +64,7 @@ func addPathDepsForProps(ctx BottomUpMutatorContext, props []interface{}) {
// pathPropertiesForPropertyStruct uses the indexes of properties that are tagged with
// pathPropertiesForPropertyStruct uses the indexes of properties that are tagged with
// android:"path" to extract all their values from a property struct, returning them as a single
// android:"path" to extract all their values from a property struct, returning them as a single
// slice of strings.
// slice of strings.
func pathPropertiesForPropertyStruct(ps interface{}) []string {
func pathPropertiesForPropertyStruct(ctx BottomUpMutatorContext, ps interface{}) []string {
	v := reflect.ValueOf(ps)
	v := reflect.ValueOf(ps)
	if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
	if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
		panic(fmt.Errorf("type %s is not a pointer to a struct", v.Type()))
		panic(fmt.Errorf("type %s is not a pointer to a struct", v.Type()))
@@ -106,6 +106,16 @@ func pathPropertiesForPropertyStruct(ps interface{}) []string {
				ret = append(ret, sv.String())
				ret = append(ret, sv.String())
			case reflect.Slice:
			case reflect.Slice:
				ret = append(ret, sv.Interface().([]string)...)
				ret = append(ret, sv.Interface().([]string)...)
			case reflect.Struct:
				intf := sv.Interface()
				if configurable, ok := intf.(proptools.Configurable[string]); ok {
					ret = append(ret, proptools.String(configurable.Evaluate(ctx)))
				} else if configurable, ok := intf.(proptools.Configurable[[]string]); ok {
					ret = append(ret, proptools.Slice(configurable.Evaluate(ctx))...)
				} else {
					panic(fmt.Errorf(`field %s in type %s has tag android:"path" but is not a string or slice of strings, it is a %s`,
						v.Type().FieldByIndex(i).Name, v.Type(), sv.Type()))
				}
			default:
			default:
				panic(fmt.Errorf(`field %s in type %s has tag android:"path" but is not a string or slice of strings, it is a %s`,
				panic(fmt.Errorf(`field %s in type %s has tag android:"path" but is not a string or slice of strings, it is a %s`,
					v.Type().FieldByIndex(i).Name, v.Type(), sv.Type()))
					v.Type().FieldByIndex(i).Name, v.Type(), sv.Type()))
+36 −2
Original line number Original line Diff line number Diff line
@@ -79,6 +79,36 @@ func TestSelects(t *testing.T) {
				my_bool: proptools.BoolPtr(true),
				my_bool: proptools.BoolPtr(true),
			},
			},
		},
		},
		{
			name: "basic paths",
			bp: `
			my_module_type {
				name: "foo",
				my_paths: select(soong_config_variable("my_namespace", "my_variable"), {
					"a": ["foo.txt"],
					"b": ["bar.txt"],
					_: ["baz.txt"],
				}),
			}
			`,
			provider: selectsTestProvider{
				my_paths: &[]string{"baz.txt"},
			},
		},
		{
			name: "paths with module references",
			bp: `
			my_module_type {
				name: "foo",
				my_paths: select(soong_config_variable("my_namespace", "my_variable"), {
					"a": [":a"],
					"b": [":b"],
					_: [":c"],
				}),
			}
			`,
			expectedError: `"foo" depends on undefined module "c"`,
		},
		{
		{
			name: "Differing types",
			name: "Differing types",
			bp: `
			bp: `
@@ -233,6 +263,7 @@ type selectsTestProvider struct {
	my_bool        *bool
	my_bool        *bool
	my_string      *string
	my_string      *string
	my_string_list *[]string
	my_string_list *[]string
	my_paths       *[]string
}
}


func (p *selectsTestProvider) String() string {
func (p *selectsTestProvider) String() string {
@@ -248,7 +279,8 @@ func (p *selectsTestProvider) String() string {
	my_bool: %v,
	my_bool: %v,
	my_string: %s,
	my_string: %s,
    my_string_list: %s,
    my_string_list: %s,
}`, myBoolStr, myStringStr, p.my_string_list)
    my_paths: %s,
}`, myBoolStr, myStringStr, p.my_string_list, p.my_paths)
}
}


var selectsTestProviderKey = blueprint.NewProvider[selectsTestProvider]()
var selectsTestProviderKey = blueprint.NewProvider[selectsTestProvider]()
@@ -257,6 +289,7 @@ type selectsMockModuleProperties struct {
	My_bool        proptools.Configurable[bool]
	My_bool        proptools.Configurable[bool]
	My_string      proptools.Configurable[string]
	My_string      proptools.Configurable[string]
	My_string_list proptools.Configurable[[]string]
	My_string_list proptools.Configurable[[]string]
	My_paths       proptools.Configurable[[]string] `android:"path"`
}
}


type selectsMockModule struct {
type selectsMockModule struct {
@@ -266,10 +299,11 @@ type selectsMockModule struct {
}
}


func (p *selectsMockModule) GenerateAndroidBuildActions(ctx ModuleContext) {
func (p *selectsMockModule) GenerateAndroidBuildActions(ctx ModuleContext) {
	SetProvider[selectsTestProvider](ctx, selectsTestProviderKey, selectsTestProvider{
	SetProvider(ctx, selectsTestProviderKey, selectsTestProvider{
		my_bool:        p.properties.My_bool.Evaluate(ctx),
		my_bool:        p.properties.My_bool.Evaluate(ctx),
		my_string:      p.properties.My_string.Evaluate(ctx),
		my_string:      p.properties.My_string.Evaluate(ctx),
		my_string_list: p.properties.My_string_list.Evaluate(ctx),
		my_string_list: p.properties.My_string_list.Evaluate(ctx),
		my_paths:       p.properties.My_paths.Evaluate(ctx),
	})
	})
}
}