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

Commit 406ea1c3 authored by Paul Duffin's avatar Paul Duffin
Browse files

Refactor prebuilt to use srcs supplier function

Previously, prebuilt had two ways to provide the src value, as a
pointer to an []string and using reflection. That meant that any code
that needed to check the src to use had to understand the two ways of
accessing it.

This change refactors the code to abstract the origin of the src values
being a supplier function. That insulates the callers from having to
know the details and makes it easy to add new suppliers in future.

Bug: 153306490
Test: m nothing
Bug: 142918168
Merged-In: I5cc7517c46cce96924c9f34ba1b046b468f7684a
Change-Id: I5cc7517c46cce96924c9f34ba1b046b468f7684a
parent 35dbafcf
Loading
Loading
Loading
Loading
+84 −55
Original line number Diff line number Diff line
@@ -50,12 +50,9 @@ type PrebuiltProperties struct {

type Prebuilt struct {
	properties PrebuiltProperties
	module     Module
	srcs       *[]string

	// Metadata for single source Prebuilt modules.
	srcProps reflect.Value
	srcField reflect.StructField
	srcsSupplier     PrebuiltSrcsSupplier
	srcsPropertyName string
}

func (p *Prebuilt) Name(name string) string {
@@ -72,50 +69,107 @@ func (p *Prebuilt) ForcePrefer() {
// preference configs. We'll want to add native support for dynamic source cases if we end up having
// more modules like this.
func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path {
	if p.srcs != nil {
		if len(*p.srcs) == 0 {
			ctx.PropertyErrorf("srcs", "missing prebuilt source file")
	if p.srcsSupplier != nil {
		srcs := p.srcsSupplier()

		if len(srcs) == 0 {
			ctx.PropertyErrorf(p.srcsPropertyName, "missing prebuilt source file")
			return nil
		}

		if len(*p.srcs) > 1 {
			ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
		if len(srcs) > 1 {
			ctx.PropertyErrorf(p.srcsPropertyName, "multiple prebuilt source files")
			return nil
		}

		// Return the singleton source after expanding any filegroup in the
		// sources.
		return PathForModuleSrc(ctx, (*p.srcs)[0])
		src := srcs[0]
		return PathForModuleSrc(ctx, src)
	} else {
		if !p.srcProps.IsValid() {
		ctx.ModuleErrorf("prebuilt source was not set")
		}
		src := p.getSingleSourceFieldValue()
		if src == "" {
			ctx.PropertyErrorf(proptools.FieldNameForProperty(p.srcField.Name),
				"missing prebuilt source file")
		return nil
	}
		return PathForModuleSrc(ctx, src)
	}
}

func (p *Prebuilt) UsePrebuilt() bool {
	return p.properties.UsePrebuilt
}

func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
// Called to provide the srcs value for the prebuilt module.
//
// Return the src value or nil if it is not available.
type PrebuiltSrcsSupplier func() []string

// Initialize the module as a prebuilt module that uses the provided supplier to access the
// prebuilt sources of the module.
//
// The supplier will be called multiple times and must return the same values each time it
// is called. If it returns an empty array (or nil) then the prebuilt module will not be used
// as a replacement for a source module with the same name even if prefer = true.
//
// If the Prebuilt.SingleSourcePath() is called on the module then this must return an array
// containing exactly one source file.
//
// The provided property name is used to provide helpful error messages in the event that
// a problem arises, e.g. calling SingleSourcePath() when more than one source is provided.
func InitPrebuiltModuleWithSrcSupplier(module PrebuiltInterface, srcsSupplier PrebuiltSrcsSupplier, srcsPropertyName string) {
	p := module.Prebuilt()
	module.AddProperties(&p.properties)
	p.srcs = srcs

	if srcsSupplier == nil {
		panic(fmt.Errorf("srcsSupplier must not be nil"))
	}
	if srcsPropertyName == "" {
		panic(fmt.Errorf("srcsPropertyName must not be empty"))
	}

	p.srcsSupplier = srcsSupplier
	p.srcsPropertyName = srcsPropertyName
}

func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
	if srcs == nil {
		panic(fmt.Errorf("srcs must not be nil"))
	}

	srcsSupplier := func() []string {
		return *srcs
	}

	InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
}

func InitSingleSourcePrebuiltModule(module PrebuiltInterface, srcProps interface{}, srcField string) {
	p := module.Prebuilt()
	module.AddProperties(&p.properties)
	p.srcProps = reflect.ValueOf(srcProps).Elem()
	p.srcField, _ = p.srcProps.Type().FieldByName(srcField)
	p.checkSingleSourceProperties()
	srcPropsValue := reflect.ValueOf(srcProps).Elem()
	srcStructField, _ := srcPropsValue.Type().FieldByName(srcField)
	if !srcPropsValue.IsValid() || srcStructField.Name == "" {
		panic(fmt.Errorf("invalid single source prebuilt %+v", module))
	}

	if srcPropsValue.Kind() != reflect.Struct && srcPropsValue.Kind() != reflect.Interface {
		panic(fmt.Errorf("invalid single source prebuilt %+v", srcProps))
	}

	srcFieldIndex := srcStructField.Index
	srcPropertyName := proptools.PropertyNameForField(srcField)

	srcsSupplier := func() []string {
		value := srcPropsValue.FieldByIndex(srcFieldIndex)
		if value.Kind() == reflect.Ptr {
			value = value.Elem()
		}
		if value.Kind() != reflect.String {
			panic(fmt.Errorf("prebuilt src field %q should be a string or a pointer to one but was %d %q", srcPropertyName, value.Kind(), value))
		}
		src := value.String()
		if src == "" {
			return nil
		}
		return []string{src}
	}

	InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, srcPropertyName)
}

type PrebuiltInterface interface {
@@ -152,7 +206,7 @@ func PrebuiltMutator(ctx BottomUpMutatorContext) {
func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
	if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
		p := m.Prebuilt()
		if p.srcs == nil && !p.srcProps.IsValid() {
		if p.srcsSupplier == nil {
			panic(fmt.Errorf("prebuilt module did not have InitPrebuiltModule called on it"))
		}
		if !p.properties.SourceExists {
@@ -191,11 +245,7 @@ func PrebuiltPostDepsMutator(ctx BottomUpMutatorContext) {
// usePrebuilt returns true if a prebuilt should be used instead of the source module.  The prebuilt
// will be used if it is marked "prefer" or if the source module is disabled.
func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module) bool {
	if p.srcs != nil && len(*p.srcs) == 0 {
		return false
	}

	if p.srcProps.IsValid() && p.getSingleSourceFieldValue() == "" {
	if p.srcsSupplier != nil && len(p.srcsSupplier()) == 0 {
		return false
	}

@@ -210,24 +260,3 @@ func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module) bool {
func (p *Prebuilt) SourceExists() bool {
	return p.properties.SourceExists
}

func (p *Prebuilt) checkSingleSourceProperties() {
	if !p.srcProps.IsValid() || p.srcField.Name == "" {
		panic(fmt.Errorf("invalid single source prebuilt %+v", p))
	}

	if p.srcProps.Kind() != reflect.Struct && p.srcProps.Kind() != reflect.Interface {
		panic(fmt.Errorf("invalid single source prebuilt %+v", p.srcProps))
	}
}

func (p *Prebuilt) getSingleSourceFieldValue() string {
	value := p.srcProps.FieldByIndex(p.srcField.Index)
	if value.Kind() == reflect.Ptr {
		value = value.Elem()
	}
	if value.Kind() != reflect.String {
		panic(fmt.Errorf("prebuilt src field %q should be a string or a pointer to one", p.srcField.Name))
	}
	return value.String()
}