| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 1 | // Copyright 2016 Google Inc. All rights reserved. | 
|  | 2 | // | 
|  | 3 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 4 | // you may not use this file except in compliance with the License. | 
|  | 5 | // You may obtain a copy of the License at | 
|  | 6 | // | 
|  | 7 | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 8 | // | 
|  | 9 | // Unless required by applicable law or agreed to in writing, software | 
|  | 10 | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 12 | // See the License for the specific language governing permissions and | 
|  | 13 | // limitations under the License. | 
|  | 14 |  | 
|  | 15 | package android | 
|  | 16 |  | 
|  | 17 | import ( | 
|  | 18 | "github.com/google/blueprint" | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 19 | ) | 
|  | 20 |  | 
|  | 21 | // This file implements hooks that external module types can use to inject logic into existing | 
|  | 22 | // module types.  Each hook takes an interface as a parameter so that new methods can be added | 
|  | 23 | // to the interface without breaking existing module types. | 
|  | 24 |  | 
|  | 25 | // Load hooks are run after the module's properties have been filled from the blueprint file, but | 
|  | 26 | // before the module has been split into architecture variants, and before defaults modules have | 
|  | 27 | // been applied. | 
|  | 28 | type LoadHookContext interface { | 
| Colin Cross | 6510f91 | 2017-11-29 00:27:14 -0800 | [diff] [blame] | 29 | // TODO: a new context that includes Config() but not Target(), etc.? | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 30 | BaseContext | 
|  | 31 | AppendProperties(...interface{}) | 
|  | 32 | PrependProperties(...interface{}) | 
| Colin Cross | 519917d | 2017-11-02 16:35:56 -0700 | [diff] [blame] | 33 | CreateModule(blueprint.ModuleFactory, ...interface{}) | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 34 | } | 
|  | 35 |  | 
|  | 36 | // Arch hooks are run after the module has been split into architecture variants, and can be used | 
|  | 37 | // to add architecture-specific properties. | 
|  | 38 | type ArchHookContext interface { | 
|  | 39 | BaseContext | 
|  | 40 | AppendProperties(...interface{}) | 
|  | 41 | PrependProperties(...interface{}) | 
|  | 42 | } | 
|  | 43 |  | 
|  | 44 | func AddLoadHook(m blueprint.Module, hook func(LoadHookContext)) { | 
|  | 45 | h := &m.(Module).base().hooks | 
|  | 46 | h.load = append(h.load, hook) | 
|  | 47 | } | 
|  | 48 |  | 
|  | 49 | func AddArchHook(m blueprint.Module, hook func(ArchHookContext)) { | 
|  | 50 | h := &m.(Module).base().hooks | 
|  | 51 | h.arch = append(h.arch, hook) | 
|  | 52 | } | 
|  | 53 |  | 
| Colin Cross | 519917d | 2017-11-02 16:35:56 -0700 | [diff] [blame] | 54 | func (x *hooks) runLoadHooks(ctx LoadHookContext, m *ModuleBase) { | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 55 | if len(x.load) > 0 { | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 56 | for _, x := range x.load { | 
| Colin Cross | 519917d | 2017-11-02 16:35:56 -0700 | [diff] [blame] | 57 | x(ctx) | 
|  | 58 | if ctx.Failed() { | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 59 | return | 
|  | 60 | } | 
|  | 61 | } | 
|  | 62 | } | 
|  | 63 | } | 
|  | 64 |  | 
| Colin Cross | 519917d | 2017-11-02 16:35:56 -0700 | [diff] [blame] | 65 | func (x *hooks) runArchHooks(ctx ArchHookContext, m *ModuleBase) { | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 66 | if len(x.arch) > 0 { | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 67 | for _, x := range x.arch { | 
| Colin Cross | 519917d | 2017-11-02 16:35:56 -0700 | [diff] [blame] | 68 | x(ctx) | 
|  | 69 | if ctx.Failed() { | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 70 | return | 
|  | 71 | } | 
|  | 72 | } | 
|  | 73 | } | 
|  | 74 | } | 
|  | 75 |  | 
|  | 76 | type InstallHookContext interface { | 
|  | 77 | ModuleContext | 
|  | 78 | Path() OutputPath | 
|  | 79 | Symlink() bool | 
|  | 80 | } | 
|  | 81 |  | 
|  | 82 | // Install hooks are run after a module creates a rule to install a file or symlink. | 
|  | 83 | // The installed path is available from InstallHookContext.Path(), and | 
|  | 84 | // InstallHookContext.Symlink() will be true if it was a symlink. | 
|  | 85 | func AddInstallHook(m blueprint.Module, hook func(InstallHookContext)) { | 
|  | 86 | h := &m.(Module).base().hooks | 
|  | 87 | h.install = append(h.install, hook) | 
|  | 88 | } | 
|  | 89 |  | 
|  | 90 | type installHookContext struct { | 
|  | 91 | ModuleContext | 
|  | 92 | path    OutputPath | 
|  | 93 | symlink bool | 
|  | 94 | } | 
|  | 95 |  | 
|  | 96 | func (x *installHookContext) Path() OutputPath { | 
|  | 97 | return x.path | 
|  | 98 | } | 
|  | 99 |  | 
|  | 100 | func (x *installHookContext) Symlink() bool { | 
|  | 101 | return x.symlink | 
|  | 102 | } | 
|  | 103 |  | 
|  | 104 | func (x *hooks) runInstallHooks(ctx ModuleContext, path OutputPath, symlink bool) { | 
|  | 105 | if len(x.install) > 0 { | 
|  | 106 | mctx := &installHookContext{ | 
|  | 107 | ModuleContext: ctx, | 
|  | 108 | path:          path, | 
|  | 109 | symlink:       symlink, | 
|  | 110 | } | 
|  | 111 | for _, x := range x.install { | 
|  | 112 | x(mctx) | 
|  | 113 | if mctx.Failed() { | 
|  | 114 | return | 
|  | 115 | } | 
|  | 116 | } | 
|  | 117 | } | 
|  | 118 | } | 
|  | 119 |  | 
|  | 120 | type hooks struct { | 
|  | 121 | load    []func(LoadHookContext) | 
|  | 122 | arch    []func(ArchHookContext) | 
|  | 123 | install []func(InstallHookContext) | 
|  | 124 | } | 
|  | 125 |  | 
|  | 126 | func loadHookMutator(ctx TopDownMutatorContext) { | 
|  | 127 | if m, ok := ctx.Module().(Module); ok { | 
| Colin Cross | 519917d | 2017-11-02 16:35:56 -0700 | [diff] [blame] | 128 | // Cast through *androidTopDownMutatorContext because AppendProperties is implemented | 
|  | 129 | // on *androidTopDownMutatorContext but not exposed through TopDownMutatorContext | 
|  | 130 | var loadHookCtx LoadHookContext = ctx.(*androidTopDownMutatorContext) | 
|  | 131 | m.base().hooks.runLoadHooks(loadHookCtx, m.base()) | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 132 | } | 
|  | 133 | } | 
|  | 134 |  | 
|  | 135 | func archHookMutator(ctx TopDownMutatorContext) { | 
|  | 136 | if m, ok := ctx.Module().(Module); ok { | 
| Colin Cross | 519917d | 2017-11-02 16:35:56 -0700 | [diff] [blame] | 137 | // Cast through *androidTopDownMutatorContext because AppendProperties is implemented | 
|  | 138 | // on *androidTopDownMutatorContext but not exposed through TopDownMutatorContext | 
|  | 139 | var archHookCtx ArchHookContext = ctx.(*androidTopDownMutatorContext) | 
|  | 140 | m.base().hooks.runArchHooks(archHookCtx, m.base()) | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 141 | } | 
|  | 142 | } |