Merge pull request #309 from colincross/providers
Add Providers to Blueprint
This commit is contained in:
commit
8a747a0864
6 changed files with 786 additions and 2 deletions
|
@ -17,6 +17,7 @@ bootstrap_go_package {
|
||||||
"ninja_strings.go",
|
"ninja_strings.go",
|
||||||
"ninja_writer.go",
|
"ninja_writer.go",
|
||||||
"package_ctx.go",
|
"package_ctx.go",
|
||||||
|
"provider.go",
|
||||||
"scope.go",
|
"scope.go",
|
||||||
"singleton_ctx.go",
|
"singleton_ctx.go",
|
||||||
],
|
],
|
||||||
|
@ -26,6 +27,7 @@ bootstrap_go_package {
|
||||||
"module_ctx_test.go",
|
"module_ctx_test.go",
|
||||||
"ninja_strings_test.go",
|
"ninja_strings_test.go",
|
||||||
"ninja_writer_test.go",
|
"ninja_writer_test.go",
|
||||||
|
"provider_test.go",
|
||||||
"splice_modules_test.go",
|
"splice_modules_test.go",
|
||||||
"visit_test.go",
|
"visit_test.go",
|
||||||
],
|
],
|
||||||
|
|
62
context.go
62
context.go
|
@ -117,6 +117,19 @@ type Context struct {
|
||||||
srcDir string
|
srcDir string
|
||||||
fs pathtools.FileSystem
|
fs pathtools.FileSystem
|
||||||
moduleListFile string
|
moduleListFile string
|
||||||
|
|
||||||
|
// Mutators indexed by the ID of the provider associated with them. Not all mutators will
|
||||||
|
// have providers, and not all providers will have a mutator, or if they do the mutator may
|
||||||
|
// not be registered in this Context.
|
||||||
|
providerMutators []*mutatorInfo
|
||||||
|
|
||||||
|
// The currently running mutator
|
||||||
|
startedMutator *mutatorInfo
|
||||||
|
// True for any mutators that have already run over all modules
|
||||||
|
finishedMutators map[*mutatorInfo]bool
|
||||||
|
|
||||||
|
// Can be set by tests to avoid invalidating Module values after mutators.
|
||||||
|
skipCloneModulesAfterMutators bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// An Error describes a problem that was encountered that is related to a
|
// An Error describes a problem that was encountered that is related to a
|
||||||
|
@ -254,6 +267,14 @@ type moduleInfo struct {
|
||||||
|
|
||||||
// set during PrepareBuildActions
|
// set during PrepareBuildActions
|
||||||
actionDefs localBuildActions
|
actionDefs localBuildActions
|
||||||
|
|
||||||
|
providers []interface{}
|
||||||
|
|
||||||
|
startedMutator *mutatorInfo
|
||||||
|
finishedMutator *mutatorInfo
|
||||||
|
|
||||||
|
startedGenerateBuildActions bool
|
||||||
|
finishedGenerateBuildActions bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type variant struct {
|
type variant struct {
|
||||||
|
@ -363,6 +384,7 @@ func newContext() *Context {
|
||||||
moduleInfo: make(map[Module]*moduleInfo),
|
moduleInfo: make(map[Module]*moduleInfo),
|
||||||
globs: make(map[string]GlobPath),
|
globs: make(map[string]GlobPath),
|
||||||
fs: pathtools.OsFs,
|
fs: pathtools.OsFs,
|
||||||
|
finishedMutators: make(map[*mutatorInfo]bool),
|
||||||
ninjaBuildDir: nil,
|
ninjaBuildDir: nil,
|
||||||
requiredNinjaMajor: 1,
|
requiredNinjaMajor: 1,
|
||||||
requiredNinjaMinor: 7,
|
requiredNinjaMinor: 7,
|
||||||
|
@ -1330,10 +1352,11 @@ func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
|
||||||
|
|
||||||
m := *origModule
|
m := *origModule
|
||||||
newModule := &m
|
newModule := &m
|
||||||
newModule.directDeps = append([]depInfo{}, origModule.directDeps...)
|
newModule.directDeps = append([]depInfo(nil), origModule.directDeps...)
|
||||||
newModule.logicModule = newLogicModule
|
newModule.logicModule = newLogicModule
|
||||||
newModule.variant = newVariant(origModule, mutatorName, variationName, local)
|
newModule.variant = newVariant(origModule, mutatorName, variationName, local)
|
||||||
newModule.properties = newProperties
|
newModule.properties = newProperties
|
||||||
|
newModule.providers = append([]interface{}(nil), origModule.providers...)
|
||||||
|
|
||||||
newModules = append(newModules, newModule)
|
newModules = append(newModules, newModule)
|
||||||
|
|
||||||
|
@ -1518,6 +1541,8 @@ func (c *Context) ResolveDependencies(config interface{}) (deps []string, errs [
|
||||||
|
|
||||||
func (c *Context) resolveDependencies(ctx context.Context, config interface{}) (deps []string, errs []error) {
|
func (c *Context) resolveDependencies(ctx context.Context, config interface{}) (deps []string, errs []error) {
|
||||||
pprof.Do(ctx, pprof.Labels("blueprint", "ResolveDependencies"), func(ctx context.Context) {
|
pprof.Do(ctx, pprof.Labels("blueprint", "ResolveDependencies"), func(ctx context.Context) {
|
||||||
|
c.initProviders()
|
||||||
|
|
||||||
c.liveGlobals = newLiveTracker(config)
|
c.liveGlobals = newLiveTracker(config)
|
||||||
|
|
||||||
deps, errs = c.generateSingletonBuildActions(config, c.preSingletonInfo, c.liveGlobals)
|
deps, errs = c.generateSingletonBuildActions(config, c.preSingletonInfo, c.liveGlobals)
|
||||||
|
@ -1537,7 +1562,9 @@ func (c *Context) resolveDependencies(ctx context.Context, config interface{}) (
|
||||||
}
|
}
|
||||||
deps = append(deps, mutatorDeps...)
|
deps = append(deps, mutatorDeps...)
|
||||||
|
|
||||||
c.cloneModules()
|
if !c.skipCloneModulesAfterMutators {
|
||||||
|
c.cloneModules()
|
||||||
|
}
|
||||||
|
|
||||||
c.dependenciesReady = true
|
c.dependenciesReady = true
|
||||||
})
|
})
|
||||||
|
@ -2419,6 +2446,8 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
|
||||||
pauseCh: pause,
|
pauseCh: pause,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.startedMutator = mutator
|
||||||
|
|
||||||
func() {
|
func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
|
@ -2434,6 +2463,8 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
|
||||||
direction.run(mutator, mctx)
|
direction.run(mutator, mctx)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
module.finishedMutator = mutator
|
||||||
|
|
||||||
if len(mctx.errs) > 0 {
|
if len(mctx.errs) > 0 {
|
||||||
errsCh <- mctx.errs
|
errsCh <- mctx.errs
|
||||||
return true
|
return true
|
||||||
|
@ -2482,6 +2513,8 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
c.startedMutator = mutator
|
||||||
|
|
||||||
var visitErrs []error
|
var visitErrs []error
|
||||||
if mutator.parallel {
|
if mutator.parallel {
|
||||||
visitErrs = parallelVisit(c.modulesSorted, direction.orderer(), parallelVisitLimit, visit)
|
visitErrs = parallelVisit(c.modulesSorted, direction.orderer(), parallelVisitLimit, visit)
|
||||||
|
@ -2493,6 +2526,8 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
|
||||||
return nil, visitErrs
|
return nil, visitErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.finishedMutators[mutator] = true
|
||||||
|
|
||||||
done <- true
|
done <- true
|
||||||
|
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
|
@ -2702,6 +2737,8 @@ func (c *Context) generateModuleBuildActions(config interface{},
|
||||||
handledMissingDeps: module.missingDeps == nil,
|
handledMissingDeps: module.missingDeps == nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mctx.module.startedGenerateBuildActions = true
|
||||||
|
|
||||||
func() {
|
func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
|
@ -2717,6 +2754,8 @@ func (c *Context) generateModuleBuildActions(config interface{},
|
||||||
mctx.module.logicModule.GenerateBuildActions(mctx)
|
mctx.module.logicModule.GenerateBuildActions(mctx)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
mctx.module.finishedGenerateBuildActions = true
|
||||||
|
|
||||||
if len(mctx.errs) > 0 {
|
if len(mctx.errs) > 0 {
|
||||||
errsCh <- mctx.errs
|
errsCh <- mctx.errs
|
||||||
return true
|
return true
|
||||||
|
@ -3287,6 +3326,25 @@ func (c *Context) ModuleType(logicModule Module) string {
|
||||||
return module.typeName
|
return module.typeName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ModuleProvider returns the value, if any, for the provider for a module. If the value for the
|
||||||
|
// provider was not set it returns the zero value of the type of the provider, which means the
|
||||||
|
// return value can always be type-asserted to the type of the provider. The return value should
|
||||||
|
// always be considered read-only. It panics if called before the appropriate mutator or
|
||||||
|
// GenerateBuildActions pass for the provider on the module. The value returned may be a deep
|
||||||
|
// copy of the value originally passed to SetProvider.
|
||||||
|
func (c *Context) ModuleProvider(logicModule Module, provider ProviderKey) interface{} {
|
||||||
|
module := c.moduleInfo[logicModule]
|
||||||
|
value, _ := c.provider(module, provider)
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModuleHasProvider returns true if the provider for the given module has been set.
|
||||||
|
func (c *Context) ModuleHasProvider(logicModule Module, provider ProviderKey) bool {
|
||||||
|
module := c.moduleInfo[logicModule]
|
||||||
|
_, ok := c.provider(module, provider)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Context) BlueprintFile(logicModule Module) string {
|
func (c *Context) BlueprintFile(logicModule Module) string {
|
||||||
module := c.moduleInfo[logicModule]
|
module := c.moduleInfo[logicModule]
|
||||||
return module.relBlueprintsFile
|
return module.relBlueprintsFile
|
||||||
|
|
|
@ -306,6 +306,31 @@ type BaseModuleContext interface {
|
||||||
// other words, it checks for the module AddReverseDependency would add a
|
// other words, it checks for the module AddReverseDependency would add a
|
||||||
// dependency on with the same argument.
|
// dependency on with the same argument.
|
||||||
OtherModuleReverseDependencyVariantExists(name string) bool
|
OtherModuleReverseDependencyVariantExists(name string) bool
|
||||||
|
|
||||||
|
// OtherModuleProvider returns the value for a provider for the given module. If the value is
|
||||||
|
// not set it returns the zero value of the type of the provider, so the return value can always
|
||||||
|
// be type asserted to the type of the provider. The value returned may be a deep copy of the
|
||||||
|
// value originally passed to SetProvider.
|
||||||
|
OtherModuleProvider(m Module, provider ProviderKey) interface{}
|
||||||
|
|
||||||
|
// OtherModuleHasProvider returns true if the provider for the given module has been set.
|
||||||
|
OtherModuleHasProvider(m Module, provider ProviderKey) bool
|
||||||
|
|
||||||
|
// Provider returns the value for a provider for the current module. If the value is
|
||||||
|
// not set it returns the zero value of the type of the provider, so the return value can always
|
||||||
|
// be type asserted to the type of the provider. It panics if called before the appropriate
|
||||||
|
// mutator or GenerateBuildActions pass for the provider. The value returned may be a deep
|
||||||
|
// copy of the value originally passed to SetProvider.
|
||||||
|
Provider(provider ProviderKey) interface{}
|
||||||
|
|
||||||
|
// HasProvider returns true if the provider for the current module has been set.
|
||||||
|
HasProvider(provider ProviderKey) bool
|
||||||
|
|
||||||
|
// SetProvider sets the value for a provider for the current module. It panics if not called
|
||||||
|
// during the appropriate mutator or GenerateBuildActions pass for the provider, if the value
|
||||||
|
// is not of the appropriate type, or if the value has already been set. The value should not
|
||||||
|
// be modified after being passed to SetProvider.
|
||||||
|
SetProvider(provider ProviderKey, value interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
type DynamicDependerModuleContext BottomUpMutatorContext
|
type DynamicDependerModuleContext BottomUpMutatorContext
|
||||||
|
@ -523,6 +548,32 @@ func (m *baseModuleContext) OtherModuleReverseDependencyVariantExists(name strin
|
||||||
return found != nil
|
return found != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *baseModuleContext) OtherModuleProvider(logicModule Module, provider ProviderKey) interface{} {
|
||||||
|
module := m.context.moduleInfo[logicModule]
|
||||||
|
value, _ := m.context.provider(module, provider)
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *baseModuleContext) OtherModuleHasProvider(logicModule Module, provider ProviderKey) bool {
|
||||||
|
module := m.context.moduleInfo[logicModule]
|
||||||
|
_, ok := m.context.provider(module, provider)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *baseModuleContext) Provider(provider ProviderKey) interface{} {
|
||||||
|
value, _ := m.context.provider(m.module, provider)
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *baseModuleContext) HasProvider(provider ProviderKey) bool {
|
||||||
|
_, ok := m.context.provider(m.module, provider)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *baseModuleContext) SetProvider(provider ProviderKey, value interface{}) {
|
||||||
|
m.context.setProvider(m.module, provider, value)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *baseModuleContext) GetDirectDep(name string) (Module, DependencyTag) {
|
func (m *baseModuleContext) GetDirectDep(name string) (Module, DependencyTag) {
|
||||||
for _, dep := range m.module.directDeps {
|
for _, dep := range m.module.directDeps {
|
||||||
if dep.module.Name() == name {
|
if dep.module.Name() == name {
|
||||||
|
@ -882,6 +933,14 @@ type BottomUpMutatorContext interface {
|
||||||
// be used to add dependencies on the toVariationName variant using the fromVariationName
|
// be used to add dependencies on the toVariationName variant using the fromVariationName
|
||||||
// variant.
|
// variant.
|
||||||
CreateAliasVariation(fromVariationName, toVariationName string)
|
CreateAliasVariation(fromVariationName, toVariationName string)
|
||||||
|
|
||||||
|
// SetVariationProvider sets the value for a provider for the given newly created variant of
|
||||||
|
// the current module, i.e. one of the Modules returned by CreateVariations.. It panics if
|
||||||
|
// not called during the appropriate mutator or GenerateBuildActions pass for the provider,
|
||||||
|
// if the value is not of the appropriate type, or if the module is not a newly created
|
||||||
|
// variant of the current module. The value should not be modified after being passed to
|
||||||
|
// SetVariationProvider.
|
||||||
|
SetVariationProvider(module Module, provider ProviderKey, value interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Mutator function is called for each Module, and can use
|
// A Mutator function is called for each Module, and can use
|
||||||
|
@ -925,6 +984,16 @@ func (mctx *mutatorContext) CreateLocalVariations(variationNames ...string) []Mo
|
||||||
return mctx.createVariations(variationNames, true)
|
return mctx.createVariations(variationNames, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mctx *mutatorContext) SetVariationProvider(module Module, provider ProviderKey, value interface{}) {
|
||||||
|
for _, variant := range mctx.newVariations {
|
||||||
|
if m := variant.module(); m != nil && m.logicModule == module {
|
||||||
|
mctx.context.setProvider(m, provider, value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic(fmt.Errorf("module %q is not a newly created variant of %q", module, mctx.module))
|
||||||
|
}
|
||||||
|
|
||||||
type pendingAlias struct {
|
type pendingAlias struct {
|
||||||
fromVariant variant
|
fromVariant variant
|
||||||
target *moduleInfo
|
target *moduleInfo
|
||||||
|
|
216
provider.go
Normal file
216
provider.go
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
// Copyright 2020 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package blueprint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This file implements Providers, modelled after Bazel
|
||||||
|
// (https://docs.bazel.build/versions/master/skylark/rules.html#providers).
|
||||||
|
// Each provider can be associated with a mutator, in which case the value for the provider for a
|
||||||
|
// module can only be set during the mutator call for the module, and the value can only be
|
||||||
|
// retrieved after the mutator call for the module. For providers not associated with a mutator, the
|
||||||
|
// value can for the provider for a module can only be set during GenerateBuildActions for the
|
||||||
|
// module, and the value can only be retrieved after GenerateBuildActions for the module.
|
||||||
|
//
|
||||||
|
// Providers are globally registered during init() and given a unique ID. The value of a provider
|
||||||
|
// for a module is stored in an []interface{} indexed by the ID. If the value of a provider has
|
||||||
|
// not been set, the value in the []interface{} will be nil.
|
||||||
|
//
|
||||||
|
// If the storage used by the provider value arrays becomes too large:
|
||||||
|
// sizeof([]interface) * number of providers * number of modules that have a provider value set
|
||||||
|
// then the storage can be replaced with something like a bitwise trie.
|
||||||
|
//
|
||||||
|
// The purpose of providers is to provide a serializable checkpoint between modules to enable
|
||||||
|
// Blueprint to skip parts of the analysis phase when inputs haven't changed. To that end,
|
||||||
|
// values passed to providers should be treated as immutable by callers to both the getters and
|
||||||
|
// setters. Go doesn't provide any way to enforce immutability on arbitrary types, so it may be
|
||||||
|
// necessary for the getters and setters to make deep copies of the values, likely extending
|
||||||
|
// proptools.CloneProperties to do so.
|
||||||
|
|
||||||
|
type provider struct {
|
||||||
|
id int
|
||||||
|
typ reflect.Type
|
||||||
|
zero interface{}
|
||||||
|
mutator string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProviderKey *provider
|
||||||
|
|
||||||
|
var providerRegistry []ProviderKey
|
||||||
|
|
||||||
|
// NewProvider returns a ProviderKey for the type of the given example value. The example value
|
||||||
|
// is otherwise unused.
|
||||||
|
//
|
||||||
|
// The returned ProviderKey can be used to set a value of the ProviderKey's type for a module
|
||||||
|
// inside GenerateBuildActions for the module, and to get the value from GenerateBuildActions from
|
||||||
|
// any module later in the build graph.
|
||||||
|
//
|
||||||
|
// Once Go has generics the exampleValue parameter will not be necessary:
|
||||||
|
// NewProvider(type T)() ProviderKey(T)
|
||||||
|
func NewProvider(exampleValue interface{}) ProviderKey {
|
||||||
|
return NewMutatorProvider(exampleValue, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMutatorProvider returns a ProviderKey for the type of the given example value. The example
|
||||||
|
// value is otherwise unused.
|
||||||
|
//
|
||||||
|
// The returned ProviderKey can be used to set a value of the ProviderKey's type for a module inside
|
||||||
|
// the given mutator for the module, and to get the value from GenerateBuildActions from any
|
||||||
|
// module later in the build graph in the same mutator, or any module in a later mutator or during
|
||||||
|
// GenerateBuildActions.
|
||||||
|
//
|
||||||
|
// Once Go has generics the exampleValue parameter will not be necessary:
|
||||||
|
// NewMutatorProvider(type T)(mutator string) ProviderKey(T)
|
||||||
|
func NewMutatorProvider(exampleValue interface{}, mutator string) ProviderKey {
|
||||||
|
checkCalledFromInit()
|
||||||
|
|
||||||
|
typ := reflect.TypeOf(exampleValue)
|
||||||
|
zero := reflect.Zero(typ).Interface()
|
||||||
|
|
||||||
|
provider := &provider{
|
||||||
|
id: len(providerRegistry),
|
||||||
|
typ: typ,
|
||||||
|
zero: zero,
|
||||||
|
mutator: mutator,
|
||||||
|
}
|
||||||
|
|
||||||
|
providerRegistry = append(providerRegistry, provider)
|
||||||
|
|
||||||
|
return provider
|
||||||
|
}
|
||||||
|
|
||||||
|
// initProviders fills c.providerMutators with the *mutatorInfo associated with each provider ID,
|
||||||
|
// if any.
|
||||||
|
func (c *Context) initProviders() {
|
||||||
|
c.providerMutators = make([]*mutatorInfo, len(providerRegistry))
|
||||||
|
for _, provider := range providerRegistry {
|
||||||
|
for _, mutator := range c.mutatorInfo {
|
||||||
|
if mutator.name == provider.mutator {
|
||||||
|
c.providerMutators[provider.id] = mutator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setProvider sets the value for a provider on a moduleInfo. Verifies that it is called during the
|
||||||
|
// appropriate mutator or GenerateBuildActions pass for the provider, and that the value is of the
|
||||||
|
// appropriate type. The value should not be modified after being passed to setProvider.
|
||||||
|
//
|
||||||
|
// Once Go has generics the value parameter can be typed:
|
||||||
|
// setProvider(type T)(m *moduleInfo, provider ProviderKey(T), value T)
|
||||||
|
func (c *Context) setProvider(m *moduleInfo, provider ProviderKey, value interface{}) {
|
||||||
|
if provider.mutator == "" {
|
||||||
|
if !m.startedGenerateBuildActions {
|
||||||
|
panic(fmt.Sprintf("Can't set value of provider %s before GenerateBuildActions started",
|
||||||
|
provider.typ))
|
||||||
|
} else if m.finishedGenerateBuildActions {
|
||||||
|
panic(fmt.Sprintf("Can't set value of provider %s after GenerateBuildActions finished",
|
||||||
|
provider.typ))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
expectedMutator := c.providerMutators[provider.id]
|
||||||
|
if expectedMutator == nil {
|
||||||
|
panic(fmt.Sprintf("Can't set value of provider %s associated with unregistered mutator %s",
|
||||||
|
provider.typ, provider.mutator))
|
||||||
|
} else if c.mutatorFinishedForModule(expectedMutator, m) {
|
||||||
|
panic(fmt.Sprintf("Can't set value of provider %s after mutator %s finished",
|
||||||
|
provider.typ, provider.mutator))
|
||||||
|
} else if !c.mutatorStartedForModule(expectedMutator, m) {
|
||||||
|
panic(fmt.Sprintf("Can't set value of provider %s before mutator %s started",
|
||||||
|
provider.typ, provider.mutator))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if typ := reflect.TypeOf(value); typ != provider.typ {
|
||||||
|
panic(fmt.Sprintf("Value for provider has incorrect type, wanted %s, got %s",
|
||||||
|
provider.typ, typ))
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.providers == nil {
|
||||||
|
m.providers = make([]interface{}, len(providerRegistry))
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.providers[provider.id] != nil {
|
||||||
|
panic(fmt.Sprintf("Value of provider %s is already set", provider.typ))
|
||||||
|
}
|
||||||
|
|
||||||
|
m.providers[provider.id] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// provider returns the value, if any, for a given provider for a module. Verifies that it is
|
||||||
|
// called after the appropriate mutator or GenerateBuildActions pass for the provider on the module.
|
||||||
|
// If the value for the provider was not set it returns the zero value of the type of the provider,
|
||||||
|
// which means the return value can always be type-asserted to the type of the provider. The return
|
||||||
|
// value should always be considered read-only.
|
||||||
|
//
|
||||||
|
// Once Go has generics the return value can be typed and the type assert by callers can be dropped:
|
||||||
|
// provider(type T)(m *moduleInfo, provider ProviderKey(T)) T
|
||||||
|
func (c *Context) provider(m *moduleInfo, provider ProviderKey) (interface{}, bool) {
|
||||||
|
if provider.mutator == "" {
|
||||||
|
if !m.finishedGenerateBuildActions {
|
||||||
|
panic(fmt.Sprintf("Can't get value of provider %s before GenerateBuildActions finished",
|
||||||
|
provider.typ))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
expectedMutator := c.providerMutators[provider.id]
|
||||||
|
if expectedMutator != nil && !c.mutatorFinishedForModule(expectedMutator, m) {
|
||||||
|
panic(fmt.Sprintf("Can't get value of provider %s before mutator %s finished",
|
||||||
|
provider.typ, provider.mutator))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(m.providers) > provider.id {
|
||||||
|
if p := m.providers[provider.id]; p != nil {
|
||||||
|
return p, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider.zero, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) mutatorFinishedForModule(mutator *mutatorInfo, m *moduleInfo) bool {
|
||||||
|
if c.finishedMutators[mutator] {
|
||||||
|
// mutator pass finished for all modules
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.startedMutator == mutator {
|
||||||
|
// mutator pass started, check if it is finished for this module
|
||||||
|
return m.finishedMutator == mutator
|
||||||
|
}
|
||||||
|
|
||||||
|
// mutator pass hasn't started
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) mutatorStartedForModule(mutator *mutatorInfo, m *moduleInfo) bool {
|
||||||
|
if c.finishedMutators[mutator] {
|
||||||
|
// mutator pass finished for all modules
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.startedMutator == mutator {
|
||||||
|
// mutator pass is currently running
|
||||||
|
if m.startedMutator == mutator {
|
||||||
|
// mutator has started for this module
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
420
provider_test.go
Normal file
420
provider_test.go
Normal file
|
@ -0,0 +1,420 @@
|
||||||
|
// Copyright 2020 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package blueprint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type providerTestModule struct {
|
||||||
|
SimpleName
|
||||||
|
properties struct {
|
||||||
|
Deps []string
|
||||||
|
}
|
||||||
|
|
||||||
|
mutatorProviderValues []string
|
||||||
|
generateBuildActionsProviderValues []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newProviderTestModule() (Module, []interface{}) {
|
||||||
|
m := &providerTestModule{}
|
||||||
|
return m, []interface{}{&m.properties, &m.SimpleName.Properties}
|
||||||
|
}
|
||||||
|
|
||||||
|
type providerTestMutatorInfo struct {
|
||||||
|
Values []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type providerTestGenerateBuildActionsInfo struct {
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type providerTestUnsetInfo string
|
||||||
|
|
||||||
|
var providerTestMutatorInfoProvider = NewMutatorProvider(&providerTestMutatorInfo{}, "provider_mutator")
|
||||||
|
var providerTestGenerateBuildActionsInfoProvider = NewProvider(&providerTestGenerateBuildActionsInfo{})
|
||||||
|
var providerTestUnsetInfoProvider = NewMutatorProvider((providerTestUnsetInfo)(""), "provider_mutator")
|
||||||
|
var providerTestUnusedMutatorProvider = NewMutatorProvider(&struct{ unused string }{}, "nonexistent_mutator")
|
||||||
|
|
||||||
|
func (p *providerTestModule) GenerateBuildActions(ctx ModuleContext) {
|
||||||
|
unset := ctx.Provider(providerTestUnsetInfoProvider).(providerTestUnsetInfo)
|
||||||
|
if unset != "" {
|
||||||
|
panic(fmt.Sprintf("expected zero value for providerTestGenerateBuildActionsInfoProvider before it was set, got %q",
|
||||||
|
unset))
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = ctx.Provider(providerTestUnusedMutatorProvider)
|
||||||
|
|
||||||
|
ctx.SetProvider(providerTestGenerateBuildActionsInfoProvider, &providerTestGenerateBuildActionsInfo{
|
||||||
|
Value: ctx.ModuleName(),
|
||||||
|
})
|
||||||
|
|
||||||
|
mp := ctx.Provider(providerTestMutatorInfoProvider).(*providerTestMutatorInfo)
|
||||||
|
if mp != nil {
|
||||||
|
p.mutatorProviderValues = mp.Values
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.VisitDirectDeps(func(module Module) {
|
||||||
|
gbap := ctx.OtherModuleProvider(module, providerTestGenerateBuildActionsInfoProvider).(*providerTestGenerateBuildActionsInfo)
|
||||||
|
if gbap != nil {
|
||||||
|
p.generateBuildActionsProviderValues = append(p.generateBuildActionsProviderValues, gbap.Value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func providerTestDepsMutator(ctx BottomUpMutatorContext) {
|
||||||
|
if p, ok := ctx.Module().(*providerTestModule); ok {
|
||||||
|
ctx.AddDependency(ctx.Module(), nil, p.properties.Deps...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func providerTestMutator(ctx BottomUpMutatorContext) {
|
||||||
|
values := []string{strings.ToLower(ctx.ModuleName())}
|
||||||
|
|
||||||
|
ctx.VisitDirectDeps(func(module Module) {
|
||||||
|
mp := ctx.OtherModuleProvider(module, providerTestMutatorInfoProvider).(*providerTestMutatorInfo)
|
||||||
|
if mp != nil {
|
||||||
|
values = append(values, mp.Values...)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.SetProvider(providerTestMutatorInfoProvider, &providerTestMutatorInfo{
|
||||||
|
Values: values,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func providerTestAfterMutator(ctx BottomUpMutatorContext) {
|
||||||
|
_ = ctx.Provider(providerTestMutatorInfoProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProviders(t *testing.T) {
|
||||||
|
ctx := NewContext()
|
||||||
|
ctx.RegisterModuleType("provider_module", newProviderTestModule)
|
||||||
|
ctx.RegisterBottomUpMutator("provider_deps_mutator", providerTestDepsMutator)
|
||||||
|
ctx.RegisterBottomUpMutator("provider_mutator", providerTestMutator)
|
||||||
|
ctx.RegisterBottomUpMutator("provider_after_mutator", providerTestAfterMutator)
|
||||||
|
|
||||||
|
ctx.MockFileSystem(map[string][]byte{
|
||||||
|
"Blueprints": []byte(`
|
||||||
|
provider_module {
|
||||||
|
name: "A",
|
||||||
|
deps: ["B"],
|
||||||
|
}
|
||||||
|
|
||||||
|
provider_module {
|
||||||
|
name: "B",
|
||||||
|
deps: ["C", "D"],
|
||||||
|
}
|
||||||
|
|
||||||
|
provider_module {
|
||||||
|
name: "C",
|
||||||
|
deps: ["D"],
|
||||||
|
}
|
||||||
|
|
||||||
|
provider_module {
|
||||||
|
name: "D",
|
||||||
|
}
|
||||||
|
`),
|
||||||
|
})
|
||||||
|
|
||||||
|
_, errs := ctx.ParseBlueprintsFiles("Blueprints", nil)
|
||||||
|
if len(errs) == 0 {
|
||||||
|
_, errs = ctx.ResolveDependencies(nil)
|
||||||
|
}
|
||||||
|
if len(errs) == 0 {
|
||||||
|
_, errs = ctx.PrepareBuildActions(nil)
|
||||||
|
}
|
||||||
|
if len(errs) > 0 {
|
||||||
|
t.Errorf("unexpected errors:")
|
||||||
|
for _, err := range errs {
|
||||||
|
t.Errorf(" %s", err)
|
||||||
|
}
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
aModule := ctx.moduleGroupFromName("A", nil).moduleByVariantName("").logicModule.(*providerTestModule)
|
||||||
|
if g, w := aModule.generateBuildActionsProviderValues, []string{"B"}; !reflect.DeepEqual(g, w) {
|
||||||
|
t.Errorf("expected A.generateBuildActionsProviderValues %q, got %q", w, g)
|
||||||
|
}
|
||||||
|
if g, w := aModule.mutatorProviderValues, []string{"a", "b", "c", "d", "d"}; !reflect.DeepEqual(g, w) {
|
||||||
|
t.Errorf("expected A.mutatorProviderValues %q, got %q", w, g)
|
||||||
|
}
|
||||||
|
|
||||||
|
bModule := ctx.moduleGroupFromName("B", nil).moduleByVariantName("").logicModule.(*providerTestModule)
|
||||||
|
if g, w := bModule.generateBuildActionsProviderValues, []string{"C", "D"}; !reflect.DeepEqual(g, w) {
|
||||||
|
t.Errorf("expected B.generateBuildActionsProviderValues %q, got %q", w, g)
|
||||||
|
}
|
||||||
|
if g, w := bModule.mutatorProviderValues, []string{"b", "c", "d", "d"}; !reflect.DeepEqual(g, w) {
|
||||||
|
t.Errorf("expected B.mutatorProviderValues %q, got %q", w, g)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type invalidProviderUsageMutatorInfo string
|
||||||
|
type invalidProviderUsageGenerateBuildActionsInfo string
|
||||||
|
|
||||||
|
var invalidProviderUsageMutatorInfoProvider = NewMutatorProvider(invalidProviderUsageMutatorInfo(""), "mutator_under_test")
|
||||||
|
var invalidProviderUsageGenerateBuildActionsInfoProvider = NewProvider(invalidProviderUsageGenerateBuildActionsInfo(""))
|
||||||
|
|
||||||
|
type invalidProviderUsageTestModule struct {
|
||||||
|
parent *invalidProviderUsageTestModule
|
||||||
|
|
||||||
|
SimpleName
|
||||||
|
properties struct {
|
||||||
|
Deps []string
|
||||||
|
|
||||||
|
Early_mutator_set_of_mutator_provider bool
|
||||||
|
Late_mutator_set_of_mutator_provider bool
|
||||||
|
Late_build_actions_set_of_mutator_provider bool
|
||||||
|
Early_mutator_set_of_build_actions_provider bool
|
||||||
|
|
||||||
|
Early_mutator_get_of_mutator_provider bool
|
||||||
|
Early_module_get_of_mutator_provider bool
|
||||||
|
Early_mutator_get_of_build_actions_provider bool
|
||||||
|
Early_module_get_of_build_actions_provider bool
|
||||||
|
|
||||||
|
Duplicate_set bool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func invalidProviderUsageDepsMutator(ctx BottomUpMutatorContext) {
|
||||||
|
if i, ok := ctx.Module().(*invalidProviderUsageTestModule); ok {
|
||||||
|
ctx.AddDependency(ctx.Module(), nil, i.properties.Deps...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func invalidProviderUsageParentMutator(ctx TopDownMutatorContext) {
|
||||||
|
if i, ok := ctx.Module().(*invalidProviderUsageTestModule); ok {
|
||||||
|
ctx.VisitDirectDeps(func(module Module) {
|
||||||
|
module.(*invalidProviderUsageTestModule).parent = i
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func invalidProviderUsageBeforeMutator(ctx BottomUpMutatorContext) {
|
||||||
|
if i, ok := ctx.Module().(*invalidProviderUsageTestModule); ok {
|
||||||
|
if i.properties.Early_mutator_set_of_mutator_provider {
|
||||||
|
// A mutator attempting to set the value of a provider associated with a later mutator.
|
||||||
|
ctx.SetProvider(invalidProviderUsageMutatorInfoProvider, invalidProviderUsageMutatorInfo(""))
|
||||||
|
}
|
||||||
|
if i.properties.Early_mutator_get_of_mutator_provider {
|
||||||
|
// A mutator attempting to get the value of a provider associated with a later mutator.
|
||||||
|
_ = ctx.Provider(invalidProviderUsageMutatorInfoProvider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func invalidProviderUsageMutatorUnderTest(ctx TopDownMutatorContext) {
|
||||||
|
if i, ok := ctx.Module().(*invalidProviderUsageTestModule); ok {
|
||||||
|
if i.properties.Early_mutator_set_of_build_actions_provider {
|
||||||
|
// A mutator attempting to set the value of a non-mutator provider.
|
||||||
|
ctx.SetProvider(invalidProviderUsageGenerateBuildActionsInfoProvider, invalidProviderUsageGenerateBuildActionsInfo(""))
|
||||||
|
}
|
||||||
|
if i.properties.Early_mutator_get_of_build_actions_provider {
|
||||||
|
// A mutator attempting to get the value of a non-mutator provider.
|
||||||
|
_ = ctx.Provider(invalidProviderUsageGenerateBuildActionsInfoProvider)
|
||||||
|
}
|
||||||
|
if i.properties.Early_module_get_of_mutator_provider {
|
||||||
|
// A mutator attempting to get the value of a provider associated with this mutator on
|
||||||
|
// a module for which this mutator hasn't run. This is a top down mutator so
|
||||||
|
// dependencies haven't run yet.
|
||||||
|
ctx.VisitDirectDeps(func(module Module) {
|
||||||
|
_ = ctx.OtherModuleProvider(module, invalidProviderUsageMutatorInfoProvider)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func invalidProviderUsageAfterMutator(ctx BottomUpMutatorContext) {
|
||||||
|
if i, ok := ctx.Module().(*invalidProviderUsageTestModule); ok {
|
||||||
|
if i.properties.Late_mutator_set_of_mutator_provider {
|
||||||
|
// A mutator trying to set the value of a provider associated with an earlier mutator.
|
||||||
|
ctx.SetProvider(invalidProviderUsageMutatorInfoProvider, invalidProviderUsageMutatorInfo(""))
|
||||||
|
}
|
||||||
|
if i.properties.Late_mutator_set_of_mutator_provider {
|
||||||
|
// A mutator trying to set the value of a provider associated with an earlier mutator.
|
||||||
|
ctx.SetProvider(invalidProviderUsageMutatorInfoProvider, invalidProviderUsageMutatorInfo(""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *invalidProviderUsageTestModule) GenerateBuildActions(ctx ModuleContext) {
|
||||||
|
if i.properties.Late_build_actions_set_of_mutator_provider {
|
||||||
|
// A GenerateBuildActions trying to set the value of a provider associated with a mutator.
|
||||||
|
ctx.SetProvider(invalidProviderUsageMutatorInfoProvider, invalidProviderUsageMutatorInfo(""))
|
||||||
|
}
|
||||||
|
if i.properties.Early_module_get_of_build_actions_provider {
|
||||||
|
// A GenerateBuildActions trying to get the value of a provider on a module for which
|
||||||
|
// GenerateBuildActions hasn't run.
|
||||||
|
_ = ctx.OtherModuleProvider(i.parent, invalidProviderUsageGenerateBuildActionsInfoProvider)
|
||||||
|
}
|
||||||
|
if i.properties.Duplicate_set {
|
||||||
|
ctx.SetProvider(invalidProviderUsageGenerateBuildActionsInfoProvider, invalidProviderUsageGenerateBuildActionsInfo(""))
|
||||||
|
ctx.SetProvider(invalidProviderUsageGenerateBuildActionsInfoProvider, invalidProviderUsageGenerateBuildActionsInfo(""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvalidProvidersUsage(t *testing.T) {
|
||||||
|
run := func(t *testing.T, module string, prop string, panicMsg string) {
|
||||||
|
t.Helper()
|
||||||
|
ctx := NewContext()
|
||||||
|
ctx.RegisterModuleType("invalid_provider_usage_test_module", func() (Module, []interface{}) {
|
||||||
|
m := &invalidProviderUsageTestModule{}
|
||||||
|
return m, []interface{}{&m.properties, &m.SimpleName.Properties}
|
||||||
|
})
|
||||||
|
ctx.RegisterBottomUpMutator("deps", invalidProviderUsageDepsMutator)
|
||||||
|
ctx.RegisterBottomUpMutator("before", invalidProviderUsageBeforeMutator)
|
||||||
|
ctx.RegisterTopDownMutator("mutator_under_test", invalidProviderUsageMutatorUnderTest)
|
||||||
|
ctx.RegisterBottomUpMutator("after", invalidProviderUsageAfterMutator)
|
||||||
|
ctx.RegisterTopDownMutator("parent", invalidProviderUsageParentMutator)
|
||||||
|
|
||||||
|
// Don't invalidate the parent pointer and before GenerateBuildActions.
|
||||||
|
ctx.skipCloneModulesAfterMutators = true
|
||||||
|
|
||||||
|
var parentBP, moduleUnderTestBP, childBP string
|
||||||
|
|
||||||
|
prop += ": true,"
|
||||||
|
|
||||||
|
switch module {
|
||||||
|
case "parent":
|
||||||
|
parentBP = prop
|
||||||
|
case "module_under_test":
|
||||||
|
moduleUnderTestBP = prop
|
||||||
|
case "child":
|
||||||
|
childBP = prop
|
||||||
|
}
|
||||||
|
|
||||||
|
bp := fmt.Sprintf(`
|
||||||
|
invalid_provider_usage_test_module {
|
||||||
|
name: "parent",
|
||||||
|
deps: ["module_under_test"],
|
||||||
|
%s
|
||||||
|
}
|
||||||
|
|
||||||
|
invalid_provider_usage_test_module {
|
||||||
|
name: "module_under_test",
|
||||||
|
deps: ["child"],
|
||||||
|
%s
|
||||||
|
}
|
||||||
|
|
||||||
|
invalid_provider_usage_test_module {
|
||||||
|
name: "child",
|
||||||
|
%s
|
||||||
|
}
|
||||||
|
|
||||||
|
`,
|
||||||
|
parentBP,
|
||||||
|
moduleUnderTestBP,
|
||||||
|
childBP)
|
||||||
|
|
||||||
|
ctx.MockFileSystem(map[string][]byte{
|
||||||
|
"Blueprints": []byte(bp),
|
||||||
|
})
|
||||||
|
|
||||||
|
_, errs := ctx.ParseBlueprintsFiles("Blueprints", nil)
|
||||||
|
|
||||||
|
if len(errs) == 0 {
|
||||||
|
_, errs = ctx.ResolveDependencies(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errs) == 0 {
|
||||||
|
_, errs = ctx.PrepareBuildActions(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errs) == 0 {
|
||||||
|
t.Fatal("expected an error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errs) > 1 {
|
||||||
|
t.Errorf("expected a single error, got %d:", len(errs))
|
||||||
|
for i, err := range errs {
|
||||||
|
t.Errorf("%d: %s", i, err)
|
||||||
|
}
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
if panicErr, ok := errs[0].(panicError); ok {
|
||||||
|
if panicErr.panic != panicMsg {
|
||||||
|
t.Fatalf("expected panic %q, got %q", panicMsg, panicErr.panic)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Fatalf("expected a panicError, got %T: %s", errs[0], errs[0].Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
prop string
|
||||||
|
module string
|
||||||
|
|
||||||
|
panicMsg string
|
||||||
|
skip string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
prop: "early_mutator_set_of_mutator_provider",
|
||||||
|
module: "module_under_test",
|
||||||
|
panicMsg: "Can't set value of provider blueprint.invalidProviderUsageMutatorInfo before mutator mutator_under_test started",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "late_mutator_set_of_mutator_provider",
|
||||||
|
module: "module_under_test",
|
||||||
|
panicMsg: "Can't set value of provider blueprint.invalidProviderUsageMutatorInfo after mutator mutator_under_test finished",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "late_build_actions_set_of_mutator_provider",
|
||||||
|
module: "module_under_test",
|
||||||
|
panicMsg: "Can't set value of provider blueprint.invalidProviderUsageMutatorInfo after mutator mutator_under_test finished",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "early_mutator_set_of_build_actions_provider",
|
||||||
|
module: "module_under_test",
|
||||||
|
panicMsg: "Can't set value of provider blueprint.invalidProviderUsageGenerateBuildActionsInfo before GenerateBuildActions started",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
prop: "early_mutator_get_of_mutator_provider",
|
||||||
|
module: "module_under_test",
|
||||||
|
panicMsg: "Can't get value of provider blueprint.invalidProviderUsageMutatorInfo before mutator mutator_under_test finished",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "early_module_get_of_mutator_provider",
|
||||||
|
module: "module_under_test",
|
||||||
|
panicMsg: "Can't get value of provider blueprint.invalidProviderUsageMutatorInfo before mutator mutator_under_test finished",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "early_mutator_get_of_build_actions_provider",
|
||||||
|
module: "module_under_test",
|
||||||
|
panicMsg: "Can't get value of provider blueprint.invalidProviderUsageGenerateBuildActionsInfo before GenerateBuildActions finished",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "early_module_get_of_build_actions_provider",
|
||||||
|
module: "module_under_test",
|
||||||
|
panicMsg: "Can't get value of provider blueprint.invalidProviderUsageGenerateBuildActionsInfo before GenerateBuildActions finished",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "duplicate_set",
|
||||||
|
module: "module_under_test",
|
||||||
|
panicMsg: "Value of provider blueprint.invalidProviderUsageGenerateBuildActionsInfo is already set",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.prop, func(t *testing.T) {
|
||||||
|
run(t, tt.module, tt.prop, tt.panicMsg)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,6 +47,16 @@ type SingletonContext interface {
|
||||||
// BlueprintFile returns the path of the Blueprint file that defined the given module.
|
// BlueprintFile returns the path of the Blueprint file that defined the given module.
|
||||||
BlueprintFile(module Module) string
|
BlueprintFile(module Module) string
|
||||||
|
|
||||||
|
// ModuleProvider returns the value, if any, for the provider for a module. If the value for the
|
||||||
|
// provider was not set it returns the zero value of the type of the provider, which means the
|
||||||
|
// return value can always be type-asserted to the type of the provider. The return value should
|
||||||
|
// always be considered read-only. It panics if called before the appropriate mutator or
|
||||||
|
// GenerateBuildActions pass for the provider on the module.
|
||||||
|
ModuleProvider(module Module, provider ProviderKey) interface{}
|
||||||
|
|
||||||
|
// ModuleHasProvider returns true if the provider for the given module has been set.
|
||||||
|
ModuleHasProvider(m Module, provider ProviderKey) bool
|
||||||
|
|
||||||
// ModuleErrorf reports an error at the line number of the module type in the module definition.
|
// ModuleErrorf reports an error at the line number of the module type in the module definition.
|
||||||
ModuleErrorf(module Module, format string, args ...interface{})
|
ModuleErrorf(module Module, format string, args ...interface{})
|
||||||
|
|
||||||
|
@ -188,6 +198,15 @@ func (s *singletonContext) ModuleType(logicModule Module) string {
|
||||||
return s.context.ModuleType(logicModule)
|
return s.context.ModuleType(logicModule)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *singletonContext) ModuleProvider(logicModule Module, provider ProviderKey) interface{} {
|
||||||
|
return s.context.ModuleProvider(logicModule, provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModuleHasProvider returns true if the provider for the given module has been set.
|
||||||
|
func (s *singletonContext) ModuleHasProvider(logicModule Module, provider ProviderKey) bool {
|
||||||
|
return s.context.ModuleHasProvider(logicModule, provider)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *singletonContext) BlueprintFile(logicModule Module) string {
|
func (s *singletonContext) BlueprintFile(logicModule Module) string {
|
||||||
return s.context.BlueprintFile(logicModule)
|
return s.context.BlueprintFile(logicModule)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue