| 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 ( | 
| Colin Cross | 31a738b | 2019-12-30 18:45:15 -0800 | [diff] [blame] | 18 | "reflect" | 
|  | 19 |  | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 20 | "github.com/google/blueprint" | 
| Colin Cross | 31a738b | 2019-12-30 18:45:15 -0800 | [diff] [blame] | 21 | "github.com/google/blueprint/proptools" | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 22 | ) | 
|  | 23 |  | 
|  | 24 | // This file implements hooks that external module types can use to inject logic into existing | 
|  | 25 | // module types.  Each hook takes an interface as a parameter so that new methods can be added | 
|  | 26 | // to the interface without breaking existing module types. | 
|  | 27 |  | 
|  | 28 | // Load hooks are run after the module's properties have been filled from the blueprint file, but | 
|  | 29 | // before the module has been split into architecture variants, and before defaults modules have | 
|  | 30 | // been applied. | 
|  | 31 | type LoadHookContext interface { | 
| Colin Cross | 1184b64 | 2019-12-30 18:43:07 -0800 | [diff] [blame] | 32 | EarlyModuleContext | 
|  | 33 |  | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 34 | AppendProperties(...interface{}) | 
|  | 35 | PrependProperties(...interface{}) | 
| Colin Cross | e003c4a | 2019-09-25 12:58:36 -0700 | [diff] [blame] | 36 | CreateModule(ModuleFactory, ...interface{}) Module | 
| Colin Cross | 9d34f35 | 2019-11-22 16:03:51 -0800 | [diff] [blame] | 37 |  | 
|  | 38 | registerScopedModuleType(name string, factory blueprint.ModuleFactory) | 
|  | 39 | moduleFactories() map[string]blueprint.ModuleFactory | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 40 | } | 
|  | 41 |  | 
| Paul Duffin | afa9fa1 | 2020-04-29 16:47:28 +0100 | [diff] [blame] | 42 | // Add a hook that will be called once the module has been loaded, i.e. its | 
|  | 43 | // properties have been initialized from the Android.bp file. | 
|  | 44 | // | 
|  | 45 | // Consider using SetDefaultableHook to register a hook for any module that implements | 
|  | 46 | // DefaultableModule as the hook is called after any defaults have been applied to the | 
|  | 47 | // module which could reduce duplication and make it easier to use. | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 48 | func AddLoadHook(m blueprint.Module, hook func(LoadHookContext)) { | 
| Colin Cross | 31a738b | 2019-12-30 18:45:15 -0800 | [diff] [blame] | 49 | blueprint.AddLoadHook(m, func(ctx blueprint.LoadHookContext) { | 
|  | 50 | actx := &loadHookContext{ | 
|  | 51 | earlyModuleContext: m.(Module).base().earlyModuleContextFactory(ctx), | 
|  | 52 | bp:                 ctx, | 
|  | 53 | } | 
|  | 54 | hook(actx) | 
|  | 55 | }) | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 56 | } | 
|  | 57 |  | 
| Colin Cross | 31a738b | 2019-12-30 18:45:15 -0800 | [diff] [blame] | 58 | type loadHookContext struct { | 
|  | 59 | earlyModuleContext | 
|  | 60 | bp     blueprint.LoadHookContext | 
|  | 61 | module Module | 
|  | 62 | } | 
|  | 63 |  | 
| Colin Cross | 9d34f35 | 2019-11-22 16:03:51 -0800 | [diff] [blame] | 64 | func (l *loadHookContext) moduleFactories() map[string]blueprint.ModuleFactory { | 
|  | 65 | return l.bp.ModuleFactories() | 
|  | 66 | } | 
|  | 67 |  | 
| Colin Cross | 31a738b | 2019-12-30 18:45:15 -0800 | [diff] [blame] | 68 | func (l *loadHookContext) AppendProperties(props ...interface{}) { | 
|  | 69 | for _, p := range props { | 
|  | 70 | err := proptools.AppendMatchingProperties(l.Module().base().customizableProperties, | 
|  | 71 | p, nil) | 
|  | 72 | if err != nil { | 
|  | 73 | if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { | 
|  | 74 | l.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) | 
|  | 75 | } else { | 
|  | 76 | panic(err) | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 77 | } | 
|  | 78 | } | 
|  | 79 | } | 
|  | 80 | } | 
|  | 81 |  | 
| Colin Cross | 31a738b | 2019-12-30 18:45:15 -0800 | [diff] [blame] | 82 | func (l *loadHookContext) PrependProperties(props ...interface{}) { | 
|  | 83 | for _, p := range props { | 
|  | 84 | err := proptools.PrependMatchingProperties(l.Module().base().customizableProperties, | 
|  | 85 | p, nil) | 
|  | 86 | if err != nil { | 
|  | 87 | if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { | 
|  | 88 | l.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) | 
|  | 89 | } else { | 
|  | 90 | panic(err) | 
|  | 91 | } | 
|  | 92 | } | 
|  | 93 | } | 
|  | 94 | } | 
|  | 95 |  | 
|  | 96 | func (l *loadHookContext) CreateModule(factory ModuleFactory, props ...interface{}) Module { | 
|  | 97 | inherited := []interface{}{&l.Module().base().commonProperties} | 
|  | 98 | module := l.bp.CreateModule(ModuleFactoryAdaptor(factory), append(inherited, props...)...).(Module) | 
|  | 99 |  | 
|  | 100 | if l.Module().base().variableProperties != nil && module.base().variableProperties != nil { | 
|  | 101 | src := l.Module().base().variableProperties | 
|  | 102 | dst := []interface{}{ | 
|  | 103 | module.base().variableProperties, | 
|  | 104 | // Put an empty copy of the src properties into dst so that properties in src that are not in dst | 
|  | 105 | // don't cause a "failed to find property to extend" error. | 
| Colin Cross | 43e789d | 2020-01-28 09:46:50 -0800 | [diff] [blame] | 106 | proptools.CloneEmptyProperties(reflect.ValueOf(src)).Interface(), | 
| Colin Cross | 31a738b | 2019-12-30 18:45:15 -0800 | [diff] [blame] | 107 | } | 
|  | 108 | err := proptools.AppendMatchingProperties(dst, src, nil) | 
|  | 109 | if err != nil { | 
|  | 110 | panic(err) | 
|  | 111 | } | 
|  | 112 | } | 
|  | 113 |  | 
|  | 114 | return module | 
|  | 115 | } | 
|  | 116 |  | 
| Colin Cross | 9d34f35 | 2019-11-22 16:03:51 -0800 | [diff] [blame] | 117 | func (l *loadHookContext) registerScopedModuleType(name string, factory blueprint.ModuleFactory) { | 
|  | 118 | l.bp.RegisterScopedModuleType(name, factory) | 
|  | 119 | } | 
|  | 120 |  | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 121 | type InstallHookContext interface { | 
|  | 122 | ModuleContext | 
| David Srbecky | 0765641 | 2020-06-04 01:26:16 +0100 | [diff] [blame] | 123 | SrcPath() Path | 
| Colin Cross | 70dda7e | 2019-10-01 22:05:35 -0700 | [diff] [blame] | 124 | Path() InstallPath | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 125 | Symlink() bool | 
|  | 126 | } | 
|  | 127 |  | 
|  | 128 | // Install hooks are run after a module creates a rule to install a file or symlink. | 
|  | 129 | // The installed path is available from InstallHookContext.Path(), and | 
|  | 130 | // InstallHookContext.Symlink() will be true if it was a symlink. | 
|  | 131 | func AddInstallHook(m blueprint.Module, hook func(InstallHookContext)) { | 
|  | 132 | h := &m.(Module).base().hooks | 
|  | 133 | h.install = append(h.install, hook) | 
|  | 134 | } | 
|  | 135 |  | 
|  | 136 | type installHookContext struct { | 
|  | 137 | ModuleContext | 
| David Srbecky | 0765641 | 2020-06-04 01:26:16 +0100 | [diff] [blame] | 138 | srcPath Path | 
| Colin Cross | 70dda7e | 2019-10-01 22:05:35 -0700 | [diff] [blame] | 139 | path    InstallPath | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 140 | symlink bool | 
|  | 141 | } | 
|  | 142 |  | 
| David Srbecky | 0765641 | 2020-06-04 01:26:16 +0100 | [diff] [blame] | 143 | var _ InstallHookContext = &installHookContext{} | 
|  | 144 |  | 
|  | 145 | func (x *installHookContext) SrcPath() Path { | 
|  | 146 | return x.srcPath | 
|  | 147 | } | 
|  | 148 |  | 
| Colin Cross | 70dda7e | 2019-10-01 22:05:35 -0700 | [diff] [blame] | 149 | func (x *installHookContext) Path() InstallPath { | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 150 | return x.path | 
|  | 151 | } | 
|  | 152 |  | 
|  | 153 | func (x *installHookContext) Symlink() bool { | 
|  | 154 | return x.symlink | 
|  | 155 | } | 
|  | 156 |  | 
| David Srbecky | 0765641 | 2020-06-04 01:26:16 +0100 | [diff] [blame] | 157 | func (x *hooks) runInstallHooks(ctx ModuleContext, srcPath Path, path InstallPath, symlink bool) { | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 158 | if len(x.install) > 0 { | 
|  | 159 | mctx := &installHookContext{ | 
|  | 160 | ModuleContext: ctx, | 
| David Srbecky | 0765641 | 2020-06-04 01:26:16 +0100 | [diff] [blame] | 161 | srcPath:       srcPath, | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 162 | path:          path, | 
|  | 163 | symlink:       symlink, | 
|  | 164 | } | 
|  | 165 | for _, x := range x.install { | 
|  | 166 | x(mctx) | 
|  | 167 | if mctx.Failed() { | 
|  | 168 | return | 
|  | 169 | } | 
|  | 170 | } | 
|  | 171 | } | 
|  | 172 | } | 
|  | 173 |  | 
|  | 174 | type hooks struct { | 
| Colin Cross | 178a509 | 2016-09-13 13:42:32 -0700 | [diff] [blame] | 175 | install []func(InstallHookContext) | 
|  | 176 | } |