diff --git a/context.go b/context.go index 896edbb..a4fea26 100644 --- a/context.go +++ b/context.go @@ -159,10 +159,8 @@ type localBuildActions struct { } type moduleAlias struct { - variantName string - variant variationMap - dependencyVariant variationMap - target *moduleInfo + variant variant + target *moduleInfo } type moduleGroup struct { @@ -184,9 +182,7 @@ type moduleInfo struct { propertyPos map[string]scanner.Position createdBy *moduleInfo - variantName string - variant variationMap - dependencyVariant variationMap + variant variant logicModule Module group *moduleGroup @@ -205,13 +201,19 @@ type moduleInfo struct { waitingCount int // set during each runMutator - splitModules []*moduleInfo - aliasTarget *moduleInfo + splitModules []*moduleInfo + pendingAliases []pendingAlias // set during PrepareBuildActions actionDefs localBuildActions } +type variant struct { + name string + variations variationMap + dependencyVariations variationMap +} + type depInfo struct { module *moduleInfo tag DependencyTag @@ -232,8 +234,8 @@ func (module *moduleInfo) Name() string { func (module *moduleInfo) String() string { s := fmt.Sprintf("module %q", module.Name()) - if module.variantName != "" { - s += fmt.Sprintf(" variant %q", module.variantName) + if module.variant.name != "" { + s += fmt.Sprintf(" variant %q", module.variant.name) } if module.createdBy != nil { s += fmt.Sprintf(" (created by %s)", module.createdBy) @@ -1224,8 +1226,37 @@ func (c *Context) cloneLogicModule(origModule *moduleInfo) (Module, []interface{ return newLogicModule, newProperties } +func newVariant(module *moduleInfo, mutatorName string, variationName string, + local bool) variant { + + newVariantName := module.variant.name + if variationName != "" { + if newVariantName == "" { + newVariantName = variationName + } else { + newVariantName += "_" + variationName + } + } + + newVariations := module.variant.variations.clone() + if newVariations == nil { + newVariations = make(variationMap) + } + newVariations[mutatorName] = variationName + + newDependencyVariations := module.variant.dependencyVariations.clone() + if !local { + if newDependencyVariations == nil { + newDependencyVariations = make(variationMap) + } + newDependencyVariations[mutatorName] = variationName + } + + return variant{newVariantName, newVariations, newDependencyVariations} +} + func (c *Context) createVariations(origModule *moduleInfo, mutatorName string, - defaultVariationName *string, variationNames []string) ([]*moduleInfo, []error) { + defaultVariationName *string, variationNames []string, local bool) ([]*moduleInfo, []error) { if len(variationNames) == 0 { panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q", @@ -1249,28 +1280,13 @@ func (c *Context) createVariations(origModule *moduleInfo, mutatorName string, newLogicModule, newProperties = c.cloneLogicModule(origModule) } - newVariant := origModule.variant.clone() - if newVariant == nil { - newVariant = make(variationMap) - } - newVariant[mutatorName] = variationName - m := *origModule newModule := &m newModule.directDeps = append([]depInfo{}, origModule.directDeps...) newModule.logicModule = newLogicModule - newModule.variant = newVariant - newModule.dependencyVariant = origModule.dependencyVariant.clone() + newModule.variant = newVariant(origModule, mutatorName, variationName, local) newModule.properties = newProperties - if variationName != "" { - if newModule.variantName == "" { - newModule.variantName = variationName - } else { - newModule.variantName += "_" + variationName - } - } - newModules = append(newModules, newModule) newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName, defaultVariationName) @@ -1296,19 +1312,37 @@ func (c *Context) convertDepsToVariation(module *moduleInfo, if dep.module.logicModule == nil { var newDep *moduleInfo for _, m := range dep.module.splitModules { - if m.variant[mutatorName] == variationName { + if m.variant.variations[mutatorName] == variationName { newDep = m 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 { - if m.variant[mutatorName] == *defaultVariationName { + if m.variant.variations[mutatorName] == *defaultVariationName { newDep = m 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{ @@ -1325,10 +1359,10 @@ func (c *Context) convertDepsToVariation(module *moduleInfo, return errs } -func (c *Context) prettyPrintVariant(variant variationMap) string { - names := make([]string, 0, len(variant)) +func (c *Context) prettyPrintVariant(variations variationMap) string { + names := make([]string, 0, len(variations)) for _, m := range c.variantMutatorNames { - if v, ok := variant[m]; ok { + if v, ok := variations[m]; ok { names = append(names, m+":"+v) } } @@ -1339,11 +1373,11 @@ func (c *Context) prettyPrintVariant(variant variationMap) string { func (c *Context) prettyPrintGroupVariants(group *moduleGroup) string { var variants []string for _, mod := range group.modules { - variants = append(variants, c.prettyPrintVariant(mod.variant)) + variants = append(variants, c.prettyPrintVariant(mod.variant.variations)) } for _, mod := range group.aliases { - variants = append(variants, c.prettyPrintVariant(mod.variant)+ - "(alias to "+c.prettyPrintVariant(mod.target.variant)+")") + variants = append(variants, c.prettyPrintVariant(mod.variant.variations)+ + "(alias to "+c.prettyPrintVariant(mod.target.variant.variations)+")") } sort.Strings(variants) return strings.Join(variants, "\n ") @@ -1518,18 +1552,18 @@ func (c *Context) findMatchingVariant(module *moduleInfo, possible *moduleGroup, if !reverse { // For forward dependency, ignore local variants by matching against // dependencyVariant which doesn't have the local variants - variantToMatch = module.dependencyVariant + variantToMatch = module.variant.dependencyVariations } else { // For reverse dependency, use all the variants - variantToMatch = module.variant + variantToMatch = module.variant.variations } for _, m := range possible.modules { - if m.variant.equal(variantToMatch) { + if m.variant.variations.equal(variantToMatch) { return m } } for _, m := range possible.aliases { - if m.variant.equal(variantToMatch) { + if m.variant.variations.equal(variantToMatch) { return m.target } } @@ -1563,13 +1597,13 @@ func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName s if c.allowMissingDependencies { // Allow missing variants. - return c.discoveredMissingDependencies(module, depName+c.prettyPrintVariant(module.dependencyVariant)) + return c.discoveredMissingDependencies(module, depName+c.prettyPrintVariant(module.variant.dependencyVariations)) } return []error{&BlueprintError{ Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s", depName, module.Name(), - c.prettyPrintVariant(module.dependencyVariant), + c.prettyPrintVariant(module.variant.dependencyVariations), c.prettyPrintGroupVariants(possibleDeps)), Pos: module.pos, }} @@ -1598,20 +1632,20 @@ func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*m if c.allowMissingDependencies { // Allow missing variants. - return module, c.discoveredMissingDependencies(module, destName+c.prettyPrintVariant(module.dependencyVariant)) + return module, c.discoveredMissingDependencies(module, destName+c.prettyPrintVariant(module.variant.dependencyVariations)) } return nil, []error{&BlueprintError{ Err: fmt.Errorf("reverse dependency %q of %q missing variant:\n %s\navailable variants:\n %s", destName, module.Name(), - c.prettyPrintVariant(module.dependencyVariant), + c.prettyPrintVariant(module.variant.dependencyVariations), c.prettyPrintGroupVariants(possibleDeps)), Pos: module.pos, }} } func (c *Context) findVariant(module *moduleInfo, possibleDeps *moduleGroup, variations []Variation, far bool, reverse bool) (*moduleInfo, variationMap) { - // We can't just append variant.Variant to module.dependencyVariants.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. // Create a new map instead, and then deep compare the maps. var newVariant variationMap @@ -1619,10 +1653,10 @@ func (c *Context) findVariant(module *moduleInfo, possibleDeps *moduleGroup, var if !reverse { // For forward dependency, ignore local variants by matching against // dependencyVariant which doesn't have the local variants - newVariant = module.dependencyVariant.clone() + newVariant = module.variant.dependencyVariations.clone() } else { // For reverse dependency, use all the variants - newVariant = module.variant.clone() + newVariant = module.variant.variations.clone() } } for _, v := range variations { @@ -1642,7 +1676,7 @@ func (c *Context) findVariant(module *moduleInfo, possibleDeps *moduleGroup, var var foundDep *moduleInfo for _, m := range possibleDeps.modules { - if check(m.variant) { + if check(m.variant.variations) { foundDep = m break } @@ -1650,7 +1684,7 @@ func (c *Context) findVariant(module *moduleInfo, possibleDeps *moduleGroup, var if foundDep == nil { for _, m := range possibleDeps.aliases { - if check(m.variant) { + if check(m.variant.variations) { foundDep = m.target break } @@ -2205,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, @@ -2299,12 +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{ - variantName: module.variantName, - variant: module.variant, - dependencyVariant: module.dependencyVariant, - target: module.aliasTarget, + variant: alias.fromVariant, + target: alias.target, }) } @@ -2325,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:]...) @@ -2461,7 +2505,7 @@ func (c *Context) generateModuleBuildActions(config interface{}, uniqueName := c.nameInterface.UniqueName(newNamespaceContext(module), module.group.name) sanitizedName := toNinjaName(uniqueName) - prefix := moduleNamespacePrefix(sanitizedName + "_" + module.variantName) + prefix := moduleNamespacePrefix(sanitizedName + "_" + module.variant.name) // The parent scope of the moduleContext's local scope gets overridden to be that of the // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we @@ -2675,13 +2719,13 @@ func (c *Context) moduleMatchingVariant(module *moduleInfo, name string) *module } for _, m := range group.modules { - if module.variantName == m.variantName { + if module.variant.name == m.variant.name { return m } } for _, m := range group.aliases { - if module.variantName == m.variantName { + if module.variant.name == m.variant.name { return m.target } } @@ -3053,7 +3097,7 @@ func (c *Context) ModuleDir(logicModule Module) string { func (c *Context) ModuleSubDir(logicModule Module) string { module := c.moduleInfo[logicModule] - return module.variantName + return module.variant.name } func (c *Context) ModuleType(logicModule Module) string { @@ -3499,8 +3543,8 @@ func (s depSorter) Less(i, j int) bool { iName := s[i].module.Name() jName := s[j].module.Name() if iName == jName { - iName = s[i].module.variantName - jName = s[j].module.variantName + iName = s[i].module.variant.name + jName = s[j].module.variant.name } return iName < jName } @@ -3524,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].variantName - jName = s.modules[j].variantName + 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) { @@ -3576,7 +3623,7 @@ func (c *Context) writeAllModuleActions(nw *ninjaWriter) error { "typeName": module.typeName, "goFactory": factoryName, "pos": relPos, - "variant": module.variantName, + "variant": module.variant.name, } err = headerTemplate.Execute(buf, infoMap) if err != nil { diff --git a/module_ctx.go b/module_ctx.go index 18dcdb0..28578e0 100644 --- a/module_ctx.go +++ b/module_ctx.go @@ -464,7 +464,7 @@ func (m *baseModuleContext) OtherModuleDir(logicModule Module) string { func (m *baseModuleContext) OtherModuleSubDir(logicModule Module) string { module := m.context.moduleInfo[logicModule] - return module.variantName + return module.variant.name } func (m *baseModuleContext) OtherModuleType(logicModule Module) string { @@ -655,7 +655,7 @@ func (m *baseModuleContext) ModuleFactories() map[string]ModuleFactory { } func (m *moduleContext) ModuleSubDir() string { - return m.module.variantName + return m.module.variant.name } func (m *moduleContext) Variable(pctx PackageContext, name, value string) { @@ -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,21 +908,20 @@ 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) + modules, errs := mctx.context.createVariations(mctx.module, mctx.name, mctx.defaultVariation, variationNames, local) if len(errs) > 0 { mctx.errs = append(mctx.errs, errs...) } - for i, module := range modules { + for _, module := range modules { ret = append(ret, module.logicModule) - if !local { - if module.dependencyVariant == nil { - module.dependencyVariant = make(variationMap) - } - module.dependencyVariant[mctx.name] = variationNames[i] - } } if mctx.newVariations != nil { @@ -929,24 +937,55 @@ 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[mctx.name] == variationName { - mctx.module.aliasTarget = variant + if variant.variant.variations[mctx.name] == variationName { + mctx.module.pendingAliases = append(mctx.module.pendingAliases, pendingAlias{ + fromVariant: mctx.module.variant, + target: variant, + }) return } } var foundVariations []string for _, variant := range mctx.newVariations { - foundVariations = append(foundVariations, variant.variant[mctx.name]) + foundVariations = append(foundVariations, variant.variant.variations[mctx.name]) } 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) } @@ -1023,7 +1062,7 @@ func (mctx *mutatorContext) ReplaceDependenciesIf(name string, predicate Replace if target == nil { panic(fmt.Errorf("ReplaceDependencies could not find identical variant %q for module %q", - mctx.module.variantName, name)) + mctx.module.variant.name, name)) } mctx.replace = append(mctx.replace, replace{target, mctx.module, predicate}) diff --git a/module_ctx_test.go b/module_ctx_test.go index e98ae82..22666dc 100644 --- a/module_ctx_test.go +++ b/module_ctx_test.go @@ -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) @@ -123,7 +134,7 @@ func TestAliases(t *testing.T) { foo := ctx.moduleGroupFromName("foo", nil).modules[0] barB := ctx.moduleGroupFromName("bar", nil).modules[1] - if g, w := barB.variantName, "b"; g != w { + if g, w := barB.variant.name, "b"; g != w { t.Fatalf("expected bar.modules[1] variant to be %q, got %q", w, g) } @@ -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) @@ -147,7 +158,7 @@ func TestAliases(t *testing.T) { foo := ctx.moduleGroupFromName("foo", nil).modules[0] barBB := ctx.moduleGroupFromName("bar", nil).modules[3] - if g, w := barBB.variantName, "b_b"; g != w { + if g, w := barBB.variant.name, "b_b"; g != w { t.Fatalf("expected bar.modules[3] variant to be %q, got %q", w, g) } @@ -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) @@ -171,7 +182,7 @@ func TestAliases(t *testing.T) { foo := ctx.moduleGroupFromName("foo", nil).modules[0] barAB := ctx.moduleGroupFromName("bar", nil).modules[1] - if g, w := barAB.variantName, "a_b"; g != w { + if g, w := barAB.variant.name, "a_b"; g != w { t.Fatalf("expected bar.modules[1] variant to be %q, got %q", w, g) } @@ -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) { diff --git a/splice_modules_test.go b/splice_modules_test.go index a67aeb1..059ff41 100644 --- a/splice_modules_test.go +++ b/splice_modules_test.go @@ -20,12 +20,12 @@ import ( ) var ( - testModuleA = &moduleInfo{variantName: "testModuleA"} - testModuleB = &moduleInfo{variantName: "testModuleB"} - testModuleC = &moduleInfo{variantName: "testModuleC"} - testModuleD = &moduleInfo{variantName: "testModuleD"} - testModuleE = &moduleInfo{variantName: "testModuleE"} - testModuleF = &moduleInfo{variantName: "testModuleF"} + testModuleA = &moduleInfo{variant: variant{name: "testModuleA"}} + testModuleB = &moduleInfo{variant: variant{name: "testModuleB"}} + testModuleC = &moduleInfo{variant: variant{name: "testModuleC"}} + testModuleD = &moduleInfo{variant: variant{name: "testModuleD"}} + testModuleE = &moduleInfo{variant: variant{name: "testModuleE"}} + testModuleF = &moduleInfo{variant: variant{name: "testModuleF"}} ) var spliceModulesTestCases = []struct {