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
This commit is contained in:
Colin Cross 2020-08-13 12:11:52 -07:00
parent edc41769fe
commit 279489c017
3 changed files with 236 additions and 32 deletions

View file

@ -201,8 +201,8 @@ type moduleInfo struct {
waitingCount int
// set during each runMutator
splitModules []*moduleInfo
aliasTarget *moduleInfo
splitModules []*moduleInfo
pendingAliases []pendingAlias
// set during PrepareBuildActions
actionDefs localBuildActions
@ -1317,6 +1317,15 @@ func (c *Context) convertDepsToVariation(module *moduleInfo,
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 @@ func (c *Context) convertDepsToVariation(module *moduleInfo,
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 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
panic("split module found in sorted module list")
}
module.pendingAliases = nil
mctx := &mutatorContext{
baseModuleContext: baseModuleContext{
context: c,
@ -2315,10 +2335,10 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
}
// 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 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
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:]...)
@ -3538,14 +3568,17 @@ func (s moduleSorter) Less(i, j int) bool {
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) {

View file

@ -850,12 +850,21 @@ type BottomUpMutatorContext interface {
// 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 @@ func (mctx *mutatorContext) CreateLocalVariations(variationNames ...string) []Mo
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) createVariations(variationNames []string, local bool
}
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 @@ func (mctx *mutatorContext) AliasVariation(variationName string) {
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)
}

View file

@ -32,7 +32,7 @@ func newModuleCtxTestModule() (Module, []interface{}) {
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 noCreateAliasMutator(name string) func(ctx BottomUpMutatorContext) {
}
}
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 addVariantDepsMutator(variants []Variation, tag DependencyTag, from, to str
}
}
func TestAliases(t *testing.T) {
func TestAliasVariation(t *testing.T) {
runWithFailures := func(ctx *Context, expectedErr string) {
t.Helper()
bp := `
@ -115,7 +126,7 @@ func TestAliases(t *testing.T) {
// 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 @@ func TestAliases(t *testing.T) {
// 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 @@ func TestAliases(t *testing.T) {
// 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 @@ func TestAliases(t *testing.T) {
// 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 TestAliases(t *testing.T) {
})
}
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) {