f31c90050c
These contained duplicate code, but evolved separately in the effort to identify module type of those created with CreateModule. This refactors to share a common implementation between the two. Test: m json-module-graph and verify Type fields Test: CI Change-Id: Ifdb9a006d9b1bef7411f9ce3a4384797693b4bfc
197 lines
6.1 KiB
Go
197 lines
6.1 KiB
Go
// Copyright 2016 Google Inc. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package android
|
|
|
|
import (
|
|
"fmt"
|
|
"path"
|
|
"reflect"
|
|
"runtime"
|
|
|
|
"github.com/google/blueprint"
|
|
"github.com/google/blueprint/proptools"
|
|
)
|
|
|
|
// This file implements hooks that external module types can use to inject logic into existing
|
|
// module types. Each hook takes an interface as a parameter so that new methods can be added
|
|
// to the interface without breaking existing module types.
|
|
|
|
// Load hooks are run after the module's properties have been filled from the blueprint file, but
|
|
// before the module has been split into architecture variants, and before defaults modules have
|
|
// been applied.
|
|
type LoadHookContext interface {
|
|
EarlyModuleContext
|
|
|
|
AppendProperties(...interface{})
|
|
PrependProperties(...interface{})
|
|
CreateModule(ModuleFactory, ...interface{}) Module
|
|
|
|
registerScopedModuleType(name string, factory blueprint.ModuleFactory)
|
|
moduleFactories() map[string]blueprint.ModuleFactory
|
|
}
|
|
|
|
// Add a hook that will be called once the module has been loaded, i.e. its
|
|
// properties have been initialized from the Android.bp file.
|
|
//
|
|
// Consider using SetDefaultableHook to register a hook for any module that implements
|
|
// DefaultableModule as the hook is called after any defaults have been applied to the
|
|
// module which could reduce duplication and make it easier to use.
|
|
func AddLoadHook(m blueprint.Module, hook func(LoadHookContext)) {
|
|
blueprint.AddLoadHook(m, func(ctx blueprint.LoadHookContext) {
|
|
actx := &loadHookContext{
|
|
earlyModuleContext: m.(Module).base().earlyModuleContextFactory(ctx),
|
|
bp: ctx,
|
|
}
|
|
hook(actx)
|
|
})
|
|
}
|
|
|
|
type loadHookContext struct {
|
|
earlyModuleContext
|
|
bp blueprint.LoadHookContext
|
|
module Module
|
|
}
|
|
|
|
func (l *loadHookContext) moduleFactories() map[string]blueprint.ModuleFactory {
|
|
return l.bp.ModuleFactories()
|
|
}
|
|
|
|
func (l *loadHookContext) appendPrependHelper(props []interface{},
|
|
extendFn func([]interface{}, interface{}, proptools.ExtendPropertyFilterFunc) error) {
|
|
for _, p := range props {
|
|
err := extendFn(l.Module().base().GetProperties(), p, nil)
|
|
if err != nil {
|
|
if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
|
|
l.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
|
|
} else {
|
|
panic(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
func (l *loadHookContext) AppendProperties(props ...interface{}) {
|
|
l.appendPrependHelper(props, proptools.AppendMatchingProperties)
|
|
}
|
|
|
|
func (l *loadHookContext) PrependProperties(props ...interface{}) {
|
|
l.appendPrependHelper(props, proptools.PrependMatchingProperties)
|
|
}
|
|
|
|
func (l *loadHookContext) createModule(factory blueprint.ModuleFactory, name string, props ...interface{}) blueprint.Module {
|
|
return l.bp.CreateModule(factory, name, props...)
|
|
}
|
|
|
|
type createModuleContext interface {
|
|
Module() Module
|
|
createModule(blueprint.ModuleFactory, string, ...interface{}) blueprint.Module
|
|
}
|
|
|
|
func createModule(ctx createModuleContext, factory ModuleFactory, ext string, props ...interface{}) Module {
|
|
inherited := []interface{}{&ctx.Module().base().commonProperties}
|
|
|
|
var typeName string
|
|
if typeNameLookup, ok := ModuleTypeByFactory()[reflect.ValueOf(factory)]; ok {
|
|
typeName = typeNameLookup
|
|
} else {
|
|
factoryPtr := reflect.ValueOf(factory).Pointer()
|
|
factoryFunc := runtime.FuncForPC(factoryPtr)
|
|
filePath, _ := factoryFunc.FileLine(factoryPtr)
|
|
typeName = fmt.Sprintf("%s_%s", path.Base(filePath), factoryFunc.Name())
|
|
}
|
|
typeName = typeName + "_" + ext
|
|
|
|
module := ctx.createModule(ModuleFactoryAdaptor(factory), typeName, append(inherited, props...)...).(Module)
|
|
|
|
if ctx.Module().base().variableProperties != nil && module.base().variableProperties != nil {
|
|
src := ctx.Module().base().variableProperties
|
|
dst := []interface{}{
|
|
module.base().variableProperties,
|
|
// Put an empty copy of the src properties into dst so that properties in src that are not in dst
|
|
// don't cause a "failed to find property to extend" error.
|
|
proptools.CloneEmptyProperties(reflect.ValueOf(src)).Interface(),
|
|
}
|
|
err := proptools.AppendMatchingProperties(dst, src, nil)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
return module
|
|
}
|
|
|
|
func (l *loadHookContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
|
|
return createModule(l, factory, "_loadHookModule", props...)
|
|
}
|
|
|
|
func (l *loadHookContext) registerScopedModuleType(name string, factory blueprint.ModuleFactory) {
|
|
l.bp.RegisterScopedModuleType(name, factory)
|
|
}
|
|
|
|
type InstallHookContext interface {
|
|
ModuleContext
|
|
SrcPath() Path
|
|
Path() InstallPath
|
|
Symlink() bool
|
|
}
|
|
|
|
// Install hooks are run after a module creates a rule to install a file or symlink.
|
|
// The installed path is available from InstallHookContext.Path(), and
|
|
// InstallHookContext.Symlink() will be true if it was a symlink.
|
|
func AddInstallHook(m blueprint.Module, hook func(InstallHookContext)) {
|
|
h := &m.(Module).base().hooks
|
|
h.install = append(h.install, hook)
|
|
}
|
|
|
|
type installHookContext struct {
|
|
ModuleContext
|
|
srcPath Path
|
|
path InstallPath
|
|
symlink bool
|
|
}
|
|
|
|
var _ InstallHookContext = &installHookContext{}
|
|
|
|
func (x *installHookContext) SrcPath() Path {
|
|
return x.srcPath
|
|
}
|
|
|
|
func (x *installHookContext) Path() InstallPath {
|
|
return x.path
|
|
}
|
|
|
|
func (x *installHookContext) Symlink() bool {
|
|
return x.symlink
|
|
}
|
|
|
|
func (x *hooks) runInstallHooks(ctx ModuleContext, srcPath Path, path InstallPath, symlink bool) {
|
|
if len(x.install) > 0 {
|
|
mctx := &installHookContext{
|
|
ModuleContext: ctx,
|
|
srcPath: srcPath,
|
|
path: path,
|
|
symlink: symlink,
|
|
}
|
|
for _, x := range x.install {
|
|
x(mctx)
|
|
if mctx.Failed() {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
type hooks struct {
|
|
install []func(InstallHookContext)
|
|
}
|