From dcb4bd6fb49b40df28f121b74c1057b9c9eb15f1 Mon Sep 17 00:00:00 2001 From: Paul Duffin Date: Thu, 12 Mar 2020 23:43:52 +0000 Subject: [PATCH] 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 --- android/prebuilt.go | 139 ++++++++++++++++++++++++++------------------ 1 file changed, 84 insertions(+), 55 deletions(-) diff --git a/android/prebuilt.go b/android/prebuilt.go index 2d16f65d7..c902ec826 100644 --- a/android/prebuilt.go +++ b/android/prebuilt.go @@ -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,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 // 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]) - } 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 - } + src := srcs[0] 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 } -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() -}