diff options
author | Colin Cross <ccross@android.com> | 2016-09-13 13:42:32 -0700 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2016-09-13 17:37:32 -0700 |
commit | 178a5098550a630bc242c7322abc2a7f59369a77 (patch) | |
tree | 031658e468354be3cd91c4cfac11df8fe0b442fa /android/hooks.go | |
parent | b4ce0ecad6500edb0ea464ee78b59a04138aed41 (diff) | |
download | build_soong-178a5098550a630bc242c7322abc2a7f59369a77.tar.gz build_soong-178a5098550a630bc242c7322abc2a7f59369a77.tar.bz2 build_soong-178a5098550a630bc242c7322abc2a7f59369a77.zip |
Replace PropertyCustomizer with hooks
Replace PropertyCustomizer with a more extensible hooks mechanism.
Instead of passing an object that satisifies an interface, pass a
function pointer that takes a context interface as an argument. Callers
can use lambdas to capture any other necessary parameters like property
structs.
Also add two new hooks, arch hooks that occur after splitting modules
into arch variants, and install hooks that occur each time a file is
installed to the output directory.
Change-Id: I3a3e34aa97f1a92d3a31e5004b4b1ba68869d242
Diffstat (limited to 'android/hooks.go')
-rw-r--r-- | android/hooks.go | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/android/hooks.go b/android/hooks.go new file mode 100644 index 00000000..7530f8d0 --- /dev/null +++ b/android/hooks.go @@ -0,0 +1,176 @@ +// 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 ( + "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 { + // TODO: a new context that includes AConfig() but not Target(), etc.? + BaseContext + AppendProperties(...interface{}) + PrependProperties(...interface{}) +} + +// Arch hooks are run after the module has been split into architecture variants, and can be used +// to add architecture-specific properties. +type ArchHookContext interface { + BaseContext + AppendProperties(...interface{}) + PrependProperties(...interface{}) +} + +func AddLoadHook(m blueprint.Module, hook func(LoadHookContext)) { + h := &m.(Module).base().hooks + h.load = append(h.load, hook) +} + +func AddArchHook(m blueprint.Module, hook func(ArchHookContext)) { + h := &m.(Module).base().hooks + h.arch = append(h.arch, hook) +} + +type propertyHookContext struct { + BaseContext + + module *ModuleBase +} + +func (ctx *propertyHookContext) AppendProperties(props ...interface{}) { + for _, p := range props { + err := proptools.AppendMatchingProperties(ctx.module.customizableProperties, p, nil) + if err != nil { + if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { + ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) + } else { + panic(err) + } + } + } +} + +func (ctx *propertyHookContext) PrependProperties(props ...interface{}) { + for _, p := range props { + err := proptools.PrependMatchingProperties(ctx.module.customizableProperties, p, nil) + if err != nil { + if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { + ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) + } else { + panic(err) + } + } + } +} + +func (x *hooks) runLoadHooks(ctx BaseContext, m *ModuleBase) { + if len(x.load) > 0 { + mctx := &propertyHookContext{ + BaseContext: ctx, + module: m, + } + for _, x := range x.load { + x(mctx) + if mctx.Failed() { + return + } + } + } +} + +func (x *hooks) runArchHooks(ctx BaseContext, m *ModuleBase) { + if len(x.arch) > 0 { + mctx := &propertyHookContext{ + BaseContext: ctx, + module: m, + } + for _, x := range x.arch { + x(mctx) + if mctx.Failed() { + return + } + } + } +} + +type InstallHookContext interface { + ModuleContext + Path() OutputPath + 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 + path OutputPath + symlink bool +} + +func (x *installHookContext) Path() OutputPath { + return x.path +} + +func (x *installHookContext) Symlink() bool { + return x.symlink +} + +func (x *hooks) runInstallHooks(ctx ModuleContext, path OutputPath, symlink bool) { + if len(x.install) > 0 { + mctx := &installHookContext{ + ModuleContext: ctx, + path: path, + symlink: symlink, + } + for _, x := range x.install { + x(mctx) + if mctx.Failed() { + return + } + } + } +} + +type hooks struct { + load []func(LoadHookContext) + arch []func(ArchHookContext) + install []func(InstallHookContext) +} + +func loadHookMutator(ctx TopDownMutatorContext) { + if m, ok := ctx.Module().(Module); ok { + m.base().hooks.runLoadHooks(ctx, m.base()) + } +} + +func archHookMutator(ctx TopDownMutatorContext) { + if m, ok := ctx.Module().(Module); ok { + m.base().hooks.runArchHooks(ctx, m.base()) + } +} |