github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/soong/android/namespace.go (about)

     1  // Copyright 2017 Google Inc. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package android
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  	"path/filepath"
    21  	"sort"
    22  	"strconv"
    23  	"strings"
    24  	"sync"
    25  
    26  	"github.com/google/blueprint"
    27  )
    28  
    29  // This file implements namespaces
    30  const (
    31  	namespacePrefix = "//"
    32  	modulePrefix    = ":"
    33  )
    34  
    35  func init() {
    36  	RegisterModuleType("soong_namespace", NamespaceFactory)
    37  }
    38  
    39  // threadsafe sorted list
    40  type sortedNamespaces struct {
    41  	lock   sync.Mutex
    42  	items  []*Namespace
    43  	sorted bool
    44  }
    45  
    46  func (s *sortedNamespaces) add(namespace *Namespace) {
    47  	s.lock.Lock()
    48  	defer s.lock.Unlock()
    49  	if s.sorted {
    50  		panic("It is not supported to call sortedNamespaces.add() after sortedNamespaces.sortedItems()")
    51  	}
    52  	s.items = append(s.items, namespace)
    53  }
    54  
    55  func (s *sortedNamespaces) sortedItems() []*Namespace {
    56  	s.lock.Lock()
    57  	defer s.lock.Unlock()
    58  	if !s.sorted {
    59  		less := func(i int, j int) bool {
    60  			return s.items[i].Path < s.items[j].Path
    61  		}
    62  		sort.Slice(s.items, less)
    63  		s.sorted = true
    64  	}
    65  	return s.items
    66  }
    67  
    68  func (s *sortedNamespaces) index(namespace *Namespace) int {
    69  	for i, candidate := range s.sortedItems() {
    70  		if namespace == candidate {
    71  			return i
    72  		}
    73  	}
    74  	return -1
    75  }
    76  
    77  // A NameResolver implements blueprint.NameInterface, and implements the logic to
    78  // find a module from namespaces based on a query string.
    79  // A query string can be a module name or can be be "//namespace_path:module_path"
    80  type NameResolver struct {
    81  	rootNamespace *Namespace
    82  
    83  	// id counter for atomic.AddInt32
    84  	nextNamespaceId int32
    85  
    86  	// All namespaces, without duplicates.
    87  	sortedNamespaces sortedNamespaces
    88  
    89  	// Map from dir to namespace. Will have duplicates if two dirs are part of the same namespace.
    90  	namespacesByDir sync.Map // if generics were supported, this would be sync.Map[string]*Namespace
    91  
    92  	// func telling whether to export a namespace to Kati
    93  	namespaceExportFilter func(*Namespace) bool
    94  }
    95  
    96  func NewNameResolver(namespaceExportFilter func(*Namespace) bool) *NameResolver {
    97  	namespacesByDir := sync.Map{}
    98  
    99  	r := &NameResolver{
   100  		namespacesByDir:       namespacesByDir,
   101  		namespaceExportFilter: namespaceExportFilter,
   102  	}
   103  	r.rootNamespace = r.newNamespace(".")
   104  	r.rootNamespace.visibleNamespaces = []*Namespace{r.rootNamespace}
   105  	r.addNamespace(r.rootNamespace)
   106  
   107  	return r
   108  }
   109  
   110  func (r *NameResolver) newNamespace(path string) *Namespace {
   111  	namespace := NewNamespace(path)
   112  
   113  	namespace.exportToKati = r.namespaceExportFilter(namespace)
   114  
   115  	return namespace
   116  }
   117  
   118  func (r *NameResolver) addNewNamespaceForModule(module *NamespaceModule, path string) error {
   119  	fileName := filepath.Base(path)
   120  	if fileName != "Android.bp" {
   121  		return errors.New("A namespace may only be declared in a file named Android.bp")
   122  	}
   123  	dir := filepath.Dir(path)
   124  
   125  	namespace := r.newNamespace(dir)
   126  	module.namespace = namespace
   127  	module.resolver = r
   128  	namespace.importedNamespaceNames = module.properties.Imports
   129  	return r.addNamespace(namespace)
   130  }
   131  
   132  func (r *NameResolver) addNamespace(namespace *Namespace) (err error) {
   133  	existingNamespace, exists := r.namespaceAt(namespace.Path)
   134  	if exists {
   135  		if existingNamespace.Path == namespace.Path {
   136  			return fmt.Errorf("namespace %v already exists", namespace.Path)
   137  		} else {
   138  			// It would probably confuse readers if namespaces were declared anywhere but
   139  			// the top of the file, so we forbid declaring namespaces after anything else.
   140  			return fmt.Errorf("a namespace must be the first module in the file")
   141  		}
   142  	}
   143  	r.sortedNamespaces.add(namespace)
   144  
   145  	r.namespacesByDir.Store(namespace.Path, namespace)
   146  	return nil
   147  }
   148  
   149  // non-recursive check for namespace
   150  func (r *NameResolver) namespaceAt(path string) (namespace *Namespace, found bool) {
   151  	mapVal, found := r.namespacesByDir.Load(path)
   152  	if !found {
   153  		return nil, false
   154  	}
   155  	return mapVal.(*Namespace), true
   156  }
   157  
   158  // recursive search upward for a namespace
   159  func (r *NameResolver) findNamespace(path string) (namespace *Namespace) {
   160  	namespace, found := r.namespaceAt(path)
   161  	if found {
   162  		return namespace
   163  	}
   164  	parentDir := filepath.Dir(path)
   165  	if parentDir == path {
   166  		return nil
   167  	}
   168  	namespace = r.findNamespace(parentDir)
   169  	r.namespacesByDir.Store(path, namespace)
   170  	return namespace
   171  }
   172  
   173  func (r *NameResolver) NewModule(ctx blueprint.NamespaceContext, moduleGroup blueprint.ModuleGroup, module blueprint.Module) (namespace blueprint.Namespace, errs []error) {
   174  	// if this module is a namespace, then save it to our list of namespaces
   175  	newNamespace, ok := module.(*NamespaceModule)
   176  	if ok {
   177  		err := r.addNewNamespaceForModule(newNamespace, ctx.ModulePath())
   178  		if err != nil {
   179  			return nil, []error{err}
   180  		}
   181  		return nil, nil
   182  	}
   183  
   184  	// if this module is not a namespace, then save it into the appropriate namespace
   185  	ns := r.findNamespaceFromCtx(ctx)
   186  
   187  	_, errs = ns.moduleContainer.NewModule(ctx, moduleGroup, module)
   188  	if len(errs) > 0 {
   189  		return nil, errs
   190  	}
   191  
   192  	amod, ok := module.(Module)
   193  	if ok {
   194  		// inform the module whether its namespace is one that we want to export to Make
   195  		amod.base().commonProperties.NamespaceExportedToMake = ns.exportToKati
   196  	}
   197  
   198  	return ns, nil
   199  }
   200  
   201  func (r *NameResolver) AllModules() []blueprint.ModuleGroup {
   202  	childLists := [][]blueprint.ModuleGroup{}
   203  	totalCount := 0
   204  	for _, namespace := range r.sortedNamespaces.sortedItems() {
   205  		newModules := namespace.moduleContainer.AllModules()
   206  		totalCount += len(newModules)
   207  		childLists = append(childLists, newModules)
   208  	}
   209  
   210  	allModules := make([]blueprint.ModuleGroup, 0, totalCount)
   211  	for _, childList := range childLists {
   212  		allModules = append(allModules, childList...)
   213  	}
   214  	return allModules
   215  }
   216  
   217  // parses a fully-qualified path (like "//namespace_path:module_name") into a namespace name and a
   218  // module name
   219  func (r *NameResolver) parseFullyQualifiedName(name string) (namespaceName string, moduleName string, ok bool) {
   220  	if !strings.HasPrefix(name, namespacePrefix) {
   221  		return "", "", false
   222  	}
   223  	name = strings.TrimPrefix(name, namespacePrefix)
   224  	components := strings.Split(name, modulePrefix)
   225  	if len(components) != 2 {
   226  		return "", "", false
   227  	}
   228  	return components[0], components[1], true
   229  
   230  }
   231  
   232  func (r *NameResolver) getNamespacesToSearchForModule(sourceNamespace *Namespace) (searchOrder []*Namespace) {
   233  	return sourceNamespace.visibleNamespaces
   234  }
   235  
   236  func (r *NameResolver) ModuleFromName(name string, namespace blueprint.Namespace) (group blueprint.ModuleGroup, found bool) {
   237  	// handle fully qualified references like "//namespace_path:module_name"
   238  	nsName, moduleName, isAbs := r.parseFullyQualifiedName(name)
   239  	if isAbs {
   240  		namespace, found := r.namespaceAt(nsName)
   241  		if !found {
   242  			return blueprint.ModuleGroup{}, false
   243  		}
   244  		container := namespace.moduleContainer
   245  		return container.ModuleFromName(moduleName, nil)
   246  	}
   247  	for _, candidate := range r.getNamespacesToSearchForModule(namespace.(*Namespace)) {
   248  		group, found = candidate.moduleContainer.ModuleFromName(name, nil)
   249  		if found {
   250  			return group, true
   251  		}
   252  	}
   253  	return blueprint.ModuleGroup{}, false
   254  
   255  }
   256  
   257  func (r *NameResolver) Rename(oldName string, newName string, namespace blueprint.Namespace) []error {
   258  	return namespace.(*Namespace).moduleContainer.Rename(oldName, newName, namespace)
   259  }
   260  
   261  // resolve each element of namespace.importedNamespaceNames and put the result in namespace.visibleNamespaces
   262  func (r *NameResolver) FindNamespaceImports(namespace *Namespace) (err error) {
   263  	namespace.visibleNamespaces = make([]*Namespace, 0, 2+len(namespace.importedNamespaceNames))
   264  	// search itself first
   265  	namespace.visibleNamespaces = append(namespace.visibleNamespaces, namespace)
   266  	// search its imports next
   267  	for _, name := range namespace.importedNamespaceNames {
   268  		imp, ok := r.namespaceAt(name)
   269  		if !ok {
   270  			return fmt.Errorf("namespace %v does not exist", name)
   271  		}
   272  		namespace.visibleNamespaces = append(namespace.visibleNamespaces, imp)
   273  	}
   274  	// search the root namespace last
   275  	namespace.visibleNamespaces = append(namespace.visibleNamespaces, r.rootNamespace)
   276  	return nil
   277  }
   278  
   279  func (r *NameResolver) chooseId(namespace *Namespace) {
   280  	id := r.sortedNamespaces.index(namespace)
   281  	if id < 0 {
   282  		panic(fmt.Sprintf("Namespace not found: %v\n", namespace.id))
   283  	}
   284  	namespace.id = strconv.Itoa(id)
   285  }
   286  
   287  func (r *NameResolver) MissingDependencyError(depender string, dependerNamespace blueprint.Namespace, depName string) (err error) {
   288  	text := fmt.Sprintf("%q depends on undefined module %q", depender, depName)
   289  
   290  	_, _, isAbs := r.parseFullyQualifiedName(depName)
   291  	if isAbs {
   292  		// if the user gave a fully-qualified name, we don't need to look for other
   293  		// modules that they might have been referring to
   294  		return fmt.Errorf(text)
   295  	}
   296  
   297  	// determine which namespaces the module can be found in
   298  	foundInNamespaces := []string{}
   299  	for _, namespace := range r.sortedNamespaces.sortedItems() {
   300  		_, found := namespace.moduleContainer.ModuleFromName(depName, nil)
   301  		if found {
   302  			foundInNamespaces = append(foundInNamespaces, namespace.Path)
   303  		}
   304  	}
   305  	if len(foundInNamespaces) > 0 {
   306  		// determine which namespaces are visible to dependerNamespace
   307  		dependerNs := dependerNamespace.(*Namespace)
   308  		searched := r.getNamespacesToSearchForModule(dependerNs)
   309  		importedNames := []string{}
   310  		for _, ns := range searched {
   311  			importedNames = append(importedNames, ns.Path)
   312  		}
   313  		text += fmt.Sprintf("\nModule %q is defined in namespace %q which can read these %v namespaces: %q", depender, dependerNs.Path, len(importedNames), importedNames)
   314  		text += fmt.Sprintf("\nModule %q can be found in these namespaces: %q", depName, foundInNamespaces)
   315  	}
   316  
   317  	return fmt.Errorf(text)
   318  }
   319  
   320  func (r *NameResolver) GetNamespace(ctx blueprint.NamespaceContext) blueprint.Namespace {
   321  	return r.findNamespaceFromCtx(ctx)
   322  }
   323  
   324  func (r *NameResolver) findNamespaceFromCtx(ctx blueprint.NamespaceContext) *Namespace {
   325  	return r.findNamespace(filepath.Dir(ctx.ModulePath()))
   326  }
   327  
   328  func (r *NameResolver) UniqueName(ctx blueprint.NamespaceContext, name string) (unique string) {
   329  	prefix := r.findNamespaceFromCtx(ctx).id
   330  	if prefix != "" {
   331  		prefix = prefix + "-"
   332  	}
   333  	return prefix + name
   334  }
   335  
   336  var _ blueprint.NameInterface = (*NameResolver)(nil)
   337  
   338  type Namespace struct {
   339  	blueprint.NamespaceMarker
   340  	Path string
   341  
   342  	// names of namespaces listed as imports by this namespace
   343  	importedNamespaceNames []string
   344  	// all namespaces that should be searched when a module in this namespace declares a dependency
   345  	visibleNamespaces []*Namespace
   346  
   347  	id string
   348  
   349  	exportToKati bool
   350  
   351  	moduleContainer blueprint.NameInterface
   352  }
   353  
   354  func NewNamespace(path string) *Namespace {
   355  	return &Namespace{Path: path, moduleContainer: blueprint.NewSimpleNameInterface()}
   356  }
   357  
   358  var _ blueprint.Namespace = (*Namespace)(nil)
   359  
   360  type NamespaceModule struct {
   361  	ModuleBase
   362  
   363  	namespace *Namespace
   364  	resolver  *NameResolver
   365  
   366  	properties struct {
   367  		Imports []string
   368  	}
   369  }
   370  
   371  func (n *NamespaceModule) DepsMutator(context BottomUpMutatorContext) {
   372  }
   373  
   374  func (n *NamespaceModule) GenerateAndroidBuildActions(ctx ModuleContext) {
   375  }
   376  
   377  func (n *NamespaceModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
   378  }
   379  
   380  func (n *NamespaceModule) Name() (name string) {
   381  	return *n.nameProperties.Name
   382  }
   383  
   384  func NamespaceFactory() Module {
   385  	module := &NamespaceModule{}
   386  
   387  	name := "soong_namespace"
   388  	module.nameProperties.Name = &name
   389  
   390  	module.AddProperties(&module.properties)
   391  	return module
   392  }
   393  
   394  func RegisterNamespaceMutator(ctx RegisterMutatorsContext) {
   395  	ctx.BottomUp("namespace_deps", namespaceMutator).Parallel()
   396  }
   397  
   398  func namespaceMutator(ctx BottomUpMutatorContext) {
   399  	module, ok := ctx.Module().(*NamespaceModule)
   400  	if ok {
   401  		err := module.resolver.FindNamespaceImports(module.namespace)
   402  		if err != nil {
   403  			ctx.ModuleErrorf(err.Error())
   404  		}
   405  
   406  		module.resolver.chooseId(module.namespace)
   407  	}
   408  }