hooks.go 5.2 KB

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