Merge remote-tracking branch 'aosp/upstream' into master
* aosp/upstream:
Extract module naming into an interface
Bug: 65683273
Test: build/soong/scripts/diff_build_graphs.sh \
--products=aosp_arm \
'build/blueprint:work^ build/soong:work^' \
'build/blueprint:work build/soong:work'
# and see that the only changes were:
# 1. adding some new files
# 2. changing some line numbers
Test: m -j nothing # which runs unit tests
Change-Id: I2a2f958579fc6f96fad0eb06a5f98c93b80459b3
diff --git a/Blueprints b/Blueprints
index edda8b8..de18298 100644
--- a/Blueprints
+++ b/Blueprints
@@ -12,6 +12,7 @@
"live_tracker.go",
"mangle.go",
"module_ctx.go",
+ "name_interface.go",
"ninja_defs.go",
"ninja_strings.go",
"ninja_writer.go",
diff --git a/context.go b/context.go
index ab5efee..11bfa50 100644
--- a/context.go
+++ b/context.go
@@ -69,7 +69,7 @@
type Context struct {
// set at instantiation
moduleFactories map[string]ModuleFactory
- moduleNames map[string]*moduleGroup
+ nameInterface NameInterface
moduleGroups []*moduleGroup
moduleInfo map[Module]*moduleInfo
modulesSorted []*moduleInfo
@@ -104,8 +104,8 @@
requiredNinjaMinor int // For the ninja_required_version variable
requiredNinjaMicro int // For the ninja_required_version variable
- // set lazily by sortedModuleNames
- cachedSortedModuleNames []string
+ // set lazily by sortedModuleGroups
+ cachedSortedModuleGroups []*moduleGroup
globs map[string]GlobPath
globLock sync.Mutex
@@ -158,6 +158,8 @@
ninjaName string
modules []*moduleInfo
+
+ namespace Namespace
}
type moduleInfo struct {
@@ -211,6 +213,10 @@
return s
}
+func (module *moduleInfo) namespace() Namespace {
+ return module.group.namespace
+}
+
// A Variation is a way that a variant of a module differs from other variants of the same module.
// For example, two variants of the same module might have Variation{"arch","arm"} and
// Variation{"arch","arm64"}
@@ -270,7 +276,7 @@
func newContext() *Context {
return &Context{
moduleFactories: make(map[string]ModuleFactory),
- moduleNames: make(map[string]*moduleGroup),
+ nameInterface: NewSimpleNameInterface(),
moduleInfo: make(map[Module]*moduleInfo),
moduleNinjaNames: make(map[string]*moduleGroup),
globs: make(map[string]GlobPath),
@@ -416,6 +422,10 @@
})
}
+func (c *Context) SetNameInterface(i NameInterface) {
+ c.nameInterface = i
+}
+
func singletonPkgPath(singleton Singleton) string {
typ := reflect.TypeOf(singleton)
for typ.Kind() == reflect.Ptr {
@@ -1233,21 +1243,7 @@
name := module.logicModule.Name()
c.moduleInfo[module.logicModule] = module
- if group, present := c.moduleNames[name]; present {
- return []error{
- &BlueprintError{
- Err: fmt.Errorf("module %q already defined", name),
- Pos: module.pos,
- },
- &BlueprintError{
- Err: fmt.Errorf("<-- previous definition here"),
- Pos: group.modules[0].pos,
- },
- }
- }
-
ninjaName := toNinjaName(name)
-
// The sanitizing in toNinjaName can result in collisions, uniquify the name if it
// already exists
for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
@@ -1260,7 +1256,18 @@
modules: []*moduleInfo{module},
}
module.group = group
- c.moduleNames[name] = group
+ namespace, errs := c.nameInterface.NewModule(
+ &moduleCreationContextImpl{c.ModuleDir(module.logicModule)},
+ ModuleGroup{moduleGroup: group},
+ module.logicModule)
+ if len(errs) > 0 {
+ for i := range errs {
+ errs[i] = &BlueprintError{Err: errs[i], Pos: module.pos}
+ }
+ return errs
+ }
+ group.namespace = namespace
+
c.moduleNinjaNames[ninjaName] = group
c.moduleGroups = append(c.moduleGroups, group)
@@ -1347,17 +1354,9 @@
}}
}
- possibleDeps := c.modulesFromName(depName)
+ possibleDeps := c.modulesFromName(depName, module.namespace())
if possibleDeps == nil {
- if c.allowMissingDependencies {
- module.missingDeps = append(module.missingDeps, depName)
- return nil
- }
- return []error{&BlueprintError{
- Err: fmt.Errorf("%q depends on undefined module %q",
- module.Name(), depName),
- Pos: module.pos,
- }}
+ return c.discoveredMissingDependencies(module, depName)
}
if m := c.findMatchingVariant(module, possibleDeps); m != nil {
@@ -1395,7 +1394,7 @@
}}
}
- possibleDeps := c.modulesFromName(destName)
+ possibleDeps := c.modulesFromName(destName, module.namespace())
if possibleDeps == nil {
return nil, []error{&BlueprintError{
Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
@@ -1429,17 +1428,9 @@
panic("BaseDependencyTag is not allowed to be used directly!")
}
- possibleDeps := c.modulesFromName(depName)
+ possibleDeps := c.modulesFromName(depName, module.namespace())
if possibleDeps == nil {
- if c.allowMissingDependencies {
- module.missingDeps = append(module.missingDeps, depName)
- return nil
- }
- return []error{&BlueprintError{
- Err: fmt.Errorf("%q depends on undefined module %q",
- module.Name(), depName),
- Pos: module.pos,
- }}
+ return c.discoveredMissingDependencies(module, depName)
}
// We can't just append variant.Variant to module.dependencyVariants.variantName and
@@ -2190,11 +2181,7 @@
if module.missingDeps != nil && !mctx.handledMissingDeps {
var errs []error
for _, depName := range module.missingDeps {
- errs = append(errs, &BlueprintError{
- Err: fmt.Errorf("%q depends on undefined module %q",
- module.Name(), depName),
- Pos: module.pos,
- })
+ errs = append(errs, c.missingDependencyError(module, depName))
}
errsCh <- errs
return true
@@ -2359,7 +2346,7 @@
}
func (c *Context) moduleMatchingVariant(module *moduleInfo, name string) *moduleInfo {
- targets := c.modulesFromName(name)
+ targets := c.modulesFromName(name, module.namespace())
if targets == nil {
return nil
@@ -2378,29 +2365,11 @@
var errs []error
for _, rename := range renames {
group, name := rename.group, rename.name
- if name == group.name {
+ if name == group.name || len(group.modules) < 1 {
continue
}
- existing := c.moduleNames[name]
- if existing != nil {
- errs = append(errs,
- &BlueprintError{
- Err: fmt.Errorf("renaming module %q to %q conflicts with existing module",
- group.name, name),
- Pos: group.modules[0].pos,
- },
- &BlueprintError{
- Err: fmt.Errorf("<-- existing module defined here"),
- Pos: existing.modules[0].pos,
- },
- )
- continue
- }
-
- c.moduleNames[name] = group
- delete(c.moduleNames, group.name)
- group.name = name
+ errs = append(errs, c.nameInterface.Rename(group.name, rename.name, group.namespace)...)
}
return errs
@@ -2423,24 +2392,45 @@
return errs
}
-func (c *Context) modulesFromName(name string) []*moduleInfo {
- if group := c.moduleNames[name]; group != nil {
+func (c *Context) discoveredMissingDependencies(module *moduleInfo, depName string) (errs []error) {
+ if c.allowMissingDependencies {
+ module.missingDeps = append(module.missingDeps, depName)
+ return nil
+ }
+ return []error{c.missingDependencyError(module, depName)}
+}
+
+func (c *Context) missingDependencyError(module *moduleInfo, depName string) (errs error) {
+ err := c.nameInterface.MissingDependencyError(module.Name(), module.namespace(), depName)
+
+ return &BlueprintError{
+ Err: err,
+ Pos: module.pos,
+ }
+}
+
+func (c *Context) modulesFromName(name string, namespace Namespace) []*moduleInfo {
+ group, exists := c.nameInterface.ModuleFromName(name, namespace)
+ if exists {
return group.modules
}
return nil
}
-func (c *Context) sortedModuleNames() []string {
- if c.cachedSortedModuleNames == nil {
- c.cachedSortedModuleNames = make([]string, 0, len(c.moduleNames))
- for moduleName := range c.moduleNames {
- c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
- moduleName)
+func (c *Context) sortedModuleGroups() []*moduleGroup {
+ if c.cachedSortedModuleGroups == nil {
+ unwrap := func(wrappers []ModuleGroup) []*moduleGroup {
+ result := make([]*moduleGroup, 0, len(wrappers))
+ for _, group := range wrappers {
+ result = append(result, group.moduleGroup)
+ }
+ return result
}
- sort.Strings(c.cachedSortedModuleNames)
+
+ c.cachedSortedModuleGroups = unwrap(c.nameInterface.AllModules())
}
- return c.cachedSortedModuleNames
+ return c.cachedSortedModuleGroups
}
func (c *Context) visitAllModules(visit func(Module)) {
@@ -2453,9 +2443,8 @@
}
}()
- for _, moduleName := range c.sortedModuleNames() {
- modules := c.modulesFromName(moduleName)
- for _, module = range modules {
+ for _, moduleGroup := range c.sortedModuleGroups() {
+ for _, module = range moduleGroup.modules {
visit(module.logicModule)
}
}
@@ -2473,9 +2462,8 @@
}
}()
- for _, moduleName := range c.sortedModuleNames() {
- modules := c.modulesFromName(moduleName)
- for _, module := range modules {
+ for _, moduleGroup := range c.sortedModuleGroups() {
+ for _, module := range moduleGroup.modules {
if pred(module.logicModule) {
visit(module.logicModule)
}
diff --git a/context_test.go b/context_test.go
index c6bc08c..16c52cf 100644
--- a/context_test.go
+++ b/context_test.go
@@ -183,7 +183,7 @@
var outputDown string
var outputUp string
- topModule := ctx.modulesFromName("A")[0]
+ topModule := ctx.modulesFromName("A", nil)[0]
ctx.walkDeps(topModule,
func(dep depInfo, parent *moduleInfo) bool {
if dep.module.logicModule.(Walker).Walk() {
@@ -239,10 +239,10 @@
t.FailNow()
}
- a := ctx.modulesFromName("A")[0].logicModule.(*fooModule)
- b := ctx.modulesFromName("B")[0].logicModule.(*barModule)
- c := ctx.modulesFromName("C")[0].logicModule.(*barModule)
- d := ctx.modulesFromName("D")[0].logicModule.(*fooModule)
+ 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)
checkDeps := func(m Module, expected string) {
var deps []string
diff --git a/module_ctx.go b/module_ctx.go
index 630d7a2..769c59a 100644
--- a/module_ctx.go
+++ b/module_ctx.go
@@ -142,6 +142,8 @@
moduleInfo() *moduleInfo
error(err error)
+
+ Namespace() Namespace
}
type DynamicDependerModuleContext BottomUpMutatorContext
@@ -269,6 +271,10 @@
return d.context.fs
}
+func (d *baseModuleContext) Namespace() Namespace {
+ return d.context.nameInterface.GetNamespace(d)
+}
+
var _ ModuleContext = (*moduleContext)(nil)
type moduleContext struct {
@@ -650,7 +656,8 @@
// correctly for all future mutator passes.
func (mctx *mutatorContext) AddDependency(module Module, tag DependencyTag, deps ...string) {
for _, dep := range deps {
- errs := mctx.context.addDependency(mctx.context.moduleInfo[module], tag, dep)
+ modInfo := mctx.context.moduleInfo[module]
+ errs := mctx.context.addDependency(modInfo, tag, dep)
if len(errs) > 0 {
mctx.errs = append(mctx.errs, errs...)
}
@@ -731,7 +738,8 @@
}
func (mctx *mutatorContext) OtherModuleExists(name string) bool {
- return mctx.context.moduleNames[name] != nil
+ _, exists := mctx.context.nameInterface.ModuleFromName(name, mctx.module.namespace())
+ return exists
}
// Rename all variants of a module. The new name is not visible to calls to ModuleName,
diff --git a/name_interface.go b/name_interface.go
new file mode 100644
index 0000000..b3a1566
--- /dev/null
+++ b/name_interface.go
@@ -0,0 +1,167 @@
+// Copyright 2017 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 (
+ "fmt"
+ "sort"
+)
+
+// This file exposes the logic of locating a module via a query string, to enable
+// other projects to override it if desired.
+// The default name resolution implementation, SimpleNameInterface,
+// just treats the query string as a module name, and does a simple map lookup.
+
+// A ModuleGroup just points to a moduleGroup to allow external packages to refer
+// to a moduleGroup but not use it
+type ModuleGroup struct {
+ *moduleGroup
+}
+
+func (h *ModuleGroup) String() string {
+ return h.moduleGroup.name
+}
+
+// The Namespace interface is just a marker interface for usage by the NameInterface,
+// to allow a NameInterface to specify that a certain parameter should be a Namespace.
+// In practice, a specific NameInterface will expect to only give and receive structs of
+// the same concrete type, but because Go doesn't support generics, we use a marker interface
+// for a little bit of clarity, and expect implementers to do typecasting instead.
+type Namespace interface {
+ namespace(Namespace)
+}
+type NamespaceMarker struct {
+}
+
+func (m *NamespaceMarker) namespace(Namespace) {
+}
+
+// A NameInterface tells how to locate modules by name.
+// There should only be one name interface per Context, but potentially many namespaces
+type NameInterface interface {
+ // Gets called when a new module is created
+ NewModule(ctx NamespaceContext, group ModuleGroup, module Module) (namespace Namespace, err []error)
+
+ // Finds the module with the given name
+ ModuleFromName(moduleName string, namespace Namespace) (group ModuleGroup, found bool)
+
+ // Returns an error indicating that the given module could not be found.
+ // The error contains some diagnostic information about where the dependency can be found.
+ MissingDependencyError(depender string, dependerNamespace Namespace, depName string) (err error)
+
+ // Rename
+ Rename(oldName string, newName string, namespace Namespace) []error
+
+ // Returns all modules in a deterministic order.
+ AllModules() []ModuleGroup
+
+ // gets the namespace for a given path
+ GetNamespace(ctx NamespaceContext) (namespace Namespace)
+}
+
+// A NamespaceContext stores the information given to a NameInterface to enable the NameInterface
+// to choose the namespace for any given module
+type NamespaceContext interface {
+ ModuleDir() string
+}
+
+type moduleCreationContextImpl struct {
+ moduleDir string
+}
+
+func (ctx *moduleCreationContextImpl) ModuleDir() string {
+ return ctx.moduleDir
+}
+
+// a SimpleNameInterface just stores all modules in a map based on name
+type SimpleNameInterface struct {
+ modules map[string]ModuleGroup
+}
+
+func NewSimpleNameInterface() *SimpleNameInterface {
+ return &SimpleNameInterface{
+ modules: make(map[string]ModuleGroup),
+ }
+}
+
+func (s *SimpleNameInterface) NewModule(ctx NamespaceContext, group ModuleGroup, module Module) (namespace Namespace, err []error) {
+ name := group.name
+ if group, present := s.modules[name]; present {
+ return nil, []error{
+ // seven characters at the start of the second line to align with the string "error: "
+ fmt.Errorf("module %q already defined\n"+
+ " %s <-- previous definition here", name, group.modules[0].pos),
+ }
+ }
+
+ s.modules[name] = group
+
+ return nil, []error{}
+}
+
+func (s *SimpleNameInterface) ModuleFromName(moduleName string, namespace Namespace) (group ModuleGroup, found bool) {
+ group, found = s.modules[moduleName]
+ return group, found
+}
+
+func (s *SimpleNameInterface) Rename(oldName string, newName string, namespace Namespace) (errs []error) {
+ existingGroup, exists := s.modules[newName]
+ if exists {
+ errs = append(errs,
+ // seven characters at the start of the second line to align with the string "error: "
+ fmt.Errorf("renaming module %q to %q conflicts with existing module\n"+
+ " %s <-- existing module defined here",
+ oldName, newName, existingGroup.modules[0].pos),
+ )
+ return errs
+ }
+
+ group := s.modules[oldName]
+ s.modules[newName] = group
+ delete(s.modules, group.name)
+ group.name = newName
+ return []error{}
+}
+
+func (s *SimpleNameInterface) AllModules() []ModuleGroup {
+ groups := make([]ModuleGroup, 0, len(s.modules))
+ for _, group := range s.modules {
+ groups = append(groups, group)
+ }
+
+ duplicateName := ""
+ less := func(i, j int) bool {
+ if groups[i].name == groups[j].name {
+ duplicateName = groups[i].name
+ }
+ return groups[i].name < groups[j].name
+ }
+ sort.Slice(groups, less)
+ if duplicateName != "" {
+ // It is permitted to have two moduleGroup's with the same name, but not within the same
+ // Namespace. The SimpleNameInterface should catch this in NewModule, however, so this
+ // should never happen.
+ panic(fmt.Sprintf("Duplicate moduleGroup name %q", duplicateName))
+ }
+ return groups
+}
+
+func (s *SimpleNameInterface) MissingDependencyError(depender string, dependerNamespace Namespace, dependency string) (err error) {
+ return fmt.Errorf("%q depends on undefined module %q", depender, dependency)
+}
+
+func (s *SimpleNameInterface) GetNamespace(ctx NamespaceContext) Namespace {
+ return nil
+}
diff --git a/visit_test.go b/visit_test.go
index d423c7a..3aa0f1b 100644
--- a/visit_test.go
+++ b/visit_test.go
@@ -141,7 +141,7 @@
func TestVisit(t *testing.T) {
ctx := setupVisitTest(t)
- topModule := ctx.modulesFromName("A")[0].logicModule.(*visitModule)
+ topModule := ctx.modulesFromName("A", nil)[0].logicModule.(*visitModule)
assertString(t, topModule.properties.VisitDepsDepthFirst, "EDCB")
assertString(t, topModule.properties.VisitDepsDepthFirstIf, "EDC")
assertString(t, topModule.properties.VisitDirectDeps, "B")