Merge remote-tracking branch 'upstream/master' into merge am: 24f0b26d90

am: 792b384412

Change-Id: I094a649a4d27a95558e15efdd3d57eed38670f95
This commit is contained in:
Jaewoong Jung 2019-11-15 11:20:20 -08:00 committed by android-build-merger
commit a67e7d88d2
6 changed files with 362 additions and 71 deletions

View file

@ -24,6 +24,7 @@ bootstrap_go_package {
testSrcs: [
"context_test.go",
"glob_test.go",
"module_ctx_test.go",
"ninja_strings_test.go",
"ninja_writer_test.go",
"splice_modules_test.go",

View file

@ -157,11 +157,19 @@ type localBuildActions struct {
buildDefs []*buildDef
}
type moduleAlias struct {
variantName string
variant variationMap
dependencyVariant variationMap
target *moduleInfo
}
type moduleGroup struct {
name string
ninjaName string
modules []*moduleInfo
aliases []*moduleAlias
namespace Namespace
}
@ -197,6 +205,7 @@ type moduleInfo struct {
// set during each runMutator
splitModules []*moduleInfo
aliasTarget *moduleInfo
// set during PrepareBuildActions
actionDefs localBuildActions
@ -242,6 +251,9 @@ type Variation struct {
type variationMap map[string]string
func (vm variationMap) clone() variationMap {
if vm == nil {
return nil
}
newVm := make(variationMap)
for k, v := range vm {
newVm[k] = v
@ -1178,6 +1190,9 @@ func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
}
newVariant := origModule.variant.clone()
if newVariant == nil {
newVariant = make(variationMap)
}
newVariant[mutatorName] = variationName
m := *origModule
@ -1261,6 +1276,19 @@ func (c *Context) prettyPrintVariant(variant variationMap) string {
return strings.Join(names, ", ")
}
func (c *Context) prettyPrintGroupVariants(group *moduleGroup) string {
var variants []string
for _, mod := range group.modules {
variants = append(variants, c.prettyPrintVariant(mod.variant))
}
for _, mod := range group.aliases {
variants = append(variants, c.prettyPrintVariant(mod.variant)+
"(alias to "+c.prettyPrintVariant(mod.target.variant)+")")
}
sort.Strings(variants)
return strings.Join(variants, "\n ")
}
func (c *Context) newModule(factory ModuleFactory) *moduleInfo {
logicModule, properties := factory()
@ -1410,9 +1438,9 @@ func blueprintDepsMutator(ctx BottomUpMutatorContext) {
// findMatchingVariant searches the moduleGroup for a module with the same variant as module,
// and returns the matching module, or nil if one is not found.
func (c *Context) findMatchingVariant(module *moduleInfo, possible []*moduleInfo, reverse bool) *moduleInfo {
if len(possible) == 1 {
return possible[0]
func (c *Context) findMatchingVariant(module *moduleInfo, possible *moduleGroup, reverse bool) *moduleInfo {
if len(possible.modules) == 1 {
return possible.modules[0]
} else {
var variantToMatch variationMap
if !reverse {
@ -1423,11 +1451,16 @@ func (c *Context) findMatchingVariant(module *moduleInfo, possible []*moduleInfo
// For reverse dependency, use all the variants
variantToMatch = module.variant
}
for _, m := range possible {
for _, m := range possible.modules {
if m.variant.equal(variantToMatch) {
return m
}
}
for _, m := range possible.aliases {
if m.variant.equal(variantToMatch) {
return m.target
}
}
}
return nil
@ -1445,7 +1478,7 @@ func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName s
}}
}
possibleDeps := c.modulesFromName(depName, module.namespace())
possibleDeps := c.moduleGroupFromName(depName, module.namespace())
if possibleDeps == nil {
return c.discoveredMissingDependencies(module, depName)
}
@ -1456,17 +1489,11 @@ func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName s
return nil
}
variants := make([]string, len(possibleDeps))
for i, mod := range possibleDeps {
variants[i] = c.prettyPrintVariant(mod.variant)
}
sort.Strings(variants)
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),
strings.Join(variants, "\n ")),
c.prettyPrintGroupVariants(possibleDeps)),
Pos: module.pos,
}}
}
@ -1479,7 +1506,7 @@ func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*m
}}
}
possibleDeps := c.modulesFromName(destName, module.namespace())
possibleDeps := c.moduleGroupFromName(destName, module.namespace())
if possibleDeps == nil {
return nil, []error{&BlueprintError{
Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
@ -1492,17 +1519,11 @@ func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*m
return m, nil
}
variants := make([]string, len(possibleDeps))
for i, mod := range possibleDeps {
variants[i] = c.prettyPrintVariant(mod.variant)
}
sort.Strings(variants)
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),
strings.Join(variants, "\n ")),
c.prettyPrintGroupVariants(possibleDeps)),
Pos: module.pos,
}}
}
@ -1513,7 +1534,7 @@ func (c *Context) addVariationDependency(module *moduleInfo, variations []Variat
panic("BaseDependencyTag is not allowed to be used directly!")
}
possibleDeps := c.modulesFromName(depName, module.namespace())
possibleDeps := c.moduleGroupFromName(depName, module.namespace())
if possibleDeps == nil {
return c.discoveredMissingDependencies(module, depName)
}
@ -1524,55 +1545,67 @@ func (c *Context) addVariationDependency(module *moduleInfo, variations []Variat
var newVariant variationMap
if !far {
newVariant = module.dependencyVariant.clone()
} else {
newVariant = make(variationMap)
}
for _, v := range variations {
if newVariant == nil {
newVariant = make(variationMap)
}
newVariant[v.Mutator] = v.Variation
}
for _, m := range possibleDeps {
var found bool
check := func(variant variationMap) bool {
if far {
found = m.variant.subset(newVariant)
return variant.subset(newVariant)
} else {
found = m.variant.equal(newVariant)
}
if found {
if module == m {
return []error{&BlueprintError{
Err: fmt.Errorf("%q depends on itself", depName),
Pos: module.pos,
}}
}
// AddVariationDependency allows adding a dependency on itself, but only if
// that module is earlier in the module list than this one, since we always
// run GenerateBuildActions in order for the variants of a module
if m.group == module.group && beforeInModuleList(module, m, module.group.modules) {
return []error{&BlueprintError{
Err: fmt.Errorf("%q depends on later version of itself", depName),
Pos: module.pos,
}}
}
module.newDirectDeps = append(module.newDirectDeps, depInfo{m, tag})
atomic.AddUint32(&c.depsModified, 1)
return nil
return variant.equal(newVariant)
}
}
variants := make([]string, len(possibleDeps))
for i, mod := range possibleDeps {
variants[i] = c.prettyPrintVariant(mod.variant)
var foundDep *moduleInfo
for _, m := range possibleDeps.modules {
if check(m.variant) {
foundDep = m
break
}
}
sort.Strings(variants)
return []error{&BlueprintError{
Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
depName, module.Name(),
c.prettyPrintVariant(newVariant),
strings.Join(variants, "\n ")),
Pos: module.pos,
}}
if foundDep == nil {
for _, m := range possibleDeps.aliases {
if check(m.variant) {
foundDep = m.target
break
}
}
}
if foundDep == nil {
return []error{&BlueprintError{
Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
depName, module.Name(),
c.prettyPrintVariant(newVariant),
c.prettyPrintGroupVariants(possibleDeps)),
Pos: module.pos,
}}
}
if module == foundDep {
return []error{&BlueprintError{
Err: fmt.Errorf("%q depends on itself", depName),
Pos: module.pos,
}}
}
// AddVariationDependency allows adding a dependency on itself, but only if
// that module is earlier in the module list than this one, since we always
// run GenerateBuildActions in order for the variants of a module
if foundDep.group == module.group && beforeInModuleList(module, foundDep, module.group.modules) {
return []error{&BlueprintError{
Err: fmt.Errorf("%q depends on later version of itself", depName),
Pos: module.pos,
}}
}
module.newDirectDeps = append(module.newDirectDeps, depInfo{foundDep, tag})
atomic.AddUint32(&c.depsModified, 1)
return nil
}
func (c *Context) addInterVariantDependency(origModule *moduleInfo, tag DependencyTag,
@ -2166,6 +2199,16 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
group.modules, i = spliceModules(group.modules, i, module.splitModules)
}
// Create any new aliases.
if module.aliasTarget != nil {
group.aliases = append(group.aliases, &moduleAlias{
variantName: module.variantName,
variant: module.variant,
dependencyVariant: module.dependencyVariant,
target: module.aliasTarget,
})
}
// Fix up any remaining dependencies on modules that were split into variants
// by replacing them with the first variant
for j, dep := range module.directDeps {
@ -2182,6 +2225,21 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
module.directDeps = append(module.directDeps, module.newDirectDeps...)
module.newDirectDeps = 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
} else {
// The alias was left dangling, remove it.
group.aliases = append(group.aliases[:i], group.aliases[i+1:]...)
i--
}
}
}
}
// Add in any new reverse dependencies that were added by the mutator
@ -2510,18 +2568,24 @@ type rename struct {
}
func (c *Context) moduleMatchingVariant(module *moduleInfo, name string) *moduleInfo {
targets := c.modulesFromName(name, module.namespace())
group := c.moduleGroupFromName(name, module.namespace())
if targets == nil {
if group == nil {
return nil
}
for _, m := range targets {
for _, m := range group.modules {
if module.variantName == m.variantName {
return m
}
}
for _, m := range group.aliases {
if module.variantName == m.variantName {
return m.target
}
}
return nil
}
@ -2573,10 +2637,10 @@ func (c *Context) missingDependencyError(module *moduleInfo, depName string) (er
}
}
func (c *Context) modulesFromName(name string, namespace Namespace) []*moduleInfo {
func (c *Context) moduleGroupFromName(name string, namespace Namespace) *moduleGroup {
group, exists := c.nameInterface.ModuleFromName(name, namespace)
if exists {
return group.modules
return group.moduleGroup
}
return nil
}

View file

@ -188,7 +188,7 @@ func TestWalkDeps(t *testing.T) {
var outputDown string
var outputUp string
topModule := ctx.modulesFromName("A", nil)[0]
topModule := ctx.moduleGroupFromName("A", nil).modules[0]
ctx.walkDeps(topModule, false,
func(dep depInfo, parent *moduleInfo) bool {
outputDown += ctx.ModuleName(dep.module.logicModule)
@ -280,7 +280,7 @@ func TestWalkDepsDuplicates(t *testing.T) {
var outputDown string
var outputUp string
topModule := ctx.modulesFromName("A", nil)[0]
topModule := ctx.moduleGroupFromName("A", nil).modules[0]
ctx.walkDeps(topModule, true,
func(dep depInfo, parent *moduleInfo) bool {
outputDown += ctx.ModuleName(dep.module.logicModule)
@ -334,10 +334,10 @@ func TestCreateModule(t *testing.T) {
t.FailNow()
}
a := ctx.modulesFromName("A", nil)[0].logicModule.(*fooModule)
b := ctx.modulesFromName("B", nil)[0].logicModule.(*barModule)
c := ctx.modulesFromName("C", nil)[0].logicModule.(*barModule)
d := ctx.modulesFromName("D", nil)[0].logicModule.(*fooModule)
a := ctx.moduleGroupFromName("A", nil).modules[0].logicModule.(*fooModule)
b := ctx.moduleGroupFromName("B", nil).modules[0].logicModule.(*barModule)
c := ctx.moduleGroupFromName("C", nil).modules[0].logicModule.(*barModule)
d := ctx.moduleGroupFromName("D", nil).modules[0].logicModule.(*fooModule)
checkDeps := func(m Module, expected string) {
var deps []string

View file

@ -785,6 +785,13 @@ type BottomUpMutatorContext interface {
// specified name with the current variant of this module. Replacements don't take effect until
// after the mutator pass is finished.
ReplaceDependencies(string)
// 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(variationName string)
}
// A Mutator function is called for each Module, and can use
@ -838,6 +845,9 @@ func (mctx *mutatorContext) createVariations(variationNames []string, local bool
for i, module := range modules {
ret = append(ret, module.logicModule)
if !local {
if module.dependencyVariant == nil {
module.dependencyVariant = make(variationMap)
}
module.dependencyVariant[mctx.name] = variationNames[i]
}
}
@ -854,6 +864,25 @@ func (mctx *mutatorContext) createVariations(variationNames []string, local bool
return ret
}
func (mctx *mutatorContext) AliasVariation(variationName string) {
if mctx.module.aliasTarget != nil {
panic(fmt.Errorf("AliasVariation already called"))
}
for _, variant := range mctx.newVariations {
if variant.variant[mctx.name] == variationName {
mctx.module.aliasTarget = variant
return
}
}
var foundVariations []string
for _, variant := range mctx.newVariations {
foundVariations = append(foundVariations, variant.variant[mctx.name])
}
panic(fmt.Errorf("no %q variation in module variations %q", variationName, foundVariations))
}
func (mctx *mutatorContext) SetDependencyVariation(variationName string) {
mctx.context.convertDepsToVariation(mctx.module, mctx.name, variationName, nil)
}

197
module_ctx_test.go Normal file
View file

@ -0,0 +1,197 @@
// Copyright 2019 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package blueprint
import (
"reflect"
"strings"
"testing"
)
type moduleCtxTestModule struct {
SimpleName
}
func newModuleCtxTestModule() (Module, []interface{}) {
m := &moduleCtxTestModule{}
return m, []interface{}{&m.SimpleName.Properties}
}
func (f *moduleCtxTestModule) GenerateBuildActions(ModuleContext) {
}
func noCreateAliasMutator(name string) func(ctx BottomUpMutatorContext) {
return func(ctx BottomUpMutatorContext) {
if ctx.ModuleName() == name {
ctx.CreateVariations("a", "b")
}
}
}
func createAliasMutator(name string) func(ctx BottomUpMutatorContext) {
return func(ctx BottomUpMutatorContext) {
if ctx.ModuleName() == name {
ctx.CreateVariations("a", "b")
ctx.AliasVariation("b")
}
}
}
func addVariantDepsMutator(variants []Variation, tag DependencyTag, from, to string) func(ctx BottomUpMutatorContext) {
return func(ctx BottomUpMutatorContext) {
if ctx.ModuleName() == from {
ctx.AddVariationDependencies(variants, tag, to)
}
}
}
func TestAliases(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"})
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 "" -> "b".
// Tests a dependency from "foo" to "bar" variant "b" through alias "".
ctx := NewContext()
ctx.RegisterModuleType("test", newModuleCtxTestModule)
ctx.RegisterBottomUpMutator("1", createAliasMutator("bar"))
ctx.RegisterBottomUpMutator("2", addVariantDepsMutator(nil, nil, "foo", "bar"))
run(ctx)
foo := ctx.moduleGroupFromName("foo", nil).modules[0]
barB := ctx.moduleGroupFromName("bar", nil).modules[1]
if g, w := barB.variantName, "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 "" -> "b_b",
// "a" -> "a_b", and "b" -> "b_b".
// 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("3", addVariantDepsMutator(nil, nil, "foo", "bar"))
run(ctx)
foo := ctx.moduleGroupFromName("foo", nil).modules[0]
barBB := ctx.moduleGroupFromName("bar", nil).modules[3]
if g, w := barBB.variantName, "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("chained2", func(t *testing.T) {
// Creates a module "bar" with variants "a_a", "a_b", "b_a" and "b_b" and aliases "" -> "b_b",
// "a" -> "a_b", and "b" -> "b_b".
// 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("3", addVariantDepsMutator([]Variation{{"1", "a"}}, nil, "foo", "bar"))
run(ctx)
foo := ctx.moduleGroupFromName("foo", nil).modules[0]
barAB := ctx.moduleGroupFromName("bar", nil).modules[1]
if g, w := barAB.variantName, "a_b"; g != w {
t.Fatalf("expected bar.modules[1] variant to be %q, got %q", w, g)
}
if g, w := foo.forwardDeps, []*moduleInfo{barAB}; !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 aliases "" -> "b", 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 "" fails.
ctx := NewContext()
ctx.RegisterModuleType("test", newModuleCtxTestModule)
ctx.RegisterBottomUpMutator("1", createAliasMutator("bar"))
ctx.RegisterBottomUpMutator("2", noCreateAliasMutator("bar"))
ctx.RegisterBottomUpMutator("3", addVariantDepsMutator(nil, nil, "foo", "bar"))
runWithFailures(ctx, `dependency "bar" of "foo" missing variant:`+"\n \n"+
"available variants:"+
"\n 1:a, 2:a\n 1:a, 2:b\n 1:b, 2:a\n 1:b, 2:b")
})
}

View file

@ -149,13 +149,13 @@ func setupVisitTest(t *testing.T) *Context {
func TestVisit(t *testing.T) {
ctx := setupVisitTest(t)
topModule := ctx.modulesFromName("A", nil)[0].logicModule.(*visitModule)
topModule := ctx.moduleGroupFromName("A", nil).modules[0].logicModule.(*visitModule)
assertString(t, topModule.properties.VisitDepsDepthFirst, "FEDCB")
assertString(t, topModule.properties.VisitDepsDepthFirstIf, "FEDC")
assertString(t, topModule.properties.VisitDirectDeps, "B")
assertString(t, topModule.properties.VisitDirectDepsIf, "")
eModule := ctx.modulesFromName("E", nil)[0].logicModule.(*visitModule)
eModule := ctx.moduleGroupFromName("E", nil).modules[0].logicModule.(*visitModule)
assertString(t, eModule.properties.VisitDepsDepthFirst, "F")
assertString(t, eModule.properties.VisitDepsDepthFirstIf, "F")
assertString(t, eModule.properties.VisitDirectDeps, "FF")