xref: /aosp_15_r20/build/blueprint/name_interface.go (revision 1fa6dee971e1612fa5cc0aa5ca2d35a22e2c34a3)
1*1fa6dee9SAndroid Build Coastguard Worker// Copyright 2017 Google Inc. All rights reserved.
2*1fa6dee9SAndroid Build Coastguard Worker//
3*1fa6dee9SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*1fa6dee9SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*1fa6dee9SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*1fa6dee9SAndroid Build Coastguard Worker//
7*1fa6dee9SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*1fa6dee9SAndroid Build Coastguard Worker//
9*1fa6dee9SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*1fa6dee9SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*1fa6dee9SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*1fa6dee9SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*1fa6dee9SAndroid Build Coastguard Worker// limitations under the License.
14*1fa6dee9SAndroid Build Coastguard Worker
15*1fa6dee9SAndroid Build Coastguard Workerpackage blueprint
16*1fa6dee9SAndroid Build Coastguard Worker
17*1fa6dee9SAndroid Build Coastguard Workerimport (
18*1fa6dee9SAndroid Build Coastguard Worker	"fmt"
19*1fa6dee9SAndroid Build Coastguard Worker	"sort"
20*1fa6dee9SAndroid Build Coastguard Worker	"strings"
21*1fa6dee9SAndroid Build Coastguard Worker)
22*1fa6dee9SAndroid Build Coastguard Worker
23*1fa6dee9SAndroid Build Coastguard Worker// This file exposes the logic of locating a module via a query string, to enable
24*1fa6dee9SAndroid Build Coastguard Worker// other projects to override it if desired.
25*1fa6dee9SAndroid Build Coastguard Worker// The default name resolution implementation, SimpleNameInterface,
26*1fa6dee9SAndroid Build Coastguard Worker// just treats the query string as a module name, and does a simple map lookup.
27*1fa6dee9SAndroid Build Coastguard Worker
28*1fa6dee9SAndroid Build Coastguard Worker// A ModuleGroup just points to a moduleGroup to allow external packages to refer
29*1fa6dee9SAndroid Build Coastguard Worker// to a moduleGroup but not use it
30*1fa6dee9SAndroid Build Coastguard Workertype ModuleGroup struct {
31*1fa6dee9SAndroid Build Coastguard Worker	*moduleGroup
32*1fa6dee9SAndroid Build Coastguard Worker}
33*1fa6dee9SAndroid Build Coastguard Worker
34*1fa6dee9SAndroid Build Coastguard Workerfunc (h *ModuleGroup) String() string {
35*1fa6dee9SAndroid Build Coastguard Worker	return h.moduleGroup.name
36*1fa6dee9SAndroid Build Coastguard Worker}
37*1fa6dee9SAndroid Build Coastguard Worker
38*1fa6dee9SAndroid Build Coastguard Worker// The Namespace interface is just a marker interface for usage by the NameInterface,
39*1fa6dee9SAndroid Build Coastguard Worker// to allow a NameInterface to specify that a certain parameter should be a Namespace.
40*1fa6dee9SAndroid Build Coastguard Worker// In practice, a specific NameInterface will expect to only give and receive structs of
41*1fa6dee9SAndroid Build Coastguard Worker// the same concrete type, but because Go doesn't support generics, we use a marker interface
42*1fa6dee9SAndroid Build Coastguard Worker// for a little bit of clarity, and expect implementers to do typecasting instead.
43*1fa6dee9SAndroid Build Coastguard Workertype Namespace interface {
44*1fa6dee9SAndroid Build Coastguard Worker	namespace(Namespace)
45*1fa6dee9SAndroid Build Coastguard Worker}
46*1fa6dee9SAndroid Build Coastguard Workertype NamespaceMarker struct {
47*1fa6dee9SAndroid Build Coastguard Worker}
48*1fa6dee9SAndroid Build Coastguard Worker
49*1fa6dee9SAndroid Build Coastguard Workerfunc (m *NamespaceMarker) namespace(Namespace) {
50*1fa6dee9SAndroid Build Coastguard Worker}
51*1fa6dee9SAndroid Build Coastguard Worker
52*1fa6dee9SAndroid Build Coastguard Worker// A NameInterface tells how to locate modules by name.
53*1fa6dee9SAndroid Build Coastguard Worker// There should only be one name interface per Context, but potentially many namespaces
54*1fa6dee9SAndroid Build Coastguard Workertype NameInterface interface {
55*1fa6dee9SAndroid Build Coastguard Worker	// Gets called when a new module is created
56*1fa6dee9SAndroid Build Coastguard Worker	NewModule(ctx NamespaceContext, group ModuleGroup, module Module) (namespace Namespace, err []error)
57*1fa6dee9SAndroid Build Coastguard Worker
58*1fa6dee9SAndroid Build Coastguard Worker	// Gets called when a module was pruned from the build tree by SourceRootDirs
59*1fa6dee9SAndroid Build Coastguard Worker	NewSkippedModule(ctx NamespaceContext, name string, skipInfo SkippedModuleInfo)
60*1fa6dee9SAndroid Build Coastguard Worker
61*1fa6dee9SAndroid Build Coastguard Worker	// Finds the module with the given name
62*1fa6dee9SAndroid Build Coastguard Worker	ModuleFromName(moduleName string, namespace Namespace) (group ModuleGroup, found bool)
63*1fa6dee9SAndroid Build Coastguard Worker
64*1fa6dee9SAndroid Build Coastguard Worker	// Finds if the module with the given name was skipped
65*1fa6dee9SAndroid Build Coastguard Worker	SkippedModuleFromName(moduleName string, namespace Namespace) (skipInfos []SkippedModuleInfo, skipped bool)
66*1fa6dee9SAndroid Build Coastguard Worker
67*1fa6dee9SAndroid Build Coastguard Worker	// Returns an error indicating that the given module could not be found.
68*1fa6dee9SAndroid Build Coastguard Worker	// The error contains some diagnostic information about where the dependency can be found.
69*1fa6dee9SAndroid Build Coastguard Worker	MissingDependencyError(depender string, dependerNamespace Namespace, depName string, guess []string) (err error)
70*1fa6dee9SAndroid Build Coastguard Worker
71*1fa6dee9SAndroid Build Coastguard Worker	// Rename
72*1fa6dee9SAndroid Build Coastguard Worker	Rename(oldName string, newName string, namespace Namespace) []error
73*1fa6dee9SAndroid Build Coastguard Worker
74*1fa6dee9SAndroid Build Coastguard Worker	// Returns all modules in a deterministic order.
75*1fa6dee9SAndroid Build Coastguard Worker	AllModules() []ModuleGroup
76*1fa6dee9SAndroid Build Coastguard Worker
77*1fa6dee9SAndroid Build Coastguard Worker	// gets the namespace for a given path
78*1fa6dee9SAndroid Build Coastguard Worker	GetNamespace(ctx NamespaceContext) (namespace Namespace)
79*1fa6dee9SAndroid Build Coastguard Worker
80*1fa6dee9SAndroid Build Coastguard Worker	// returns a deterministic, unique, arbitrary string for the given name in the given namespace
81*1fa6dee9SAndroid Build Coastguard Worker	UniqueName(ctx NamespaceContext, name string) (unique string)
82*1fa6dee9SAndroid Build Coastguard Worker}
83*1fa6dee9SAndroid Build Coastguard Worker
84*1fa6dee9SAndroid Build Coastguard Worker// A NamespaceContext stores the information given to a NameInterface to enable the NameInterface
85*1fa6dee9SAndroid Build Coastguard Worker// to choose the namespace for any given module
86*1fa6dee9SAndroid Build Coastguard Workertype NamespaceContext interface {
87*1fa6dee9SAndroid Build Coastguard Worker	ModulePath() string
88*1fa6dee9SAndroid Build Coastguard Worker}
89*1fa6dee9SAndroid Build Coastguard Worker
90*1fa6dee9SAndroid Build Coastguard Workertype namespaceContextImpl struct {
91*1fa6dee9SAndroid Build Coastguard Worker	modulePath string
92*1fa6dee9SAndroid Build Coastguard Worker}
93*1fa6dee9SAndroid Build Coastguard Worker
94*1fa6dee9SAndroid Build Coastguard Workerfunc newNamespaceContext(moduleInfo *moduleInfo) (ctx NamespaceContext) {
95*1fa6dee9SAndroid Build Coastguard Worker	return &namespaceContextImpl{moduleInfo.pos.Filename}
96*1fa6dee9SAndroid Build Coastguard Worker}
97*1fa6dee9SAndroid Build Coastguard Worker
98*1fa6dee9SAndroid Build Coastguard Workerfunc newNamespaceContextFromFilename(filename string) NamespaceContext {
99*1fa6dee9SAndroid Build Coastguard Worker	return &namespaceContextImpl{filename}
100*1fa6dee9SAndroid Build Coastguard Worker}
101*1fa6dee9SAndroid Build Coastguard Worker
102*1fa6dee9SAndroid Build Coastguard Workerfunc (ctx *namespaceContextImpl) ModulePath() string {
103*1fa6dee9SAndroid Build Coastguard Worker	return ctx.modulePath
104*1fa6dee9SAndroid Build Coastguard Worker}
105*1fa6dee9SAndroid Build Coastguard Worker
106*1fa6dee9SAndroid Build Coastguard Workertype SkippedModuleInfo struct {
107*1fa6dee9SAndroid Build Coastguard Worker	filename string
108*1fa6dee9SAndroid Build Coastguard Worker	reason   string
109*1fa6dee9SAndroid Build Coastguard Worker}
110*1fa6dee9SAndroid Build Coastguard Worker
111*1fa6dee9SAndroid Build Coastguard Worker// a SimpleNameInterface just stores all modules in a map based on name
112*1fa6dee9SAndroid Build Coastguard Workertype SimpleNameInterface struct {
113*1fa6dee9SAndroid Build Coastguard Worker	modules        map[string]ModuleGroup
114*1fa6dee9SAndroid Build Coastguard Worker	skippedModules map[string][]SkippedModuleInfo
115*1fa6dee9SAndroid Build Coastguard Worker}
116*1fa6dee9SAndroid Build Coastguard Worker
117*1fa6dee9SAndroid Build Coastguard Workerfunc NewSimpleNameInterface() *SimpleNameInterface {
118*1fa6dee9SAndroid Build Coastguard Worker	return &SimpleNameInterface{
119*1fa6dee9SAndroid Build Coastguard Worker		modules:        make(map[string]ModuleGroup),
120*1fa6dee9SAndroid Build Coastguard Worker		skippedModules: make(map[string][]SkippedModuleInfo),
121*1fa6dee9SAndroid Build Coastguard Worker	}
122*1fa6dee9SAndroid Build Coastguard Worker}
123*1fa6dee9SAndroid Build Coastguard Worker
124*1fa6dee9SAndroid Build Coastguard Workerfunc (s *SimpleNameInterface) NewModule(ctx NamespaceContext, group ModuleGroup, module Module) (namespace Namespace, err []error) {
125*1fa6dee9SAndroid Build Coastguard Worker	name := group.name
126*1fa6dee9SAndroid Build Coastguard Worker	if group, present := s.modules[name]; present {
127*1fa6dee9SAndroid Build Coastguard Worker		return nil, []error{
128*1fa6dee9SAndroid Build Coastguard Worker			// seven characters at the start of the second line to align with the string "error: "
129*1fa6dee9SAndroid Build Coastguard Worker			fmt.Errorf("module %q already defined\n"+
130*1fa6dee9SAndroid Build Coastguard Worker				"       %s <-- previous definition here", name, group.modules.firstModule().pos),
131*1fa6dee9SAndroid Build Coastguard Worker		}
132*1fa6dee9SAndroid Build Coastguard Worker	}
133*1fa6dee9SAndroid Build Coastguard Worker
134*1fa6dee9SAndroid Build Coastguard Worker	s.modules[name] = group
135*1fa6dee9SAndroid Build Coastguard Worker
136*1fa6dee9SAndroid Build Coastguard Worker	return nil, []error{}
137*1fa6dee9SAndroid Build Coastguard Worker}
138*1fa6dee9SAndroid Build Coastguard Worker
139*1fa6dee9SAndroid Build Coastguard Workerfunc (s *SimpleNameInterface) NewSkippedModule(ctx NamespaceContext, name string, info SkippedModuleInfo) {
140*1fa6dee9SAndroid Build Coastguard Worker	if name == "" {
141*1fa6dee9SAndroid Build Coastguard Worker		return
142*1fa6dee9SAndroid Build Coastguard Worker	}
143*1fa6dee9SAndroid Build Coastguard Worker	s.skippedModules[name] = append(s.skippedModules[name], info)
144*1fa6dee9SAndroid Build Coastguard Worker}
145*1fa6dee9SAndroid Build Coastguard Worker
146*1fa6dee9SAndroid Build Coastguard Workerfunc (s *SimpleNameInterface) ModuleFromName(moduleName string, namespace Namespace) (group ModuleGroup, found bool) {
147*1fa6dee9SAndroid Build Coastguard Worker	group, found = s.modules[moduleName]
148*1fa6dee9SAndroid Build Coastguard Worker	return group, found
149*1fa6dee9SAndroid Build Coastguard Worker}
150*1fa6dee9SAndroid Build Coastguard Worker
151*1fa6dee9SAndroid Build Coastguard Workerfunc (s *SimpleNameInterface) SkippedModuleFromName(moduleName string, namespace Namespace) (skipInfos []SkippedModuleInfo, skipped bool) {
152*1fa6dee9SAndroid Build Coastguard Worker	skipInfos, skipped = s.skippedModules[moduleName]
153*1fa6dee9SAndroid Build Coastguard Worker	return
154*1fa6dee9SAndroid Build Coastguard Worker}
155*1fa6dee9SAndroid Build Coastguard Worker
156*1fa6dee9SAndroid Build Coastguard Workerfunc (s *SimpleNameInterface) Rename(oldName string, newName string, namespace Namespace) (errs []error) {
157*1fa6dee9SAndroid Build Coastguard Worker	existingGroup, exists := s.modules[newName]
158*1fa6dee9SAndroid Build Coastguard Worker	if exists {
159*1fa6dee9SAndroid Build Coastguard Worker		return []error{
160*1fa6dee9SAndroid Build Coastguard Worker			// seven characters at the start of the second line to align with the string "error: "
161*1fa6dee9SAndroid Build Coastguard Worker			fmt.Errorf("renaming module %q to %q conflicts with existing module\n"+
162*1fa6dee9SAndroid Build Coastguard Worker				"       %s <-- existing module defined here",
163*1fa6dee9SAndroid Build Coastguard Worker				oldName, newName, existingGroup.modules.firstModule().pos),
164*1fa6dee9SAndroid Build Coastguard Worker		}
165*1fa6dee9SAndroid Build Coastguard Worker	}
166*1fa6dee9SAndroid Build Coastguard Worker
167*1fa6dee9SAndroid Build Coastguard Worker	group, exists := s.modules[oldName]
168*1fa6dee9SAndroid Build Coastguard Worker	if !exists {
169*1fa6dee9SAndroid Build Coastguard Worker		return []error{fmt.Errorf("module %q to renamed to %q doesn't exist", oldName, newName)}
170*1fa6dee9SAndroid Build Coastguard Worker	}
171*1fa6dee9SAndroid Build Coastguard Worker	s.modules[newName] = group
172*1fa6dee9SAndroid Build Coastguard Worker	delete(s.modules, group.name)
173*1fa6dee9SAndroid Build Coastguard Worker	group.name = newName
174*1fa6dee9SAndroid Build Coastguard Worker	return nil
175*1fa6dee9SAndroid Build Coastguard Worker}
176*1fa6dee9SAndroid Build Coastguard Worker
177*1fa6dee9SAndroid Build Coastguard Workerfunc (s *SimpleNameInterface) AllModules() []ModuleGroup {
178*1fa6dee9SAndroid Build Coastguard Worker	groups := make([]ModuleGroup, 0, len(s.modules))
179*1fa6dee9SAndroid Build Coastguard Worker	for _, group := range s.modules {
180*1fa6dee9SAndroid Build Coastguard Worker		groups = append(groups, group)
181*1fa6dee9SAndroid Build Coastguard Worker	}
182*1fa6dee9SAndroid Build Coastguard Worker
183*1fa6dee9SAndroid Build Coastguard Worker	duplicateName := ""
184*1fa6dee9SAndroid Build Coastguard Worker	less := func(i, j int) bool {
185*1fa6dee9SAndroid Build Coastguard Worker		if groups[i].name == groups[j].name {
186*1fa6dee9SAndroid Build Coastguard Worker			duplicateName = groups[i].name
187*1fa6dee9SAndroid Build Coastguard Worker		}
188*1fa6dee9SAndroid Build Coastguard Worker		return groups[i].name < groups[j].name
189*1fa6dee9SAndroid Build Coastguard Worker	}
190*1fa6dee9SAndroid Build Coastguard Worker	sort.Slice(groups, less)
191*1fa6dee9SAndroid Build Coastguard Worker	if duplicateName != "" {
192*1fa6dee9SAndroid Build Coastguard Worker		// It is permitted to have two moduleGroup's with the same name, but not within the same
193*1fa6dee9SAndroid Build Coastguard Worker		// Namespace. The SimpleNameInterface should catch this in NewModule, however, so this
194*1fa6dee9SAndroid Build Coastguard Worker		// should never happen.
195*1fa6dee9SAndroid Build Coastguard Worker		panic(fmt.Sprintf("Duplicate moduleGroup name %q", duplicateName))
196*1fa6dee9SAndroid Build Coastguard Worker	}
197*1fa6dee9SAndroid Build Coastguard Worker	return groups
198*1fa6dee9SAndroid Build Coastguard Worker}
199*1fa6dee9SAndroid Build Coastguard Worker
200*1fa6dee9SAndroid Build Coastguard Workerfunc (s *SimpleNameInterface) MissingDependencyError(depender string, dependerNamespace Namespace, dependency string, guess []string) (err error) {
201*1fa6dee9SAndroid Build Coastguard Worker	skipInfos, skipped := s.SkippedModuleFromName(dependency, dependerNamespace)
202*1fa6dee9SAndroid Build Coastguard Worker	if skipped {
203*1fa6dee9SAndroid Build Coastguard Worker		filesFound := make([]string, 0, len(skipInfos))
204*1fa6dee9SAndroid Build Coastguard Worker		reasons := make([]string, 0, len(skipInfos))
205*1fa6dee9SAndroid Build Coastguard Worker		for _, info := range skipInfos {
206*1fa6dee9SAndroid Build Coastguard Worker			filesFound = append(filesFound, info.filename)
207*1fa6dee9SAndroid Build Coastguard Worker			reasons = append(reasons, info.reason)
208*1fa6dee9SAndroid Build Coastguard Worker		}
209*1fa6dee9SAndroid Build Coastguard Worker		return fmt.Errorf(
210*1fa6dee9SAndroid Build Coastguard Worker			"module %q depends on skipped module %q; %q was defined in files(s) [%v], but was skipped for reason(s) [%v]",
211*1fa6dee9SAndroid Build Coastguard Worker			depender,
212*1fa6dee9SAndroid Build Coastguard Worker			dependency,
213*1fa6dee9SAndroid Build Coastguard Worker			dependency,
214*1fa6dee9SAndroid Build Coastguard Worker			strings.Join(filesFound, ", "),
215*1fa6dee9SAndroid Build Coastguard Worker			strings.Join(reasons, "; "),
216*1fa6dee9SAndroid Build Coastguard Worker		)
217*1fa6dee9SAndroid Build Coastguard Worker	}
218*1fa6dee9SAndroid Build Coastguard Worker
219*1fa6dee9SAndroid Build Coastguard Worker	guessString := ""
220*1fa6dee9SAndroid Build Coastguard Worker	if len(guess) > 0 {
221*1fa6dee9SAndroid Build Coastguard Worker		guessString = fmt.Sprintf(" Did you mean %q?", guess)
222*1fa6dee9SAndroid Build Coastguard Worker	}
223*1fa6dee9SAndroid Build Coastguard Worker	return fmt.Errorf("%q depends on undefined module %q.%s", depender, dependency, guessString)
224*1fa6dee9SAndroid Build Coastguard Worker}
225*1fa6dee9SAndroid Build Coastguard Worker
226*1fa6dee9SAndroid Build Coastguard Workerfunc (s *SimpleNameInterface) GetNamespace(ctx NamespaceContext) Namespace {
227*1fa6dee9SAndroid Build Coastguard Worker	return nil
228*1fa6dee9SAndroid Build Coastguard Worker}
229*1fa6dee9SAndroid Build Coastguard Worker
230*1fa6dee9SAndroid Build Coastguard Workerfunc (s *SimpleNameInterface) UniqueName(ctx NamespaceContext, name string) (unique string) {
231*1fa6dee9SAndroid Build Coastguard Worker	return name
232*1fa6dee9SAndroid Build Coastguard Worker}
233