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.

Test: m nothing
Bug: 142918168
Change-Id: I5cc7517c46cce96924c9f34ba1b046b468f7684a
This commit is contained in:
Paul Duffin 2020-03-12 23:43:52 +00:00
parent 843f09723b
commit dcb4bd6fb4

View file

@ -50,12 +50,9 @@ type PrebuiltProperties struct {
type Prebuilt struct { type Prebuilt struct {
properties PrebuiltProperties properties PrebuiltProperties
module Module
srcs *[]string
// Metadata for single source Prebuilt modules. srcsSupplier PrebuiltSrcsSupplier
srcProps reflect.Value srcsPropertyName string
srcField reflect.StructField
} }
func (p *Prebuilt) Name(name string) string { func (p *Prebuilt) Name(name string) string {
@ -72,31 +69,26 @@ func (p *Prebuilt) ForcePrefer() {
// preference configs. We'll want to add native support for dynamic source cases if we end up having // preference configs. We'll want to add native support for dynamic source cases if we end up having
// more modules like this. // more modules like this.
func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path { func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path {
if p.srcs != nil { if p.srcsSupplier != nil {
if len(*p.srcs) == 0 { srcs := p.srcsSupplier()
ctx.PropertyErrorf("srcs", "missing prebuilt source file")
if len(srcs) == 0 {
ctx.PropertyErrorf(p.srcsPropertyName, "missing prebuilt source file")
return nil return nil
} }
if len(*p.srcs) > 1 { if len(srcs) > 1 {
ctx.PropertyErrorf("srcs", "multiple prebuilt source files") ctx.PropertyErrorf(p.srcsPropertyName, "multiple prebuilt source files")
return nil return nil
} }
// Return the singleton source after expanding any filegroup in the // Return the singleton source after expanding any filegroup in the
// sources. // sources.
return PathForModuleSrc(ctx, (*p.srcs)[0]) src := srcs[0]
} 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) return PathForModuleSrc(ctx, src)
} else {
ctx.ModuleErrorf("prebuilt source was not set")
return nil
} }
} }
@ -104,18 +96,80 @@ func (p *Prebuilt) UsePrebuilt() bool {
return p.properties.UsePrebuilt 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() p := module.Prebuilt()
module.AddProperties(&p.properties) 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) { func InitSingleSourcePrebuiltModule(module PrebuiltInterface, srcProps interface{}, srcField string) {
p := module.Prebuilt() srcPropsValue := reflect.ValueOf(srcProps).Elem()
module.AddProperties(&p.properties) srcStructField, _ := srcPropsValue.Type().FieldByName(srcField)
p.srcProps = reflect.ValueOf(srcProps).Elem() if !srcPropsValue.IsValid() || srcStructField.Name == "" {
p.srcField, _ = p.srcProps.Type().FieldByName(srcField) panic(fmt.Errorf("invalid single source prebuilt %+v", module))
p.checkSingleSourceProperties() }
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 { type PrebuiltInterface interface {
@ -152,7 +206,7 @@ func PrebuiltMutator(ctx BottomUpMutatorContext) {
func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) { func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil { if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
p := m.Prebuilt() 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")) panic(fmt.Errorf("prebuilt module did not have InitPrebuiltModule called on it"))
} }
if !p.properties.SourceExists { 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 // 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. // will be used if it is marked "prefer" or if the source module is disabled.
func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module) bool { func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module) bool {
if p.srcs != nil && len(*p.srcs) == 0 { if p.srcsSupplier != nil && len(p.srcsSupplier()) == 0 {
return false
}
if p.srcProps.IsValid() && p.getSingleSourceFieldValue() == "" {
return false return false
} }
@ -210,24 +260,3 @@ func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module) bool {
func (p *Prebuilt) SourceExists() bool { func (p *Prebuilt) SourceExists() bool {
return p.properties.SourceExists 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()
}