08bd504b62
Soong analyzes the entire source tree even though not every lunch target needs to know about every module. For example, OEM sources can be ignored for cuttlefish products. This functionality allows blueprint to ignore a list of undesired directories. Bug: 269457150 Change-Id: Icbbf8f3b66813ad639a7ebd27b1a3ec153cbf269
219 lines
7.1 KiB
Go
219 lines
7.1 KiB
Go
// 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"
|
|
"os"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// 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)
|
|
|
|
// Gets called when a module was pruned from the build tree by SourceRootDirs
|
|
NewSkippedModule(ctx NamespaceContext, name string, skipInfo SkippedModuleInfo)
|
|
|
|
// 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)
|
|
|
|
// returns a deterministic, unique, arbitrary string for the given name in the given namespace
|
|
UniqueName(ctx NamespaceContext, name string) (unique string)
|
|
}
|
|
|
|
// A NamespaceContext stores the information given to a NameInterface to enable the NameInterface
|
|
// to choose the namespace for any given module
|
|
type NamespaceContext interface {
|
|
ModulePath() string
|
|
}
|
|
|
|
type namespaceContextImpl struct {
|
|
modulePath string
|
|
}
|
|
|
|
func newNamespaceContext(moduleInfo *moduleInfo) (ctx NamespaceContext) {
|
|
return &namespaceContextImpl{moduleInfo.pos.Filename}
|
|
}
|
|
|
|
func newNamespaceContextFromFilename(filename string) NamespaceContext {
|
|
return &namespaceContextImpl{filename}
|
|
}
|
|
|
|
func (ctx *namespaceContextImpl) ModulePath() string {
|
|
return ctx.modulePath
|
|
}
|
|
|
|
type SkippedModuleInfo struct {
|
|
filename string
|
|
reason string
|
|
}
|
|
|
|
// a SimpleNameInterface just stores all modules in a map based on name
|
|
type SimpleNameInterface struct {
|
|
modules map[string]ModuleGroup
|
|
skippedModules map[string][]SkippedModuleInfo
|
|
}
|
|
|
|
func NewSimpleNameInterface() *SimpleNameInterface {
|
|
return &SimpleNameInterface{
|
|
modules: make(map[string]ModuleGroup),
|
|
skippedModules: make(map[string][]SkippedModuleInfo),
|
|
}
|
|
}
|
|
|
|
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.firstModule().pos),
|
|
}
|
|
}
|
|
|
|
s.modules[name] = group
|
|
|
|
return nil, []error{}
|
|
}
|
|
|
|
func (s *SimpleNameInterface) NewSkippedModule(ctx NamespaceContext, name string, info SkippedModuleInfo) {
|
|
if name == "" {
|
|
return
|
|
}
|
|
s.skippedModules[name] = append(s.skippedModules[name], info)
|
|
}
|
|
|
|
func (s *SimpleNameInterface) ModuleFromName(moduleName string, namespace Namespace) (group ModuleGroup, found bool) {
|
|
group, found = s.modules[moduleName]
|
|
skipInfos, skipped := s.skippedModules[moduleName]
|
|
if skipped {
|
|
filesFound := make([]string, 0, len(skipInfos))
|
|
reasons := make([]string, 0, len(skipInfos))
|
|
for _, info := range skipInfos {
|
|
filesFound = append(filesFound, info.filename)
|
|
reasons = append(reasons, info.reason)
|
|
}
|
|
fmt.Fprintf(
|
|
os.Stderr,
|
|
"module %q was defined in files(s) [%v], but was skipped for reason(s) [%v]\n",
|
|
moduleName,
|
|
strings.Join(filesFound, ", "),
|
|
strings.Join(reasons, "; "),
|
|
)
|
|
}
|
|
return group, found
|
|
}
|
|
|
|
func (s *SimpleNameInterface) Rename(oldName string, newName string, namespace Namespace) (errs []error) {
|
|
existingGroup, exists := s.modules[newName]
|
|
if exists {
|
|
return []error{
|
|
// 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.firstModule().pos),
|
|
}
|
|
}
|
|
|
|
group, exists := s.modules[oldName]
|
|
if !exists {
|
|
return []error{fmt.Errorf("module %q to renamed to %q doesn't exist", oldName, newName)}
|
|
}
|
|
s.modules[newName] = group
|
|
delete(s.modules, group.name)
|
|
group.name = newName
|
|
return nil
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
func (s *SimpleNameInterface) UniqueName(ctx NamespaceContext, name string) (unique string) {
|
|
return name
|
|
}
|