Add CreateAliasVariation
CreateAliasVariation creates a new variation for the current mutator
that is an alias to a variation that was created with CreateVarations
by the same mutator. It is similar to AliasVariation, except that
AliasVariation creates an alias from the pre-mutated variant to one
of the new variations, while CreateAliasVariation creates an alias
from a new post-mutated variation to one of the new variations.
Bug: 164216768
Test: TestCreateAliasVariation
Change-Id: I8847b8d6fc1d3248abc910b2fe2399881f9bdaee
diff --git a/context.go b/context.go
index e2f07e6..75e9b00 100644
--- a/context.go
+++ b/context.go
@@ -201,8 +201,8 @@
waitingCount int
// set during each runMutator
- splitModules []*moduleInfo
- aliasTarget *moduleInfo
+ splitModules []*moduleInfo
+ pendingAliases []pendingAlias
// set during PrepareBuildActions
actionDefs localBuildActions
@@ -1317,6 +1317,15 @@
break
}
}
+ if newDep == nil {
+ // check aliases against variationNam
+ for _, a := range dep.module.pendingAliases {
+ if a.fromVariant.variations[mutatorName] == variationName {
+ newDep = a.target
+ break
+ }
+ }
+ }
if newDep == nil && defaultVariationName != nil {
// give it a second chance; match with defaultVariationName
for _, m := range dep.module.splitModules {
@@ -1325,6 +1334,15 @@
break
}
}
+ if newDep == nil {
+ // check aliases against defaultVariationName
+ for _, a := range dep.module.pendingAliases {
+ if a.fromVariant.variations[mutatorName] == *defaultVariationName {
+ newDep = a.target
+ break
+ }
+ }
+ }
}
if newDep == nil {
errs = append(errs, &BlueprintError{
@@ -2221,6 +2239,8 @@
panic("split module found in sorted module list")
}
+ module.pendingAliases = nil
+
mctx := &mutatorContext{
baseModuleContext: baseModuleContext{
context: c,
@@ -2315,10 +2335,10 @@
}
// Create any new aliases.
- if module.aliasTarget != nil {
+ for _, alias := range module.pendingAliases {
group.aliases = append(group.aliases, &moduleAlias{
- variant: module.variant,
- target: module.aliasTarget,
+ variant: alias.fromVariant,
+ target: alias.target,
})
}
@@ -2339,13 +2359,23 @@
module.newDirectDeps = nil
}
+ findAliasTarget := func(variant variant) *moduleInfo {
+ for _, alias := range group.aliases {
+ if alias.variant.variations.equal(variant.variations) {
+ return alias.target
+ }
+ }
+ return nil
+ }
+
// Forward or delete any dangling aliases.
for i := 0; i < len(group.aliases); i++ {
alias := group.aliases[i]
if alias.target.logicModule == nil {
- if alias.target.aliasTarget != nil {
- alias.target = alias.target.aliasTarget
+ newTarget := findAliasTarget(alias.target.variant)
+ if newTarget != nil {
+ alias.target = newTarget
} else {
// The alias was left dangling, remove it.
group.aliases = append(group.aliases[:i], group.aliases[i+1:]...)
@@ -3543,14 +3573,17 @@
iName := s.nameInterface.UniqueName(newNamespaceContext(iMod), iMod.group.name)
jName := s.nameInterface.UniqueName(newNamespaceContext(jMod), jMod.group.name)
if iName == jName {
- iName = s.modules[i].variant.name
- jName = s.modules[j].variant.name
+ iVariantName := s.modules[i].variant.name
+ jVariantName := s.modules[j].variant.name
+ if iVariantName == jVariantName {
+ panic(fmt.Sprintf("duplicate module name: %s %s: %#v and %#v\n",
+ iName, iVariantName, iMod.variant.variations, jMod.variant.variations))
+ } else {
+ return iVariantName < jVariantName
+ }
+ } else {
+ return iName < jName
}
-
- if iName == jName {
- panic(fmt.Sprintf("duplicate module name: %s: %#v and %#v\n", iName, iMod, jMod))
- }
- return iName < jName
}
func (s moduleSorter) Swap(i, j int) {
diff --git a/module_ctx.go b/module_ctx.go
index 0b58817..d8b1582 100644
--- a/module_ctx.go
+++ b/module_ctx.go
@@ -850,12 +850,21 @@
// Replacements don't take effect until after the mutator pass is finished.
ReplaceDependenciesIf(string, ReplaceDependencyPredicate)
- // AliasVariation takes a variationName that was passed to CreateVariations for this module, and creates an
- // alias from the current variant to the new variant. The alias will be valid until the next time a mutator
- // calls CreateVariations or CreateLocalVariations on this module without also calling AliasVariation. The
- // alias can be used to add dependencies on the newly created variant using the variant map from before
- // CreateVariations was run.
+ // AliasVariation takes a variationName that was passed to CreateVariations for this module,
+ // and creates an alias from the current variant (before the mutator has run) to the new
+ // variant. The alias will be valid until the next time a mutator calls CreateVariations or
+ // CreateLocalVariations on this module without also calling AliasVariation. The alias can
+ // be used to add dependencies on the newly created variant using the variant map from
+ // before CreateVariations was run.
AliasVariation(variationName string)
+
+ // CreateAliasVariation takes a toVariationName that was passed to CreateVariations for this
+ // module, and creates an alias from a new fromVariationName variant the toVariationName
+ // variant. The alias will be valid until the next time a mutator calls CreateVariations or
+ // CreateLocalVariations on this module without also calling AliasVariation. The alias can
+ // be used to add dependencies on the toVariationName variant using the fromVariationName
+ // variant.
+ CreateAliasVariation(fromVariationName, toVariationName string)
}
// A Mutator function is called for each Module, and can use
@@ -899,6 +908,11 @@
return mctx.createVariations(variationNames, true)
}
+type pendingAlias struct {
+ fromVariant variant
+ target *moduleInfo
+}
+
func (mctx *mutatorContext) createVariations(variationNames []string, local bool) []Module {
ret := []Module{}
modules, errs := mctx.context.createVariations(mctx.module, mctx.name, mctx.defaultVariation, variationNames, local)
@@ -923,13 +937,18 @@
}
func (mctx *mutatorContext) AliasVariation(variationName string) {
- if mctx.module.aliasTarget != nil {
- panic(fmt.Errorf("AliasVariation already called"))
+ for _, alias := range mctx.module.pendingAliases {
+ if alias.fromVariant.variations.equal(mctx.module.variant.variations) {
+ panic(fmt.Errorf("AliasVariation already called"))
+ }
}
for _, variant := range mctx.newVariations {
if variant.variant.variations[mctx.name] == variationName {
- mctx.module.aliasTarget = variant
+ mctx.module.pendingAliases = append(mctx.module.pendingAliases, pendingAlias{
+ fromVariant: mctx.module.variant,
+ target: variant,
+ })
return
}
}
@@ -941,6 +960,32 @@
panic(fmt.Errorf("no %q variation in module variations %q", variationName, foundVariations))
}
+func (mctx *mutatorContext) CreateAliasVariation(aliasVariationName, targetVariationName string) {
+ newVariant := newVariant(mctx.module, mctx.name, aliasVariationName, false)
+
+ for _, alias := range mctx.module.pendingAliases {
+ if alias.fromVariant.variations.equal(newVariant.variations) {
+ panic(fmt.Errorf("can't alias %q to %q, already aliased to %q", aliasVariationName, targetVariationName, alias.target.variant.name))
+ }
+ }
+
+ for _, variant := range mctx.newVariations {
+ if variant.variant.variations[mctx.name] == targetVariationName {
+ mctx.module.pendingAliases = append(mctx.module.pendingAliases, pendingAlias{
+ fromVariant: newVariant,
+ target: variant,
+ })
+ return
+ }
+ }
+
+ var foundVariations []string
+ for _, variant := range mctx.newVariations {
+ foundVariations = append(foundVariations, variant.variant.variations[mctx.name])
+ }
+ panic(fmt.Errorf("no %q variation in module variations %q", targetVariationName, foundVariations))
+}
+
func (mctx *mutatorContext) SetDependencyVariation(variationName string) {
mctx.context.convertDepsToVariation(mctx.module, mctx.name, variationName, nil)
}
diff --git a/module_ctx_test.go b/module_ctx_test.go
index e39f51a..22666dc 100644
--- a/module_ctx_test.go
+++ b/module_ctx_test.go
@@ -32,7 +32,7 @@
func (f *moduleCtxTestModule) GenerateBuildActions(ModuleContext) {
}
-func noCreateAliasMutator(name string) func(ctx BottomUpMutatorContext) {
+func noAliasMutator(name string) func(ctx BottomUpMutatorContext) {
return func(ctx BottomUpMutatorContext) {
if ctx.ModuleName() == name {
ctx.CreateVariations("a", "b")
@@ -40,11 +40,22 @@
}
}
+func aliasMutator(name string) func(ctx BottomUpMutatorContext) {
+ return func(ctx BottomUpMutatorContext) {
+ if ctx.ModuleName() == name {
+ ctx.CreateVariations("a", "b")
+ ctx.AliasVariation("b")
+ }
+ }
+}
+
func createAliasMutator(name string) func(ctx BottomUpMutatorContext) {
return func(ctx BottomUpMutatorContext) {
if ctx.ModuleName() == name {
ctx.CreateVariations("a", "b")
- ctx.AliasVariation("b")
+ ctx.CreateAliasVariation("c", "a")
+ ctx.CreateAliasVariation("d", "b")
+ ctx.CreateAliasVariation("e", "a")
}
}
}
@@ -57,7 +68,7 @@
}
}
-func TestAliases(t *testing.T) {
+func TestAliasVariation(t *testing.T) {
runWithFailures := func(ctx *Context, expectedErr string) {
t.Helper()
bp := `
@@ -115,7 +126,7 @@
// Tests a dependency from "foo" to "bar" variant "b" through alias "".
ctx := NewContext()
ctx.RegisterModuleType("test", newModuleCtxTestModule)
- ctx.RegisterBottomUpMutator("1", createAliasMutator("bar"))
+ ctx.RegisterBottomUpMutator("1", aliasMutator("bar"))
ctx.RegisterBottomUpMutator("2", addVariantDepsMutator(nil, nil, "foo", "bar"))
run(ctx)
@@ -138,8 +149,8 @@
// Tests a dependency from "foo" to "bar" variant "b_b" through alias "".
ctx := NewContext()
ctx.RegisterModuleType("test", newModuleCtxTestModule)
- ctx.RegisterBottomUpMutator("1", createAliasMutator("bar"))
- ctx.RegisterBottomUpMutator("2", createAliasMutator("bar"))
+ ctx.RegisterBottomUpMutator("1", aliasMutator("bar"))
+ ctx.RegisterBottomUpMutator("2", aliasMutator("bar"))
ctx.RegisterBottomUpMutator("3", addVariantDepsMutator(nil, nil, "foo", "bar"))
run(ctx)
@@ -162,8 +173,8 @@
// Tests a dependency from "foo" to "bar" variant "a_b" through alias "a".
ctx := NewContext()
ctx.RegisterModuleType("test", newModuleCtxTestModule)
- ctx.RegisterBottomUpMutator("1", createAliasMutator("bar"))
- ctx.RegisterBottomUpMutator("2", createAliasMutator("bar"))
+ ctx.RegisterBottomUpMutator("1", aliasMutator("bar"))
+ ctx.RegisterBottomUpMutator("2", aliasMutator("bar"))
ctx.RegisterBottomUpMutator("3", addVariantDepsMutator([]Variation{{"1", "a"}}, nil, "foo", "bar"))
run(ctx)
@@ -186,8 +197,8 @@
// Tests a dependency from "foo" to removed "bar" alias "" fails.
ctx := NewContext()
ctx.RegisterModuleType("test", newModuleCtxTestModule)
- ctx.RegisterBottomUpMutator("1", createAliasMutator("bar"))
- ctx.RegisterBottomUpMutator("2", noCreateAliasMutator("bar"))
+ ctx.RegisterBottomUpMutator("1", aliasMutator("bar"))
+ ctx.RegisterBottomUpMutator("2", noAliasMutator("bar"))
ctx.RegisterBottomUpMutator("3", addVariantDepsMutator(nil, nil, "foo", "bar"))
runWithFailures(ctx, `dependency "bar" of "foo" missing variant:`+"\n \n"+
@@ -196,6 +207,121 @@
})
}
+func TestCreateAliasVariations(t *testing.T) {
+ runWithFailures := func(ctx *Context, expectedErr string) {
+ t.Helper()
+ bp := `
+ test {
+ name: "foo",
+ }
+
+ test {
+ name: "bar",
+ }
+ `
+
+ mockFS := map[string][]byte{
+ "Blueprints": []byte(bp),
+ }
+
+ ctx.MockFileSystem(mockFS)
+
+ _, errs := ctx.ParseFileList(".", []string{"Blueprints"}, nil)
+ if len(errs) > 0 {
+ t.Errorf("unexpected parse errors:")
+ for _, err := range errs {
+ t.Errorf(" %s", err)
+ }
+ }
+
+ _, errs = ctx.ResolveDependencies(nil)
+ if len(errs) > 0 {
+ if expectedErr == "" {
+ t.Errorf("unexpected dep errors:")
+ for _, err := range errs {
+ t.Errorf(" %s", err)
+ }
+ } else {
+ for _, err := range errs {
+ if strings.Contains(err.Error(), expectedErr) {
+ continue
+ } else {
+ t.Errorf("unexpected dep error: %s", err)
+ }
+ }
+ }
+ } else if expectedErr != "" {
+ t.Errorf("missing dep error: %s", expectedErr)
+ }
+ }
+
+ run := func(ctx *Context) {
+ t.Helper()
+ runWithFailures(ctx, "")
+ }
+
+ t.Run("simple", func(t *testing.T) {
+ // Creates a module "bar" with variants "a" and "b" and alias "c" -> "a", "d" -> "b", and "e" -> "a".
+ // Tests a dependency from "foo" to "bar" variant "b" through alias "d".
+ ctx := NewContext()
+ ctx.RegisterModuleType("test", newModuleCtxTestModule)
+ ctx.RegisterBottomUpMutator("1", createAliasMutator("bar"))
+ ctx.RegisterBottomUpMutator("2", addVariantDepsMutator([]Variation{{"1", "d"}}, nil, "foo", "bar"))
+
+ run(ctx)
+
+ foo := ctx.moduleGroupFromName("foo", nil).modules[0]
+ barB := ctx.moduleGroupFromName("bar", nil).modules[1]
+
+ if g, w := barB.variant.name, "b"; g != w {
+ t.Fatalf("expected bar.modules[1] variant to be %q, got %q", w, g)
+ }
+
+ if g, w := foo.forwardDeps, []*moduleInfo{barB}; !reflect.DeepEqual(g, w) {
+ t.Fatalf("expected foo deps to be %q, got %q", w, g)
+ }
+ })
+
+ t.Run("chained", func(t *testing.T) {
+ // Creates a module "bar" with variants "a_a", "a_b", "b_a" and "b_b" and aliases "c" -> "a_b",
+ // "d" -> "b_b", and "d" -> "a_b".
+ // Tests a dependency from "foo" to "bar" variant "b_b" through alias "d".
+ ctx := NewContext()
+ ctx.RegisterModuleType("test", newModuleCtxTestModule)
+ ctx.RegisterBottomUpMutator("1", createAliasMutator("bar"))
+ ctx.RegisterBottomUpMutator("2", aliasMutator("bar"))
+ ctx.RegisterBottomUpMutator("3", addVariantDepsMutator([]Variation{{"1", "d"}}, nil, "foo", "bar"))
+
+ run(ctx)
+
+ foo := ctx.moduleGroupFromName("foo", nil).modules[0]
+ barBB := ctx.moduleGroupFromName("bar", nil).modules[3]
+
+ if g, w := barBB.variant.name, "b_b"; g != w {
+ t.Fatalf("expected bar.modules[3] variant to be %q, got %q", w, g)
+ }
+
+ if g, w := foo.forwardDeps, []*moduleInfo{barBB}; !reflect.DeepEqual(g, w) {
+ t.Fatalf("expected foo deps to be %q, got %q", w, g)
+ }
+ })
+
+ t.Run("removed dangling alias", func(t *testing.T) {
+ // Creates a module "bar" with variants "a" and "b" and alias "c" -> "a", "d" -> "b", and "e" -> "a",
+ // then splits the variants into "a_a", "a_b", "b_a" and "b_b" without creating new aliases.
+ // Tests a dependency from "foo" to removed "bar" alias "d" fails.
+ ctx := NewContext()
+ ctx.RegisterModuleType("test", newModuleCtxTestModule)
+ ctx.RegisterBottomUpMutator("1", createAliasMutator("bar"))
+ ctx.RegisterBottomUpMutator("2", noAliasMutator("bar"))
+ ctx.RegisterBottomUpMutator("3", addVariantDepsMutator([]Variation{{"1", "d"}}, nil, "foo", "bar"))
+
+ runWithFailures(ctx, `dependency "bar" of "foo" missing variant:`+"\n 1:d\n"+
+ "available variants:"+
+ "\n 1:a, 2:a\n 1:a, 2:b\n 1:b, 2:a\n 1:b, 2:b")
+ })
+}
+
func expectedErrors(t *testing.T, errs []error, expectedMessages ...string) {
t.Helper()
if len(errs) != len(expectedMessages) {