blob: 1849e9d31c12b12828984e6adc2d844cab48d7f3 [file] [log] [blame]
Jeff Gastond70bf752017-11-10 15:12:08 -08001// 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
15package blueprint
16
17import (
18 "fmt"
19 "sort"
20)
21
22// This file exposes the logic of locating a module via a query string, to enable
23// other projects to override it if desired.
24// The default name resolution implementation, SimpleNameInterface,
25// just treats the query string as a module name, and does a simple map lookup.
26
27// A ModuleGroup just points to a moduleGroup to allow external packages to refer
28// to a moduleGroup but not use it
29type ModuleGroup struct {
30 *moduleGroup
31}
32
33func (h *ModuleGroup) String() string {
34 return h.moduleGroup.name
35}
36
37// The Namespace interface is just a marker interface for usage by the NameInterface,
38// to allow a NameInterface to specify that a certain parameter should be a Namespace.
39// In practice, a specific NameInterface will expect to only give and receive structs of
40// the same concrete type, but because Go doesn't support generics, we use a marker interface
41// for a little bit of clarity, and expect implementers to do typecasting instead.
42type Namespace interface {
43 namespace(Namespace)
44}
45type NamespaceMarker struct {
46}
47
48func (m *NamespaceMarker) namespace(Namespace) {
49}
50
51// A NameInterface tells how to locate modules by name.
52// There should only be one name interface per Context, but potentially many namespaces
53type NameInterface interface {
54 // Gets called when a new module is created
55 NewModule(ctx NamespaceContext, group ModuleGroup, module Module) (namespace Namespace, err []error)
56
57 // Finds the module with the given name
58 ModuleFromName(moduleName string, namespace Namespace) (group ModuleGroup, found bool)
59
60 // Returns an error indicating that the given module could not be found.
61 // The error contains some diagnostic information about where the dependency can be found.
62 MissingDependencyError(depender string, dependerNamespace Namespace, depName string) (err error)
63
64 // Rename
65 Rename(oldName string, newName string, namespace Namespace) []error
66
67 // Returns all modules in a deterministic order.
68 AllModules() []ModuleGroup
69
70 // gets the namespace for a given path
71 GetNamespace(ctx NamespaceContext) (namespace Namespace)
Jeff Gaston0e907592017-12-01 17:10:52 -080072
73 // returns a deterministic, unique, arbitrary string for the given name in the given namespace
74 UniqueName(ctx NamespaceContext, name string) (unique string)
Jeff Gastond70bf752017-11-10 15:12:08 -080075}
76
77// A NamespaceContext stores the information given to a NameInterface to enable the NameInterface
78// to choose the namespace for any given module
79type NamespaceContext interface {
Jeff Gaston3c8c3342017-11-30 17:30:42 -080080 ModulePath() string
Jeff Gastond70bf752017-11-10 15:12:08 -080081}
82
Jeff Gaston3c8c3342017-11-30 17:30:42 -080083type namespaceContextImpl struct {
84 modulePath string
Jeff Gastond70bf752017-11-10 15:12:08 -080085}
86
Jeff Gaston0e907592017-12-01 17:10:52 -080087func newNamespaceContext(moduleInfo *moduleInfo) (ctx NamespaceContext) {
88 return &namespaceContextImpl{moduleInfo.pos.Filename}
89}
90
Jeff Gaston3c8c3342017-11-30 17:30:42 -080091func (ctx *namespaceContextImpl) ModulePath() string {
92 return ctx.modulePath
Jeff Gastond70bf752017-11-10 15:12:08 -080093}
94
95// a SimpleNameInterface just stores all modules in a map based on name
96type SimpleNameInterface struct {
97 modules map[string]ModuleGroup
98}
99
100func NewSimpleNameInterface() *SimpleNameInterface {
101 return &SimpleNameInterface{
102 modules: make(map[string]ModuleGroup),
103 }
104}
105
106func (s *SimpleNameInterface) NewModule(ctx NamespaceContext, group ModuleGroup, module Module) (namespace Namespace, err []error) {
107 name := group.name
108 if group, present := s.modules[name]; present {
109 return nil, []error{
110 // seven characters at the start of the second line to align with the string "error: "
111 fmt.Errorf("module %q already defined\n"+
112 " %s <-- previous definition here", name, group.modules[0].pos),
113 }
114 }
115
116 s.modules[name] = group
117
118 return nil, []error{}
119}
120
121func (s *SimpleNameInterface) ModuleFromName(moduleName string, namespace Namespace) (group ModuleGroup, found bool) {
122 group, found = s.modules[moduleName]
123 return group, found
124}
125
126func (s *SimpleNameInterface) Rename(oldName string, newName string, namespace Namespace) (errs []error) {
127 existingGroup, exists := s.modules[newName]
128 if exists {
Colin Cross61fa6032018-04-16 14:41:40 -0700129 return []error{
Jeff Gastond70bf752017-11-10 15:12:08 -0800130 // seven characters at the start of the second line to align with the string "error: "
131 fmt.Errorf("renaming module %q to %q conflicts with existing module\n"+
132 " %s <-- existing module defined here",
133 oldName, newName, existingGroup.modules[0].pos),
Colin Cross61fa6032018-04-16 14:41:40 -0700134 }
Jeff Gastond70bf752017-11-10 15:12:08 -0800135 }
136
Colin Cross61fa6032018-04-16 14:41:40 -0700137 group, exists := s.modules[oldName]
138 if !exists {
139 return []error{fmt.Errorf("module %q to renamed to %q doesn't exist", oldName, newName)}
140 }
Jeff Gastond70bf752017-11-10 15:12:08 -0800141 s.modules[newName] = group
142 delete(s.modules, group.name)
143 group.name = newName
Colin Cross61fa6032018-04-16 14:41:40 -0700144 return nil
Jeff Gastond70bf752017-11-10 15:12:08 -0800145}
146
147func (s *SimpleNameInterface) AllModules() []ModuleGroup {
148 groups := make([]ModuleGroup, 0, len(s.modules))
149 for _, group := range s.modules {
150 groups = append(groups, group)
151 }
152
153 duplicateName := ""
154 less := func(i, j int) bool {
155 if groups[i].name == groups[j].name {
156 duplicateName = groups[i].name
157 }
158 return groups[i].name < groups[j].name
159 }
160 sort.Slice(groups, less)
161 if duplicateName != "" {
162 // It is permitted to have two moduleGroup's with the same name, but not within the same
163 // Namespace. The SimpleNameInterface should catch this in NewModule, however, so this
164 // should never happen.
165 panic(fmt.Sprintf("Duplicate moduleGroup name %q", duplicateName))
166 }
167 return groups
168}
169
170func (s *SimpleNameInterface) MissingDependencyError(depender string, dependerNamespace Namespace, dependency string) (err error) {
171 return fmt.Errorf("%q depends on undefined module %q", depender, dependency)
172}
173
174func (s *SimpleNameInterface) GetNamespace(ctx NamespaceContext) Namespace {
175 return nil
176}
Jeff Gaston0e907592017-12-01 17:10:52 -0800177
178func (s *SimpleNameInterface) UniqueName(ctx NamespaceContext, name string) (unique string) {
179 return name
180}