aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2024-03-29 12:25:29 -0700
committerColin Cross <ccross@android.com>2024-04-16 15:18:29 -0700
commitd7474dd743a284d37756c2b5c5716cf2e0d81f07 (patch)
tree577db864d59e46f219d01948e64c18d1e868d9f1
parent6ed94b7f852cfbbe96a918bcd2b3a9648dbf3f5e (diff)
downloadblueprint-d7474dd743a284d37756c2b5c5716cf2e0d81f07.tar.gz
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
-rw-r--r--context.go92
-rw-r--r--context_test.go3
-rw-r--r--module_ctx.go14
-rw-r--r--transition.go7
-rw-r--r--transition_test.go273
5 files changed, 277 insertions, 112 deletions
diff --git a/context.go b/context.go
index 0dbd223..738e4c3 100644
--- a/context.go
+++ b/context.go
@@ -91,6 +91,8 @@ type Context struct {
mutatorInfo []*mutatorInfo
variantMutatorNames []string
+ transitionMutators []*transitionMutatorImpl
+
depsModified uint32 // positive if a mutator modified the dependencies
dependenciesReady bool // set to true on a successful ResolveDependencies
@@ -455,10 +457,11 @@ type singletonInfo struct {
type mutatorInfo struct {
// set during RegisterMutator
- topDownMutator TopDownMutator
- bottomUpMutator BottomUpMutator
- name string
- parallel bool
+ topDownMutator TopDownMutator
+ bottomUpMutator BottomUpMutator
+ name string
+ parallel bool
+ transitionMutator *transitionMutatorImpl
}
func newContext() *Context {
@@ -686,6 +689,8 @@ type MutatorHandle interface {
// 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.
Parallel() MutatorHandle
+
+ setTransitionMutator(impl *transitionMutatorImpl) MutatorHandle
}
func (mutator *mutatorInfo) Parallel() MutatorHandle {
@@ -693,6 +698,11 @@ func (mutator *mutatorInfo) Parallel() MutatorHandle {
return mutator
}
+func (mutator *mutatorInfo) setTransitionMutator(impl *transitionMutatorImpl) MutatorHandle {
+ mutator.transitionMutator = impl
+ return mutator
+}
+
// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
// 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
@@ -1489,7 +1499,7 @@ func (c *Context) createVariations(origModule *moduleInfo, mutator *mutatorInfo,
var newLogicModule Module
var newProperties []interface{}
- if i == 0 {
+ if i == 0 && mutator.transitionMutator == nil {
// Reuse the existing module for the first new variant
// 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
@@ -1736,6 +1746,8 @@ func (c *Context) resolveDependencies(ctx context.Context, config interface{}) (
}
defer c.EndEvent("clone_modules")
+ c.clearTransitionMutatorInputVariants()
+
c.dependenciesReady = true
})
@@ -1772,8 +1784,8 @@ func blueprintDepsMutator(ctx BottomUpMutatorContext) {
// 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
// is always considered matching.
-func findExactVariantOrSingle(module *moduleInfo, possible *moduleGroup, reverse bool) *moduleInfo {
- found, _ := findVariant(module, possible, nil, false, reverse)
+func (c *Context) findExactVariantOrSingle(module *moduleInfo, config any, possible *moduleGroup, reverse bool) *moduleInfo {
+ found, _ := c.findVariant(module, config, possible, nil, false, reverse)
if found == nil {
for _, moduleOrAlias := range possible.modules {
if m := moduleOrAlias.module(); m != nil {
@@ -1788,7 +1800,7 @@ func findExactVariantOrSingle(module *moduleInfo, possible *moduleGroup, reverse
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 {
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)
}
- 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})
atomic.AddUint32(&c.depsModified, 1)
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() {
return nil, []error{&BlueprintError{
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
}
@@ -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
// compare the strings because the result won't be in mutator registration order.
// 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
}
+ c.applyIncomingTransitions(config, possibleDeps, newVariant)
+
check := func(variant variationMap) bool {
if far {
return newVariant.subsetOf(variant)
@@ -1901,7 +1941,7 @@ func findVariant(module *moduleInfo, possibleDeps *moduleGroup, variations []Var
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) {
if _, ok := tag.(BaseDependencyTag); ok {
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)
}
- foundDep, newVariant := findVariant(module, possibleDeps, variations, far, false)
+ foundDep, newVariant := c.findVariant(module, config, possibleDeps, variations, far, false)
if foundDep == nil {
if c.allowMissingDependencies {
@@ -2936,6 +2976,13 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
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 i := 0; i < len(group.modules); i++ {
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
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)
}
@@ -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
for module, deps := range reverseDeps {
sort.Sort(depSorter(deps))
@@ -3031,6 +3087,14 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
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
// a mutator sets a non-property member variable on a module, which works until a later mutator
// creates variants of that module.
diff --git a/context_test.go b/context_test.go
index b946497..e69f5da 100644
--- a/context_test.go
+++ b/context_test.go
@@ -829,7 +829,8 @@ func Test_findVariant(t *testing.T) {
}
for _, tt := range tests {
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 {
t.Fatalf("findVariant() got = %v, want %v", got, tt.want)
}
diff --git a/module_ctx.go b/module_ctx.go
index 6416a25..530eb5e 100644
--- a/module_ctx.go
+++ b/module_ctx.go
@@ -575,7 +575,7 @@ func (m *baseModuleContext) OtherModuleDependencyVariantExists(variations []Vari
if possibleDeps == nil {
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
}
@@ -584,7 +584,7 @@ func (m *baseModuleContext) OtherModuleFarDependencyVariantExists(variations []V
if possibleDeps == nil {
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
}
@@ -593,7 +593,7 @@ func (m *baseModuleContext) OtherModuleReverseDependencyVariantExists(name strin
if possibleDeps == nil {
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
}
@@ -1117,7 +1117,7 @@ func (mctx *mutatorContext) AddDependency(module Module, tag DependencyTag, deps
depInfos := make([]Module, 0, len(deps))
for _, dep := range deps {
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 {
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!")
}
- 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 {
mctx.errs = append(mctx.errs, errs...)
return
@@ -1152,7 +1152,7 @@ func (mctx *mutatorContext) AddVariationDependencies(variations []Variation, tag
depInfos := make([]Module, 0, len(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 {
mctx.errs = append(mctx.errs, errs...)
}
@@ -1170,7 +1170,7 @@ func (mctx *mutatorContext) AddFarVariationDependencies(variations []Variation,
depInfos := make([]Module, 0, len(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 {
mctx.errs = append(mctx.errs, errs...)
}
diff --git a/transition.go b/transition.go
index 31f785e..6a03e1d 100644
--- a/transition.go
+++ b/transition.go
@@ -144,8 +144,9 @@ type OutgoingTransitionContext interface {
}
type transitionMutatorImpl struct {
- name string
- mutator TransitionMutator
+ name string
+ mutator TransitionMutator
+ inputVariants map[*moduleGroup][]*moduleInfo
}
// 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}
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()
}
diff --git a/transition_test.go b/transition_test.go
index 128e7d5..dea818a 100644
--- a/transition_test.go
+++ b/transition_test.go
@@ -15,14 +15,48 @@
package blueprint
import (
+ "fmt"
"slices"
+ "strings"
"testing"
)
-func TestTransition(t *testing.T) {
+func testTransition(bp string) (*Context, []error) {
ctx := newContext()
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 {
name: "A",
deps: ["B", "C"],
@@ -33,6 +67,7 @@ func TestTransition(t *testing.T) {
name: "B",
deps: ["C"],
outgoing: "c",
+ %s
}
transition_module {
@@ -43,103 +78,156 @@ func TestTransition(t *testing.T) {
transition_module {
name: "D",
incoming: "d",
+ deps: ["E"],
}
- `),
- })
- ctx.RegisterBottomUpMutator("deps", depsMutator)
- ctx.RegisterTransitionMutator("transition", transitionTestMutator{})
+ transition_module {
+ name: "E",
+ }
+ `
- 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()
- }
+func getTransitionModule(ctx *Context, name, variant string) *transitionModule {
+ group := ctx.moduleGroupFromName(name, nil)
+ module := group.moduleOrAliasByVariantName(variant).module()
+ return module.logicModule.(*transitionModule)
+}
- _, errs = ctx.ResolveDependencies(nil)
- if len(errs) > 0 {
- t.Errorf("unexpected dep errors:")
- for _, err := range errs {
- t.Errorf(" %s", err)
- }
- t.FailNow()
+func checkTransitionVariants(t *testing.T, ctx *Context, name string, expectedVariants []string) {
+ t.Helper()
+ group := ctx.moduleGroupFromName(name, nil)
+ var gotVariants []string
+ for _, variant := range group.modules {
+ gotVariants = append(gotVariants, variant.moduleOrAliasVariant().variations["transition"])
+ }
+ if !slices.Equal(expectedVariants, gotVariants) {
+ t.Errorf("expected variants of %q to be %q, got %q", name, expectedVariants, gotVariants)
}
+}
- getModule := func(name, variant string) *transitionModule {
- group := ctx.moduleGroupFromName(name, nil)
- module := group.moduleOrAliasByVariantName(variant).module()
- return module.logicModule.(*transitionModule)
+func checkTransitionDeps(t *testing.T, ctx *Context, m Module, expected ...string) {
+ t.Helper()
+ var got []string
+ ctx.VisitDirectDeps(m, func(m Module) {
+ got = append(got, ctx.ModuleName(m)+"("+ctx.ModuleSubDir(m)+")")
+ })
+ if !slices.Equal(got, expected) {
+ t.Errorf("unexpected %q dependencies, got %q expected %q",
+ ctx.ModuleName(m), got, expected)
}
+}
- checkVariants := func(name string, expectedVariants []string) {
- t.Helper()
- group := ctx.moduleGroupFromName(name, nil)
- var gotVariants []string
- for _, variant := range group.modules {
- gotVariants = append(gotVariants, variant.moduleOrAliasVariant().variations["transition"])
- }
- if !slices.Equal(expectedVariants, gotVariants) {
- t.Errorf("expected variants of %q to be %q, got %q", name, expectedVariants, gotVariants)
- }
+func checkTransitionMutate(t *testing.T, m *transitionModule, variant string) {
+ t.Helper()
+ if m.properties.Mutated != variant {
+ t.Errorf("unexpected mutated property in %q, expected %q got %q", m.Name(), variant, m.properties.Mutated)
}
+}
+
+func TestTransition(t *testing.T) {
+ ctx, errs := testTransition(fmt.Sprintf(testTransitionBp, ""))
+ assertNoErrors(t, errs)
// Module A uses Split to create a and b variants
- checkVariants("A", []string{"a", "b"})
+ checkTransitionVariants(t, ctx, "A", []string{"a", "b"})
// Module B inherits a and b variants from A
- checkVariants("B", []string{"", "a", "b"})
+ checkTransitionVariants(t, ctx, "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"})
+ checkTransitionVariants(t, ctx, "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
- ctx.VisitDirectDeps(m, func(m Module) {
- got = append(got, ctx.ModuleName(m)+"("+ctx.ModuleSubDir(m)+")")
- })
- if !slices.Equal(got, expected) {
- t.Errorf("unexpected %q dependencies, got %q expected %q",
- ctx.ModuleName(m), got, expected)
- }
- }
+ checkTransitionVariants(t, ctx, "D", []string{"", "d"})
+ // Module E inherits d from D
+ checkTransitionVariants(t, ctx, "E", []string{"", "d"})
- checkDeps(A_a, "B(a)", "C(a)")
- 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()
- if m.properties.Mutated != variant {
- t.Errorf("unexpected mutated property in %q, expected %q got %q", m.Name(), variant, m.properties.Mutated)
- }
- }
+ 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)
- checkMutate(A_a, "a")
- checkMutate(A_b, "b")
- checkMutate(B_a, "a")
- checkMutate(B_b, "b")
- checkMutate(C_a, "a")
- checkMutate(C_b, "b")
- checkMutate(C_c, "c")
- checkMutate(D_d, "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{}
@@ -172,10 +260,11 @@ func (transitionTestMutator) Mutate(ctx BottomUpMutatorContext, variation string
type transitionModule struct {
SimpleName
properties struct {
- Deps []string
- Split []string
- Outgoing *string
- Incoming *string
+ Deps []string
+ Post_transition_deps []string
+ Split []string
+ Outgoing *string
+ Incoming *string
Mutated string `blueprint:"mutated"`
}
@@ -196,3 +285,13 @@ func (f *transitionModule) Deps() []string {
func (f *transitionModule) IgnoreDeps() []string {
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)
+ }
+ }
+}