blob: 7530f8d0f3a1f55877e290e258229d3de6a4acca [file] [log] [blame]
Colin Cross178a5092016-09-13 13:42:32 -07001// 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
15package android
16
17import (
18 "github.com/google/blueprint"
19 "github.com/google/blueprint/proptools"
20)
21
22// This file implements hooks that external module types can use to inject logic into existing
23// module types. Each hook takes an interface as a parameter so that new methods can be added
24// to the interface without breaking existing module types.
25
26// Load hooks are run after the module's properties have been filled from the blueprint file, but
27// before the module has been split into architecture variants, and before defaults modules have
28// been applied.
29type LoadHookContext interface {
30 // TODO: a new context that includes AConfig() but not Target(), etc.?
31 BaseContext
32 AppendProperties(...interface{})
33 PrependProperties(...interface{})
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.
38type ArchHookContext interface {
39 BaseContext
40 AppendProperties(...interface{})
41 PrependProperties(...interface{})
42}
43
44func AddLoadHook(m blueprint.Module, hook func(LoadHookContext)) {
45 h := &m.(Module).base().hooks
46 h.load = append(h.load, hook)
47}
48
49func AddArchHook(m blueprint.Module, hook func(ArchHookContext)) {
50 h := &m.(Module).base().hooks
51 h.arch = append(h.arch, hook)
52}
53
54type propertyHookContext struct {
55 BaseContext
56
57 module *ModuleBase
58}
59
60func (ctx *propertyHookContext) AppendProperties(props ...interface{}) {
61 for _, p := range props {
62 err := proptools.AppendMatchingProperties(ctx.module.customizableProperties, p, nil)
63 if err != nil {
64 if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
65 ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
66 } else {
67 panic(err)
68 }
69 }
70 }
71}
72
73func (ctx *propertyHookContext) PrependProperties(props ...interface{}) {
74 for _, p := range props {
75 err := proptools.PrependMatchingProperties(ctx.module.customizableProperties, p, nil)
76 if err != nil {
77 if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
78 ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
79 } else {
80 panic(err)
81 }
82 }
83 }
84}
85
86func (x *hooks) runLoadHooks(ctx BaseContext, m *ModuleBase) {
87 if len(x.load) > 0 {
88 mctx := &propertyHookContext{
89 BaseContext: ctx,
90 module: m,
91 }
92 for _, x := range x.load {
93 x(mctx)
94 if mctx.Failed() {
95 return
96 }
97 }
98 }
99}
100
101func (x *hooks) runArchHooks(ctx BaseContext, m *ModuleBase) {
102 if len(x.arch) > 0 {
103 mctx := &propertyHookContext{
104 BaseContext: ctx,
105 module: m,
106 }
107 for _, x := range x.arch {
108 x(mctx)
109 if mctx.Failed() {
110 return
111 }
112 }
113 }
114}
115
116type InstallHookContext interface {
117 ModuleContext
118 Path() OutputPath
119 Symlink() bool
120}
121
122// Install hooks are run after a module creates a rule to install a file or symlink.
123// The installed path is available from InstallHookContext.Path(), and
124// InstallHookContext.Symlink() will be true if it was a symlink.
125func AddInstallHook(m blueprint.Module, hook func(InstallHookContext)) {
126 h := &m.(Module).base().hooks
127 h.install = append(h.install, hook)
128}
129
130type installHookContext struct {
131 ModuleContext
132 path OutputPath
133 symlink bool
134}
135
136func (x *installHookContext) Path() OutputPath {
137 return x.path
138}
139
140func (x *installHookContext) Symlink() bool {
141 return x.symlink
142}
143
144func (x *hooks) runInstallHooks(ctx ModuleContext, path OutputPath, symlink bool) {
145 if len(x.install) > 0 {
146 mctx := &installHookContext{
147 ModuleContext: ctx,
148 path: path,
149 symlink: symlink,
150 }
151 for _, x := range x.install {
152 x(mctx)
153 if mctx.Failed() {
154 return
155 }
156 }
157 }
158}
159
160type hooks struct {
161 load []func(LoadHookContext)
162 arch []func(ArchHookContext)
163 install []func(InstallHookContext)
164}
165
166func loadHookMutator(ctx TopDownMutatorContext) {
167 if m, ok := ctx.Module().(Module); ok {
168 m.base().hooks.runLoadHooks(ctx, m.base())
169 }
170}
171
172func archHookMutator(ctx TopDownMutatorContext) {
173 if m, ok := ctx.Module().(Module); ok {
174 m.base().hooks.runArchHooks(ctx, m.base())
175 }
176}