Home | History | Annotate | Download | only in android
      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"
     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.
     29 type 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.
     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 
     54 type propertyHookContext struct {
     55 	BaseContext
     56 
     57 	module *ModuleBase
     58 }
     59 
     60 func (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 
     73 func (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 
     86 func (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 
    101 func (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 
    116 type 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.
    125 func AddInstallHook(m blueprint.Module, hook func(InstallHookContext)) {
    126 	h := &m.(Module).base().hooks
    127 	h.install = append(h.install, hook)
    128 }
    129 
    130 type installHookContext struct {
    131 	ModuleContext
    132 	path    OutputPath
    133 	symlink bool
    134 }
    135 
    136 func (x *installHookContext) Path() OutputPath {
    137 	return x.path
    138 }
    139 
    140 func (x *installHookContext) Symlink() bool {
    141 	return x.symlink
    142 }
    143 
    144 func (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 
    160 type hooks struct {
    161 	load    []func(LoadHookContext)
    162 	arch    []func(ArchHookContext)
    163 	install []func(InstallHookContext)
    164 }
    165 
    166 func loadHookMutator(ctx TopDownMutatorContext) {
    167 	if m, ok := ctx.Module().(Module); ok {
    168 		m.base().hooks.runLoadHooks(ctx, m.base())
    169 	}
    170 }
    171 
    172 func archHookMutator(ctx TopDownMutatorContext) {
    173 	if m, ok := ctx.Module().(Module); ok {
    174 		m.base().hooks.runArchHooks(ctx, m.base())
    175 	}
    176 }
    177