Call TransitionMutator.IncomingTransition when adding dependencies later
Adding a dependency on a module that has already had a TransitionMutator run on it may require adjusting the variation name based on the results of IncomingTranstion. Store the variants that existed before the TransitionMutator ran, find one that is a subset of the requested variant, and call TranstionMutator.IncomingTransition to update the value. Bug: 319288033 Test: TestPostTransitionDeps Change-Id: I690357f9792401a3edbc5ae9fdcb666495954fbc
This commit is contained in:
parent
6ed94b7f85
commit
d7474dd743
5 changed files with 279 additions and 114 deletions
84
context.go
84
context.go
|
@ -91,6 +91,8 @@ type Context struct {
|
||||||
mutatorInfo []*mutatorInfo
|
mutatorInfo []*mutatorInfo
|
||||||
variantMutatorNames []string
|
variantMutatorNames []string
|
||||||
|
|
||||||
|
transitionMutators []*transitionMutatorImpl
|
||||||
|
|
||||||
depsModified uint32 // positive if a mutator modified the dependencies
|
depsModified uint32 // positive if a mutator modified the dependencies
|
||||||
|
|
||||||
dependenciesReady bool // set to true on a successful ResolveDependencies
|
dependenciesReady bool // set to true on a successful ResolveDependencies
|
||||||
|
@ -459,6 +461,7 @@ type mutatorInfo struct {
|
||||||
bottomUpMutator BottomUpMutator
|
bottomUpMutator BottomUpMutator
|
||||||
name string
|
name string
|
||||||
parallel bool
|
parallel bool
|
||||||
|
transitionMutator *transitionMutatorImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
func newContext() *Context {
|
func newContext() *Context {
|
||||||
|
@ -686,6 +689,8 @@ type MutatorHandle interface {
|
||||||
// method on the mutator context is thread-safe, but the mutator must handle synchronization
|
// method on the mutator context is thread-safe, but the mutator must handle synchronization
|
||||||
// for any modifications to global state or any modules outside the one it was invoked on.
|
// for any modifications to global state or any modules outside the one it was invoked on.
|
||||||
Parallel() MutatorHandle
|
Parallel() MutatorHandle
|
||||||
|
|
||||||
|
setTransitionMutator(impl *transitionMutatorImpl) MutatorHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mutator *mutatorInfo) Parallel() MutatorHandle {
|
func (mutator *mutatorInfo) Parallel() MutatorHandle {
|
||||||
|
@ -693,6 +698,11 @@ func (mutator *mutatorInfo) Parallel() MutatorHandle {
|
||||||
return mutator
|
return mutator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mutator *mutatorInfo) setTransitionMutator(impl *transitionMutatorImpl) MutatorHandle {
|
||||||
|
mutator.transitionMutator = impl
|
||||||
|
return mutator
|
||||||
|
}
|
||||||
|
|
||||||
// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
|
// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
|
||||||
// where it encounters an unknown module type while parsing Blueprints files. By
|
// where it encounters an unknown module type while parsing Blueprints files. By
|
||||||
// default, the context will report unknown module types as an error. If this
|
// default, the context will report unknown module types as an error. If this
|
||||||
|
@ -1489,7 +1499,7 @@ func (c *Context) createVariations(origModule *moduleInfo, mutator *mutatorInfo,
|
||||||
var newLogicModule Module
|
var newLogicModule Module
|
||||||
var newProperties []interface{}
|
var newProperties []interface{}
|
||||||
|
|
||||||
if i == 0 {
|
if i == 0 && mutator.transitionMutator == nil {
|
||||||
// Reuse the existing module for the first new variant
|
// Reuse the existing module for the first new variant
|
||||||
// This both saves creating a new module, and causes the insertion in c.moduleInfo below
|
// This both saves creating a new module, and causes the insertion in c.moduleInfo below
|
||||||
// with logicModule as the key to replace the original entry in c.moduleInfo
|
// with logicModule as the key to replace the original entry in c.moduleInfo
|
||||||
|
@ -1736,6 +1746,8 @@ func (c *Context) resolveDependencies(ctx context.Context, config interface{}) (
|
||||||
}
|
}
|
||||||
defer c.EndEvent("clone_modules")
|
defer c.EndEvent("clone_modules")
|
||||||
|
|
||||||
|
c.clearTransitionMutatorInputVariants()
|
||||||
|
|
||||||
c.dependenciesReady = true
|
c.dependenciesReady = true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1772,8 +1784,8 @@ func blueprintDepsMutator(ctx BottomUpMutatorContext) {
|
||||||
// findExactVariantOrSingle searches the moduleGroup for a module with the same variant as module,
|
// findExactVariantOrSingle searches the moduleGroup for a module with the same variant as module,
|
||||||
// and returns the matching module, or nil if one is not found. A group with exactly one module
|
// and returns the matching module, or nil if one is not found. A group with exactly one module
|
||||||
// is always considered matching.
|
// is always considered matching.
|
||||||
func findExactVariantOrSingle(module *moduleInfo, possible *moduleGroup, reverse bool) *moduleInfo {
|
func (c *Context) findExactVariantOrSingle(module *moduleInfo, config any, possible *moduleGroup, reverse bool) *moduleInfo {
|
||||||
found, _ := findVariant(module, possible, nil, false, reverse)
|
found, _ := c.findVariant(module, config, possible, nil, false, reverse)
|
||||||
if found == nil {
|
if found == nil {
|
||||||
for _, moduleOrAlias := range possible.modules {
|
for _, moduleOrAlias := range possible.modules {
|
||||||
if m := moduleOrAlias.module(); m != nil {
|
if m := moduleOrAlias.module(); m != nil {
|
||||||
|
@ -1788,7 +1800,7 @@ func findExactVariantOrSingle(module *moduleInfo, possible *moduleGroup, reverse
|
||||||
return found
|
return found
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName string) (*moduleInfo, []error) {
|
func (c *Context) addDependency(module *moduleInfo, config any, tag DependencyTag, depName string) (*moduleInfo, []error) {
|
||||||
if _, ok := tag.(BaseDependencyTag); ok {
|
if _, ok := tag.(BaseDependencyTag); ok {
|
||||||
panic("BaseDependencyTag is not allowed to be used directly!")
|
panic("BaseDependencyTag is not allowed to be used directly!")
|
||||||
}
|
}
|
||||||
|
@ -1805,7 +1817,7 @@ func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName s
|
||||||
return nil, c.discoveredMissingDependencies(module, depName, nil)
|
return nil, c.discoveredMissingDependencies(module, depName, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if m := findExactVariantOrSingle(module, possibleDeps, false); m != nil {
|
if m := c.findExactVariantOrSingle(module, config, possibleDeps, false); m != nil {
|
||||||
module.newDirectDeps = append(module.newDirectDeps, depInfo{m, tag})
|
module.newDirectDeps = append(module.newDirectDeps, depInfo{m, tag})
|
||||||
atomic.AddUint32(&c.depsModified, 1)
|
atomic.AddUint32(&c.depsModified, 1)
|
||||||
return m, nil
|
return m, nil
|
||||||
|
@ -1825,7 +1837,7 @@ func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName s
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
|
func (c *Context) findReverseDependency(module *moduleInfo, config any, destName string) (*moduleInfo, []error) {
|
||||||
if destName == module.Name() {
|
if destName == module.Name() {
|
||||||
return nil, []error{&BlueprintError{
|
return nil, []error{&BlueprintError{
|
||||||
Err: fmt.Errorf("%q depends on itself", destName),
|
Err: fmt.Errorf("%q depends on itself", destName),
|
||||||
|
@ -1842,7 +1854,7 @@ func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*m
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
if m := findExactVariantOrSingle(module, possibleDeps, true); m != nil {
|
if m := c.findExactVariantOrSingle(module, config, possibleDeps, true); m != nil {
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1860,7 +1872,33 @@ func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*m
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func findVariant(module *moduleInfo, possibleDeps *moduleGroup, variations []Variation, far bool, reverse bool) (*moduleInfo, variationMap) {
|
// applyIncomingTransitions takes a variationMap being used to add a dependency on a module in a moduleGroup
|
||||||
|
// and applies the IncomingTransition method of each completed TransitionMutator to modify the requested variation.
|
||||||
|
// It finds a variant that existed before the TransitionMutator ran that is a subset of the requested variant to
|
||||||
|
// use as the module context for IncomingTransition.
|
||||||
|
func (c *Context) applyIncomingTransitions(config any, group *moduleGroup, variant variationMap) {
|
||||||
|
for _, transitionMutator := range c.transitionMutators {
|
||||||
|
for _, inputVariant := range transitionMutator.inputVariants[group] {
|
||||||
|
if inputVariant.variant.variations.subsetOf(variant) {
|
||||||
|
sourceVariation := variant[transitionMutator.name]
|
||||||
|
|
||||||
|
ctx := &incomingTransitionContextImpl{
|
||||||
|
transitionContextImpl{context: c, source: nil, dep: inputVariant,
|
||||||
|
depTag: nil, config: config},
|
||||||
|
}
|
||||||
|
|
||||||
|
outgoingVariation := transitionMutator.mutator.IncomingTransition(ctx, sourceVariation)
|
||||||
|
variant[transitionMutator.name] = outgoingVariation
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) findVariant(module *moduleInfo, config any,
|
||||||
|
possibleDeps *moduleGroup, variations []Variation, far bool, reverse bool) (*moduleInfo, variationMap) {
|
||||||
|
|
||||||
// We can't just append variant.Variant to module.dependencyVariant.variantName and
|
// We can't just append variant.Variant to module.dependencyVariant.variantName and
|
||||||
// compare the strings because the result won't be in mutator registration order.
|
// compare the strings because the result won't be in mutator registration order.
|
||||||
// Create a new map instead, and then deep compare the maps.
|
// Create a new map instead, and then deep compare the maps.
|
||||||
|
@ -1882,6 +1920,8 @@ func findVariant(module *moduleInfo, possibleDeps *moduleGroup, variations []Var
|
||||||
newVariant[v.Mutator] = v.Variation
|
newVariant[v.Mutator] = v.Variation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.applyIncomingTransitions(config, possibleDeps, newVariant)
|
||||||
|
|
||||||
check := func(variant variationMap) bool {
|
check := func(variant variationMap) bool {
|
||||||
if far {
|
if far {
|
||||||
return newVariant.subsetOf(variant)
|
return newVariant.subsetOf(variant)
|
||||||
|
@ -1901,7 +1941,7 @@ func findVariant(module *moduleInfo, possibleDeps *moduleGroup, variations []Var
|
||||||
return foundDep, newVariant
|
return foundDep, newVariant
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
|
func (c *Context) addVariationDependency(module *moduleInfo, config any, variations []Variation,
|
||||||
tag DependencyTag, depName string, far bool) (*moduleInfo, []error) {
|
tag DependencyTag, depName string, far bool) (*moduleInfo, []error) {
|
||||||
if _, ok := tag.(BaseDependencyTag); ok {
|
if _, ok := tag.(BaseDependencyTag); ok {
|
||||||
panic("BaseDependencyTag is not allowed to be used directly!")
|
panic("BaseDependencyTag is not allowed to be used directly!")
|
||||||
|
@ -1912,7 +1952,7 @@ func (c *Context) addVariationDependency(module *moduleInfo, variations []Variat
|
||||||
return nil, c.discoveredMissingDependencies(module, depName, nil)
|
return nil, c.discoveredMissingDependencies(module, depName, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
foundDep, newVariant := findVariant(module, possibleDeps, variations, far, false)
|
foundDep, newVariant := c.findVariant(module, config, possibleDeps, variations, far, false)
|
||||||
|
|
||||||
if foundDep == nil {
|
if foundDep == nil {
|
||||||
if c.allowMissingDependencies {
|
if c.allowMissingDependencies {
|
||||||
|
@ -2936,6 +2976,13 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
|
||||||
|
|
||||||
c.moduleInfo = newModuleInfo
|
c.moduleInfo = newModuleInfo
|
||||||
|
|
||||||
|
isTransitionMutator := mutator.transitionMutator != nil
|
||||||
|
|
||||||
|
var transitionMutatorInputVariants map[*moduleGroup][]*moduleInfo
|
||||||
|
if isTransitionMutator {
|
||||||
|
transitionMutatorInputVariants = make(map[*moduleGroup][]*moduleInfo)
|
||||||
|
}
|
||||||
|
|
||||||
for _, group := range c.moduleGroups {
|
for _, group := range c.moduleGroups {
|
||||||
for i := 0; i < len(group.modules); i++ {
|
for i := 0; i < len(group.modules); i++ {
|
||||||
module := group.modules[i].module()
|
module := group.modules[i].module()
|
||||||
|
@ -2946,6 +2993,10 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
|
||||||
|
|
||||||
// Update module group to contain newly split variants
|
// Update module group to contain newly split variants
|
||||||
if module.splitModules != nil {
|
if module.splitModules != nil {
|
||||||
|
if isTransitionMutator {
|
||||||
|
// For transition mutators, save the pre-split variant for reusing later in applyIncomingTransitions.
|
||||||
|
transitionMutatorInputVariants[group] = append(transitionMutatorInputVariants[group], module)
|
||||||
|
}
|
||||||
group.modules, i = spliceModules(group.modules, i, module.splitModules)
|
group.modules, i = spliceModules(group.modules, i, module.splitModules)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2996,6 +3047,11 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isTransitionMutator {
|
||||||
|
mutator.transitionMutator.inputVariants = transitionMutatorInputVariants
|
||||||
|
c.transitionMutators = append(c.transitionMutators, mutator.transitionMutator)
|
||||||
|
}
|
||||||
|
|
||||||
// Add in any new reverse dependencies that were added by the mutator
|
// Add in any new reverse dependencies that were added by the mutator
|
||||||
for module, deps := range reverseDeps {
|
for module, deps := range reverseDeps {
|
||||||
sort.Sort(depSorter(deps))
|
sort.Sort(depSorter(deps))
|
||||||
|
@ -3031,6 +3087,14 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
|
||||||
return deps, errs
|
return deps, errs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clearTransitionMutatorInputVariants removes the inputVariants field from every
|
||||||
|
// TransitionMutator now that all dependencies have been resolved.
|
||||||
|
func (c *Context) clearTransitionMutatorInputVariants() {
|
||||||
|
for _, mutator := range c.transitionMutators {
|
||||||
|
mutator.inputVariants = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Replaces every build logic module with a clone of itself. Prevents introducing problems where
|
// Replaces every build logic module with a clone of itself. Prevents introducing problems where
|
||||||
// a mutator sets a non-property member variable on a module, which works until a later mutator
|
// a mutator sets a non-property member variable on a module, which works until a later mutator
|
||||||
// creates variants of that module.
|
// creates variants of that module.
|
||||||
|
|
|
@ -829,7 +829,8 @@ func Test_findVariant(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got, _ := findVariant(module, tt.possibleDeps, tt.variations, tt.far, tt.reverse)
|
ctx := NewContext()
|
||||||
|
got, _ := ctx.findVariant(module, nil, tt.possibleDeps, tt.variations, tt.far, tt.reverse)
|
||||||
if g, w := got == nil, tt.want == "nil"; g != w {
|
if g, w := got == nil, tt.want == "nil"; g != w {
|
||||||
t.Fatalf("findVariant() got = %v, want %v", got, tt.want)
|
t.Fatalf("findVariant() got = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
|
|
|
@ -575,7 +575,7 @@ func (m *baseModuleContext) OtherModuleDependencyVariantExists(variations []Vari
|
||||||
if possibleDeps == nil {
|
if possibleDeps == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
found, _ := findVariant(m.module, possibleDeps, variations, false, false)
|
found, _ := m.context.findVariant(m.module, m.config, possibleDeps, variations, false, false)
|
||||||
return found != nil
|
return found != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,7 +584,7 @@ func (m *baseModuleContext) OtherModuleFarDependencyVariantExists(variations []V
|
||||||
if possibleDeps == nil {
|
if possibleDeps == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
found, _ := findVariant(m.module, possibleDeps, variations, true, false)
|
found, _ := m.context.findVariant(m.module, m.config, possibleDeps, variations, true, false)
|
||||||
return found != nil
|
return found != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,7 +593,7 @@ func (m *baseModuleContext) OtherModuleReverseDependencyVariantExists(name strin
|
||||||
if possibleDeps == nil {
|
if possibleDeps == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
found, _ := findVariant(m.module, possibleDeps, nil, false, true)
|
found, _ := m.context.findVariant(m.module, m.config, possibleDeps, nil, false, true)
|
||||||
return found != nil
|
return found != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1117,7 +1117,7 @@ func (mctx *mutatorContext) AddDependency(module Module, tag DependencyTag, deps
|
||||||
depInfos := make([]Module, 0, len(deps))
|
depInfos := make([]Module, 0, len(deps))
|
||||||
for _, dep := range deps {
|
for _, dep := range deps {
|
||||||
modInfo := mctx.context.moduleInfo[module]
|
modInfo := mctx.context.moduleInfo[module]
|
||||||
depInfo, errs := mctx.context.addDependency(modInfo, tag, dep)
|
depInfo, errs := mctx.context.addDependency(modInfo, mctx.config, tag, dep)
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
mctx.errs = append(mctx.errs, errs...)
|
mctx.errs = append(mctx.errs, errs...)
|
||||||
}
|
}
|
||||||
|
@ -1135,7 +1135,7 @@ func (mctx *mutatorContext) AddReverseDependency(module Module, tag DependencyTa
|
||||||
panic("BaseDependencyTag is not allowed to be used directly!")
|
panic("BaseDependencyTag is not allowed to be used directly!")
|
||||||
}
|
}
|
||||||
|
|
||||||
destModule, errs := mctx.context.findReverseDependency(mctx.context.moduleInfo[module], destName)
|
destModule, errs := mctx.context.findReverseDependency(mctx.context.moduleInfo[module], mctx.config, destName)
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
mctx.errs = append(mctx.errs, errs...)
|
mctx.errs = append(mctx.errs, errs...)
|
||||||
return
|
return
|
||||||
|
@ -1152,7 +1152,7 @@ func (mctx *mutatorContext) AddVariationDependencies(variations []Variation, tag
|
||||||
|
|
||||||
depInfos := make([]Module, 0, len(deps))
|
depInfos := make([]Module, 0, len(deps))
|
||||||
for _, dep := range deps {
|
for _, dep := range deps {
|
||||||
depInfo, errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, false)
|
depInfo, errs := mctx.context.addVariationDependency(mctx.module, mctx.config, variations, tag, dep, false)
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
mctx.errs = append(mctx.errs, errs...)
|
mctx.errs = append(mctx.errs, errs...)
|
||||||
}
|
}
|
||||||
|
@ -1170,7 +1170,7 @@ func (mctx *mutatorContext) AddFarVariationDependencies(variations []Variation,
|
||||||
|
|
||||||
depInfos := make([]Module, 0, len(deps))
|
depInfos := make([]Module, 0, len(deps))
|
||||||
for _, dep := range deps {
|
for _, dep := range deps {
|
||||||
depInfo, errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, true)
|
depInfo, errs := mctx.context.addVariationDependency(mctx.module, mctx.config, variations, tag, dep, true)
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
mctx.errs = append(mctx.errs, errs...)
|
mctx.errs = append(mctx.errs, errs...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,6 +146,7 @@ type OutgoingTransitionContext interface {
|
||||||
type transitionMutatorImpl struct {
|
type transitionMutatorImpl struct {
|
||||||
name string
|
name string
|
||||||
mutator TransitionMutator
|
mutator TransitionMutator
|
||||||
|
inputVariants map[*moduleGroup][]*moduleInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds each argument in items to l if it's not already there.
|
// Adds each argument in items to l if it's not already there.
|
||||||
|
@ -294,7 +295,7 @@ func (c *Context) RegisterTransitionMutator(name string, mutator TransitionMutat
|
||||||
impl := &transitionMutatorImpl{name: name, mutator: mutator}
|
impl := &transitionMutatorImpl{name: name, mutator: mutator}
|
||||||
|
|
||||||
c.RegisterTopDownMutator(name+"_deps", impl.topDownMutator).Parallel()
|
c.RegisterTopDownMutator(name+"_deps", impl.topDownMutator).Parallel()
|
||||||
c.RegisterBottomUpMutator(name, impl.bottomUpMutator).Parallel()
|
c.RegisterBottomUpMutator(name, impl.bottomUpMutator).Parallel().setTransitionMutator(impl)
|
||||||
c.RegisterBottomUpMutator(name+"_mutate", impl.mutateMutator).Parallel()
|
c.RegisterBottomUpMutator(name+"_mutate", impl.mutateMutator).Parallel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,14 +15,48 @@
|
||||||
package blueprint
|
package blueprint
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTransition(t *testing.T) {
|
func testTransition(bp string) (*Context, []error) {
|
||||||
ctx := newContext()
|
ctx := newContext()
|
||||||
ctx.MockFileSystem(map[string][]byte{
|
ctx.MockFileSystem(map[string][]byte{
|
||||||
"Android.bp": []byte(`
|
"Android.bp": []byte(bp),
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.RegisterBottomUpMutator("deps", depsMutator)
|
||||||
|
ctx.RegisterTransitionMutator("transition", transitionTestMutator{})
|
||||||
|
ctx.RegisterBottomUpMutator("post_transition_deps", postTransitionDepsMutator)
|
||||||
|
|
||||||
|
ctx.RegisterModuleType("transition_module", newTransitionModule)
|
||||||
|
_, errs := ctx.ParseBlueprintsFiles("Android.bp", nil)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return nil, errs
|
||||||
|
}
|
||||||
|
|
||||||
|
_, errs = ctx.ResolveDependencies(nil)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return nil, errs
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertNoErrors(t *testing.T, errs []error) {
|
||||||
|
t.Helper()
|
||||||
|
if len(errs) > 0 {
|
||||||
|
t.Errorf("unexpected errors:")
|
||||||
|
for _, err := range errs {
|
||||||
|
t.Errorf(" %s", err)
|
||||||
|
}
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testTransitionBp = `
|
||||||
transition_module {
|
transition_module {
|
||||||
name: "A",
|
name: "A",
|
||||||
deps: ["B", "C"],
|
deps: ["B", "C"],
|
||||||
|
@ -33,6 +67,7 @@ func TestTransition(t *testing.T) {
|
||||||
name: "B",
|
name: "B",
|
||||||
deps: ["C"],
|
deps: ["C"],
|
||||||
outgoing: "c",
|
outgoing: "c",
|
||||||
|
%s
|
||||||
}
|
}
|
||||||
|
|
||||||
transition_module {
|
transition_module {
|
||||||
|
@ -43,39 +78,21 @@ func TestTransition(t *testing.T) {
|
||||||
transition_module {
|
transition_module {
|
||||||
name: "D",
|
name: "D",
|
||||||
incoming: "d",
|
incoming: "d",
|
||||||
}
|
deps: ["E"],
|
||||||
`),
|
|
||||||
})
|
|
||||||
|
|
||||||
ctx.RegisterBottomUpMutator("deps", depsMutator)
|
|
||||||
ctx.RegisterTransitionMutator("transition", transitionTestMutator{})
|
|
||||||
|
|
||||||
ctx.RegisterModuleType("transition_module", newTransitionModule)
|
|
||||||
_, errs := ctx.ParseBlueprintsFiles("Android.bp", nil)
|
|
||||||
if len(errs) > 0 {
|
|
||||||
t.Errorf("unexpected parse errors:")
|
|
||||||
for _, err := range errs {
|
|
||||||
t.Errorf(" %s", err)
|
|
||||||
}
|
|
||||||
t.FailNow()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, errs = ctx.ResolveDependencies(nil)
|
transition_module {
|
||||||
if len(errs) > 0 {
|
name: "E",
|
||||||
t.Errorf("unexpected dep errors:")
|
|
||||||
for _, err := range errs {
|
|
||||||
t.Errorf(" %s", err)
|
|
||||||
}
|
|
||||||
t.FailNow()
|
|
||||||
}
|
}
|
||||||
|
`
|
||||||
|
|
||||||
getModule := func(name, variant string) *transitionModule {
|
func getTransitionModule(ctx *Context, name, variant string) *transitionModule {
|
||||||
group := ctx.moduleGroupFromName(name, nil)
|
group := ctx.moduleGroupFromName(name, nil)
|
||||||
module := group.moduleOrAliasByVariantName(variant).module()
|
module := group.moduleOrAliasByVariantName(variant).module()
|
||||||
return module.logicModule.(*transitionModule)
|
return module.logicModule.(*transitionModule)
|
||||||
}
|
}
|
||||||
|
|
||||||
checkVariants := func(name string, expectedVariants []string) {
|
func checkTransitionVariants(t *testing.T, ctx *Context, name string, expectedVariants []string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
group := ctx.moduleGroupFromName(name, nil)
|
group := ctx.moduleGroupFromName(name, nil)
|
||||||
var gotVariants []string
|
var gotVariants []string
|
||||||
|
@ -85,27 +102,10 @@ func TestTransition(t *testing.T) {
|
||||||
if !slices.Equal(expectedVariants, gotVariants) {
|
if !slices.Equal(expectedVariants, gotVariants) {
|
||||||
t.Errorf("expected variants of %q to be %q, got %q", name, expectedVariants, gotVariants)
|
t.Errorf("expected variants of %q to be %q, got %q", name, expectedVariants, gotVariants)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Module A uses Split to create a and b variants
|
func checkTransitionDeps(t *testing.T, ctx *Context, m Module, expected ...string) {
|
||||||
checkVariants("A", []string{"a", "b"})
|
t.Helper()
|
||||||
// Module B inherits a and b variants from A
|
|
||||||
checkVariants("B", []string{"", "a", "b"})
|
|
||||||
// Module C inherits a and b variants from A, but gets an outgoing c variant from B
|
|
||||||
checkVariants("C", []string{"", "a", "b", "c"})
|
|
||||||
// Module D always has incoming variant d
|
|
||||||
checkVariants("D", []string{"", "d"})
|
|
||||||
|
|
||||||
A_a := getModule("A", "a")
|
|
||||||
A_b := getModule("A", "b")
|
|
||||||
B_a := getModule("B", "a")
|
|
||||||
B_b := getModule("B", "b")
|
|
||||||
C_a := getModule("C", "a")
|
|
||||||
C_b := getModule("C", "b")
|
|
||||||
C_c := getModule("C", "c")
|
|
||||||
D_d := getModule("D", "d")
|
|
||||||
|
|
||||||
checkDeps := func(m Module, expected ...string) {
|
|
||||||
var got []string
|
var got []string
|
||||||
ctx.VisitDirectDeps(m, func(m Module) {
|
ctx.VisitDirectDeps(m, func(m Module) {
|
||||||
got = append(got, ctx.ModuleName(m)+"("+ctx.ModuleSubDir(m)+")")
|
got = append(got, ctx.ModuleName(m)+"("+ctx.ModuleSubDir(m)+")")
|
||||||
|
@ -114,32 +114,120 @@ func TestTransition(t *testing.T) {
|
||||||
t.Errorf("unexpected %q dependencies, got %q expected %q",
|
t.Errorf("unexpected %q dependencies, got %q expected %q",
|
||||||
ctx.ModuleName(m), got, expected)
|
ctx.ModuleName(m), got, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkDeps(A_a, "B(a)", "C(a)")
|
func checkTransitionMutate(t *testing.T, m *transitionModule, variant string) {
|
||||||
checkDeps(A_b, "B(b)", "C(b)")
|
|
||||||
checkDeps(B_a, "C(c)")
|
|
||||||
checkDeps(B_b, "C(c)")
|
|
||||||
checkDeps(C_a, "D(d)")
|
|
||||||
checkDeps(C_b, "D(d)")
|
|
||||||
checkDeps(C_c, "D(d)")
|
|
||||||
checkDeps(D_d)
|
|
||||||
|
|
||||||
checkMutate := func(m *transitionModule, variant string) {
|
|
||||||
t.Helper()
|
t.Helper()
|
||||||
if m.properties.Mutated != variant {
|
if m.properties.Mutated != variant {
|
||||||
t.Errorf("unexpected mutated property in %q, expected %q got %q", m.Name(), variant, m.properties.Mutated)
|
t.Errorf("unexpected mutated property in %q, expected %q got %q", m.Name(), variant, m.properties.Mutated)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkMutate(A_a, "a")
|
func TestTransition(t *testing.T) {
|
||||||
checkMutate(A_b, "b")
|
ctx, errs := testTransition(fmt.Sprintf(testTransitionBp, ""))
|
||||||
checkMutate(B_a, "a")
|
assertNoErrors(t, errs)
|
||||||
checkMutate(B_b, "b")
|
|
||||||
checkMutate(C_a, "a")
|
// Module A uses Split to create a and b variants
|
||||||
checkMutate(C_b, "b")
|
checkTransitionVariants(t, ctx, "A", []string{"a", "b"})
|
||||||
checkMutate(C_c, "c")
|
// Module B inherits a and b variants from A
|
||||||
checkMutate(D_d, "d")
|
checkTransitionVariants(t, ctx, "B", []string{"", "a", "b"})
|
||||||
|
// Module C inherits a and b variants from A, but gets an outgoing c variant from B
|
||||||
|
checkTransitionVariants(t, ctx, "C", []string{"", "a", "b", "c"})
|
||||||
|
// Module D always has incoming variant d
|
||||||
|
checkTransitionVariants(t, ctx, "D", []string{"", "d"})
|
||||||
|
// Module E inherits d from D
|
||||||
|
checkTransitionVariants(t, ctx, "E", []string{"", "d"})
|
||||||
|
|
||||||
|
A_a := getTransitionModule(ctx, "A", "a")
|
||||||
|
A_b := getTransitionModule(ctx, "A", "b")
|
||||||
|
B_a := getTransitionModule(ctx, "B", "a")
|
||||||
|
B_b := getTransitionModule(ctx, "B", "b")
|
||||||
|
C_a := getTransitionModule(ctx, "C", "a")
|
||||||
|
C_b := getTransitionModule(ctx, "C", "b")
|
||||||
|
C_c := getTransitionModule(ctx, "C", "c")
|
||||||
|
D_d := getTransitionModule(ctx, "D", "d")
|
||||||
|
E_d := getTransitionModule(ctx, "E", "d")
|
||||||
|
|
||||||
|
checkTransitionDeps(t, ctx, A_a, "B(a)", "C(a)")
|
||||||
|
checkTransitionDeps(t, ctx, A_b, "B(b)", "C(b)")
|
||||||
|
checkTransitionDeps(t, ctx, B_a, "C(c)")
|
||||||
|
checkTransitionDeps(t, ctx, B_b, "C(c)")
|
||||||
|
checkTransitionDeps(t, ctx, C_a, "D(d)")
|
||||||
|
checkTransitionDeps(t, ctx, C_b, "D(d)")
|
||||||
|
checkTransitionDeps(t, ctx, C_c, "D(d)")
|
||||||
|
checkTransitionDeps(t, ctx, D_d, "E(d)")
|
||||||
|
checkTransitionDeps(t, ctx, E_d)
|
||||||
|
|
||||||
|
checkTransitionMutate(t, A_a, "a")
|
||||||
|
checkTransitionMutate(t, A_b, "b")
|
||||||
|
checkTransitionMutate(t, B_a, "a")
|
||||||
|
checkTransitionMutate(t, B_b, "b")
|
||||||
|
checkTransitionMutate(t, C_a, "a")
|
||||||
|
checkTransitionMutate(t, C_b, "b")
|
||||||
|
checkTransitionMutate(t, C_c, "c")
|
||||||
|
checkTransitionMutate(t, D_d, "d")
|
||||||
|
checkTransitionMutate(t, E_d, "d")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPostTransitionDeps(t *testing.T) {
|
||||||
|
ctx, errs := testTransition(fmt.Sprintf(testTransitionBp,
|
||||||
|
`post_transition_deps: ["D:late", "E:d"],`))
|
||||||
|
assertNoErrors(t, errs)
|
||||||
|
|
||||||
|
// Module A uses Split to create a and b variants
|
||||||
|
checkTransitionVariants(t, ctx, "A", []string{"a", "b"})
|
||||||
|
// Module B inherits a and b variants from A
|
||||||
|
checkTransitionVariants(t, ctx, "B", []string{"", "a", "b"})
|
||||||
|
// Module C inherits a and b variants from A, but gets an outgoing c variant from B
|
||||||
|
checkTransitionVariants(t, ctx, "C", []string{"", "a", "b", "c"})
|
||||||
|
// Module D always has incoming variant d
|
||||||
|
checkTransitionVariants(t, ctx, "D", []string{"", "d"})
|
||||||
|
// Module E inherits d from D
|
||||||
|
checkTransitionVariants(t, ctx, "E", []string{"", "d"})
|
||||||
|
|
||||||
|
A_a := getTransitionModule(ctx, "A", "a")
|
||||||
|
A_b := getTransitionModule(ctx, "A", "b")
|
||||||
|
B_a := getTransitionModule(ctx, "B", "a")
|
||||||
|
B_b := getTransitionModule(ctx, "B", "b")
|
||||||
|
C_a := getTransitionModule(ctx, "C", "a")
|
||||||
|
C_b := getTransitionModule(ctx, "C", "b")
|
||||||
|
C_c := getTransitionModule(ctx, "C", "c")
|
||||||
|
D_d := getTransitionModule(ctx, "D", "d")
|
||||||
|
E_d := getTransitionModule(ctx, "E", "d")
|
||||||
|
|
||||||
|
checkTransitionDeps(t, ctx, A_a, "B(a)", "C(a)")
|
||||||
|
checkTransitionDeps(t, ctx, A_b, "B(b)", "C(b)")
|
||||||
|
checkTransitionDeps(t, ctx, B_a, "C(c)", "D(d)", "E(d)")
|
||||||
|
checkTransitionDeps(t, ctx, B_b, "C(c)", "D(d)", "E(d)")
|
||||||
|
checkTransitionDeps(t, ctx, C_a, "D(d)")
|
||||||
|
checkTransitionDeps(t, ctx, C_b, "D(d)")
|
||||||
|
checkTransitionDeps(t, ctx, C_c, "D(d)")
|
||||||
|
checkTransitionDeps(t, ctx, D_d, "E(d)")
|
||||||
|
checkTransitionDeps(t, ctx, E_d)
|
||||||
|
|
||||||
|
checkTransitionMutate(t, A_a, "a")
|
||||||
|
checkTransitionMutate(t, A_b, "b")
|
||||||
|
checkTransitionMutate(t, B_a, "a")
|
||||||
|
checkTransitionMutate(t, B_b, "b")
|
||||||
|
checkTransitionMutate(t, C_a, "a")
|
||||||
|
checkTransitionMutate(t, C_b, "b")
|
||||||
|
checkTransitionMutate(t, C_c, "c")
|
||||||
|
checkTransitionMutate(t, D_d, "d")
|
||||||
|
checkTransitionMutate(t, E_d, "d")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPostTransitionDepsMissingVariant(t *testing.T) {
|
||||||
|
// TODO: eventually this will create the missing variant on demand
|
||||||
|
_, errs := testTransition(fmt.Sprintf(testTransitionBp,
|
||||||
|
`post_transition_deps: ["E:missing"],`))
|
||||||
|
expectedError := `Android.bp:8:4: dependency "E" of "B" missing variant:
|
||||||
|
transition:missing
|
||||||
|
available variants:
|
||||||
|
transition:
|
||||||
|
transition:d`
|
||||||
|
if len(errs) != 1 || errs[0].Error() != expectedError {
|
||||||
|
t.Errorf("expected error %q, got %q", expectedError, errs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type transitionTestMutator struct{}
|
type transitionTestMutator struct{}
|
||||||
|
@ -173,6 +261,7 @@ type transitionModule struct {
|
||||||
SimpleName
|
SimpleName
|
||||||
properties struct {
|
properties struct {
|
||||||
Deps []string
|
Deps []string
|
||||||
|
Post_transition_deps []string
|
||||||
Split []string
|
Split []string
|
||||||
Outgoing *string
|
Outgoing *string
|
||||||
Incoming *string
|
Incoming *string
|
||||||
|
@ -196,3 +285,13 @@ func (f *transitionModule) Deps() []string {
|
||||||
func (f *transitionModule) IgnoreDeps() []string {
|
func (f *transitionModule) IgnoreDeps() []string {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func postTransitionDepsMutator(mctx BottomUpMutatorContext) {
|
||||||
|
if m, ok := mctx.Module().(*transitionModule); ok {
|
||||||
|
for _, dep := range m.properties.Post_transition_deps {
|
||||||
|
module, variation, _ := strings.Cut(dep, ":")
|
||||||
|
variations := []Variation{{"transition", variation}}
|
||||||
|
mctx.AddVariationDependencies(variations, walkerDepsTag{follow: true}, module)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue