Revert "Revert "Soong support for namespaces""

This mostly reverts commit 178d5fefc0cea9d0f031c0bdee125b9d960f32c3
and mostly reapplies change I6d3e52ef62c4cabe85b9a135a54de0e1a6aab29c .

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: I32baae00277a547fdcdd1c2219fe6625ee0e45d7
diff --git a/android/namespace.go b/android/namespace.go
new file mode 100644
index 0000000..a2ff1a6
--- /dev/null
+++ b/android/namespace.go
@@ -0,0 +1,398 @@
+// 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 android
+
+import (
+	"fmt"
+	"path/filepath"
+	"sort"
+	"strconv"
+	"strings"
+	"sync"
+	"sync/atomic"
+
+	"github.com/google/blueprint"
+)
+
+// This file implements namespaces
+const (
+	namespacePrefix = "//"
+	modulePrefix    = ":"
+)
+
+func init() {
+	RegisterModuleType("soong_namespace", NamespaceFactory)
+}
+
+// threadsafe sorted list
+type sortedNamespaces struct {
+	lock   sync.Mutex
+	items  []*Namespace
+	sorted bool
+}
+
+func (s *sortedNamespaces) add(namespace *Namespace) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+	if s.sorted {
+		panic("It is not supported to call sortedNamespaces.add() after sortedNamespaces.sortedItems()")
+	}
+	s.items = append(s.items, namespace)
+}
+
+func (s *sortedNamespaces) sortedItems() []*Namespace {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+	if !s.sorted {
+		less := func(i int, j int) bool {
+			return s.items[i].Path < s.items[j].Path
+		}
+		sort.Slice(s.items, less)
+		s.sorted = true
+	}
+	return s.items
+}
+
+// A NameResolver implements blueprint.NameInterface, and implements the logic to
+// find a module from namespaces based on a query string.
+// A query string can be a module name or can be be "//namespace_path:module_path"
+type NameResolver struct {
+	rootNamespace *Namespace
+
+	// id counter for atomic.AddInt32
+	numNamespaces int32
+
+	// All namespaces, without duplicates.
+	sortedNamespaces sortedNamespaces
+
+	// Map from dir to namespace. Will have duplicates if two dirs are part of the same namespace.
+	namespacesByDir sync.Map // if generics were supported, this would be sync.Map[string]*Namespace
+
+	// func telling whether to export a namespace to Kati
+	namespaceExportFilter func(*Namespace) bool
+}
+
+func NewNameResolver(namespaceExportFilter func(*Namespace) bool) *NameResolver {
+	namespacesByDir := sync.Map{}
+
+	r := &NameResolver{
+		namespacesByDir:       namespacesByDir,
+		namespaceExportFilter: namespaceExportFilter,
+	}
+	r.rootNamespace = r.newNamespace(".")
+	r.rootNamespace.visibleNamespaces = []*Namespace{r.rootNamespace}
+	r.addNamespace(r.rootNamespace)
+
+	return r
+}
+
+func (r *NameResolver) newNamespace(path string) *Namespace {
+	namespace := NewNamespace(path)
+
+	namespace.exportToKati = r.namespaceExportFilter(namespace)
+
+	nextId := atomic.AddInt32(&r.numNamespaces, 1)
+	id := nextId - 1
+	stringId := ""
+	if id > 0 {
+		stringId = strconv.Itoa(int(id))
+	}
+	namespace.id = stringId
+
+	return namespace
+}
+
+func (r *NameResolver) addNewNamespaceForModule(module *NamespaceModule, dir string) error {
+	namespace := r.newNamespace(dir)
+	module.namespace = namespace
+	module.resolver = r
+	namespace.importedNamespaceNames = module.properties.Imports
+	return r.addNamespace(namespace)
+}
+
+func (r *NameResolver) addNamespace(namespace *Namespace) (err error) {
+	existingNamespace, exists := r.namespaceAt(namespace.Path)
+	if exists {
+		if existingNamespace.Path == namespace.Path {
+			return fmt.Errorf("namespace %v already exists", namespace.Path)
+		} else {
+			// It would probably confuse readers if namespaces were declared anywhere but
+			// the top of the file, so we forbid declaring namespaces after anything else.
+			return fmt.Errorf("a namespace must be the first module in the file")
+		}
+	}
+	r.sortedNamespaces.add(namespace)
+
+	r.namespacesByDir.Store(namespace.Path, namespace)
+	return nil
+}
+
+// non-recursive check for namespace
+func (r *NameResolver) namespaceAt(path string) (namespace *Namespace, found bool) {
+	mapVal, found := r.namespacesByDir.Load(path)
+	if !found {
+		return nil, false
+	}
+	return mapVal.(*Namespace), true
+}
+
+// recursive search upward for a namespace
+func (r *NameResolver) findNamespace(path string) (namespace *Namespace) {
+	namespace, found := r.namespaceAt(path)
+	if found {
+		return namespace
+	}
+	parentDir := filepath.Dir(path)
+	if parentDir == path {
+		return nil
+	}
+	namespace = r.findNamespace(parentDir)
+	r.namespacesByDir.Store(path, namespace)
+	return namespace
+}
+
+func (r *NameResolver) NewModule(ctx blueprint.NamespaceContext, moduleGroup blueprint.ModuleGroup, module blueprint.Module) (namespace blueprint.Namespace, errs []error) {
+	// if this module is a namespace, then save it to our list of namespaces
+	newNamespace, ok := module.(*NamespaceModule)
+	if ok {
+		err := r.addNewNamespaceForModule(newNamespace, ctx.ModuleDir())
+		if err != nil {
+			return nil, []error{err}
+		}
+		return nil, nil
+	}
+
+	// if this module is not a namespace, then save it into the appropriate namespace
+	ns := r.findNamespaceFromCtx(ctx)
+
+	_, errs = ns.moduleContainer.NewModule(ctx, moduleGroup, module)
+	if len(errs) > 0 {
+		return nil, errs
+	}
+
+	amod, ok := module.(Module)
+	if ok {
+		// inform the module whether its namespace is one that we want to export to Make
+		amod.base().commonProperties.NamespaceExportedToMake = ns.exportToKati
+	}
+
+	return ns, nil
+}
+
+func (r *NameResolver) AllModules() []blueprint.ModuleGroup {
+	childLists := [][]blueprint.ModuleGroup{}
+	totalCount := 0
+	for _, namespace := range r.sortedNamespaces.sortedItems() {
+		newModules := namespace.moduleContainer.AllModules()
+		totalCount += len(newModules)
+		childLists = append(childLists, newModules)
+	}
+
+	allModules := make([]blueprint.ModuleGroup, 0, totalCount)
+	for _, childList := range childLists {
+		allModules = append(allModules, childList...)
+	}
+	return allModules
+}
+
+// parses a fully-qualified path (like "//namespace_path:module_name") into a namespace name and a
+// module name
+func (r *NameResolver) parseFullyQualifiedName(name string) (namespaceName string, moduleName string, ok bool) {
+	if !strings.HasPrefix(name, namespacePrefix) {
+		return "", "", false
+	}
+	name = strings.TrimPrefix(name, namespacePrefix)
+	components := strings.Split(name, modulePrefix)
+	if len(components) != 2 {
+		return "", "", false
+	}
+	return components[0], components[1], true
+
+}
+
+func (r *NameResolver) getNamespacesToSearchForModule(sourceNamespace *Namespace) (searchOrder []*Namespace) {
+	return sourceNamespace.visibleNamespaces
+}
+
+func (r *NameResolver) ModuleFromName(name string, namespace blueprint.Namespace) (group blueprint.ModuleGroup, found bool) {
+	// handle fully qualified references like "//namespace_path:module_name"
+	nsName, moduleName, isAbs := r.parseFullyQualifiedName(name)
+	if isAbs {
+		namespace, found := r.namespaceAt(nsName)
+		if !found {
+			return blueprint.ModuleGroup{}, false
+		}
+		container := namespace.moduleContainer
+		return container.ModuleFromName(moduleName, nil)
+	}
+	for _, candidate := range r.getNamespacesToSearchForModule(namespace.(*Namespace)) {
+		group, found = candidate.moduleContainer.ModuleFromName(name, nil)
+		if found {
+			return group, true
+		}
+	}
+	return blueprint.ModuleGroup{}, false
+
+}
+
+func (r *NameResolver) Rename(oldName string, newName string, namespace blueprint.Namespace) []error {
+	oldNs := r.findNamespace(oldName)
+	newNs := r.findNamespace(newName)
+	if oldNs != newNs {
+		return []error{fmt.Errorf("cannot rename %v to %v because the destination is outside namespace %v", oldName, newName, oldNs.Path)}
+	}
+
+	oldName, err := filepath.Rel(oldNs.Path, oldName)
+	if err != nil {
+		panic(err)
+	}
+	newName, err = filepath.Rel(newNs.Path, newName)
+	if err != nil {
+		panic(err)
+	}
+
+	return oldNs.moduleContainer.Rename(oldName, newName, nil)
+}
+
+// resolve each element of namespace.importedNamespaceNames and put the result in namespace.visibleNamespaces
+func (r *NameResolver) FindNamespaceImports(namespace *Namespace) (err error) {
+	namespace.visibleNamespaces = make([]*Namespace, 0, 2+len(namespace.importedNamespaceNames))
+	// search itself first
+	namespace.visibleNamespaces = append(namespace.visibleNamespaces, namespace)
+	// search its imports next
+	for _, name := range namespace.importedNamespaceNames {
+		imp, ok := r.namespaceAt(name)
+		if !ok {
+			return fmt.Errorf("namespace %v does not exist", name)
+		}
+		namespace.visibleNamespaces = append(namespace.visibleNamespaces, imp)
+	}
+	// search the root namespace last
+	namespace.visibleNamespaces = append(namespace.visibleNamespaces, r.rootNamespace)
+	return nil
+}
+
+func (r *NameResolver) MissingDependencyError(depender string, dependerNamespace blueprint.Namespace, depName string) (err error) {
+	text := fmt.Sprintf("%q depends on undefined module %q", depender, depName)
+
+	_, _, isAbs := r.parseFullyQualifiedName(depName)
+	if isAbs {
+		// if the user gave a fully-qualified name, we don't need to look for other
+		// modules that they might have been referring to
+		return fmt.Errorf(text)
+	}
+
+	// determine which namespaces the module can be found in
+	foundInNamespaces := []string{}
+	for _, namespace := range r.sortedNamespaces.sortedItems() {
+		_, found := namespace.moduleContainer.ModuleFromName(depName, nil)
+		if found {
+			foundInNamespaces = append(foundInNamespaces, namespace.Path)
+		}
+	}
+	if len(foundInNamespaces) > 0 {
+		// determine which namespaces are visible to dependerNamespace
+		dependerNs := dependerNamespace.(*Namespace)
+		searched := r.getNamespacesToSearchForModule(dependerNs)
+		importedNames := []string{}
+		for _, ns := range searched {
+			importedNames = append(importedNames, ns.Path)
+		}
+		text += fmt.Sprintf("\nModule %q is defined in namespace %q which can read these %v namespaces: %q", depender, dependerNs.Path, len(importedNames), importedNames)
+		text += fmt.Sprintf("\nModule %q can be found in these namespaces: %q", depName, foundInNamespaces)
+	}
+
+	return fmt.Errorf(text)
+}
+
+func (r *NameResolver) GetNamespace(ctx blueprint.NamespaceContext) blueprint.Namespace {
+	return r.findNamespaceFromCtx(ctx)
+}
+
+func (r *NameResolver) findNamespaceFromCtx(ctx blueprint.NamespaceContext) *Namespace {
+	return r.findNamespace(ctx.ModuleDir())
+}
+
+var _ blueprint.NameInterface = (*NameResolver)(nil)
+
+type Namespace struct {
+	blueprint.NamespaceMarker
+	Path string
+
+	// names of namespaces listed as imports by this namespace
+	importedNamespaceNames []string
+	// all namespaces that should be searched when a module in this namespace declares a dependency
+	visibleNamespaces []*Namespace
+
+	id string
+
+	exportToKati bool
+
+	moduleContainer blueprint.NameInterface
+}
+
+func NewNamespace(path string) *Namespace {
+	return &Namespace{Path: path, moduleContainer: blueprint.NewSimpleNameInterface()}
+}
+
+var _ blueprint.Namespace = (*Namespace)(nil)
+
+type NamespaceModule struct {
+	ModuleBase
+
+	namespace *Namespace
+	resolver  *NameResolver
+
+	properties struct {
+		Imports []string
+	}
+}
+
+func (n *NamespaceModule) DepsMutator(context BottomUpMutatorContext) {
+}
+
+func (n *NamespaceModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+func (n *NamespaceModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
+}
+
+func (n *NamespaceModule) Name() (name string) {
+	return *n.nameProperties.Name
+}
+
+func NamespaceFactory() Module {
+	module := &NamespaceModule{}
+
+	name := "soong_namespace"
+	module.nameProperties.Name = &name
+
+	module.AddProperties(&module.properties)
+	return module
+}
+
+func RegisterNamespaceMutator(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("namespace_deps", namespaceDeps)
+}
+
+func namespaceDeps(ctx BottomUpMutatorContext) {
+	module, ok := ctx.Module().(*NamespaceModule)
+	if ok {
+		err := module.resolver.FindNamespaceImports(module.namespace)
+		if err != nil {
+			ctx.ModuleErrorf(err.Error())
+		}
+	}
+}