Jeff Gaston | d70bf75 | 2017-11-10 15:12:08 -0800 | [diff] [blame] | 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 blueprint |
| 16 | |
| 17 | import ( |
| 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 |
| 29 | type ModuleGroup struct { |
| 30 | *moduleGroup |
| 31 | } |
| 32 | |
| 33 | func (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. |
| 42 | type Namespace interface { |
| 43 | namespace(Namespace) |
| 44 | } |
| 45 | type NamespaceMarker struct { |
| 46 | } |
| 47 | |
| 48 | func (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 |
| 53 | type 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 Gaston | 0e90759 | 2017-12-01 17:10:52 -0800 | [diff] [blame] | 72 | |
| 73 | // returns a deterministic, unique, arbitrary string for the given name in the given namespace |
| 74 | UniqueName(ctx NamespaceContext, name string) (unique string) |
Jeff Gaston | d70bf75 | 2017-11-10 15:12:08 -0800 | [diff] [blame] | 75 | } |
| 76 | |
| 77 | // A NamespaceContext stores the information given to a NameInterface to enable the NameInterface |
| 78 | // to choose the namespace for any given module |
| 79 | type NamespaceContext interface { |
Jeff Gaston | 3c8c334 | 2017-11-30 17:30:42 -0800 | [diff] [blame] | 80 | ModulePath() string |
Jeff Gaston | d70bf75 | 2017-11-10 15:12:08 -0800 | [diff] [blame] | 81 | } |
| 82 | |
Jeff Gaston | 3c8c334 | 2017-11-30 17:30:42 -0800 | [diff] [blame] | 83 | type namespaceContextImpl struct { |
| 84 | modulePath string |
Jeff Gaston | d70bf75 | 2017-11-10 15:12:08 -0800 | [diff] [blame] | 85 | } |
| 86 | |
Jeff Gaston | 0e90759 | 2017-12-01 17:10:52 -0800 | [diff] [blame] | 87 | func newNamespaceContext(moduleInfo *moduleInfo) (ctx NamespaceContext) { |
| 88 | return &namespaceContextImpl{moduleInfo.pos.Filename} |
| 89 | } |
| 90 | |
Jeff Gaston | 3c8c334 | 2017-11-30 17:30:42 -0800 | [diff] [blame] | 91 | func (ctx *namespaceContextImpl) ModulePath() string { |
| 92 | return ctx.modulePath |
Jeff Gaston | d70bf75 | 2017-11-10 15:12:08 -0800 | [diff] [blame] | 93 | } |
| 94 | |
| 95 | // a SimpleNameInterface just stores all modules in a map based on name |
| 96 | type SimpleNameInterface struct { |
| 97 | modules map[string]ModuleGroup |
| 98 | } |
| 99 | |
| 100 | func NewSimpleNameInterface() *SimpleNameInterface { |
| 101 | return &SimpleNameInterface{ |
| 102 | modules: make(map[string]ModuleGroup), |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | func (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"+ |
Colin Cross | 5df74a8 | 2020-08-24 16:18:21 -0700 | [diff] [blame] | 112 | " %s <-- previous definition here", name, group.modules.firstModule().pos), |
Jeff Gaston | d70bf75 | 2017-11-10 15:12:08 -0800 | [diff] [blame] | 113 | } |
| 114 | } |
| 115 | |
| 116 | s.modules[name] = group |
| 117 | |
| 118 | return nil, []error{} |
| 119 | } |
| 120 | |
| 121 | func (s *SimpleNameInterface) ModuleFromName(moduleName string, namespace Namespace) (group ModuleGroup, found bool) { |
| 122 | group, found = s.modules[moduleName] |
| 123 | return group, found |
| 124 | } |
| 125 | |
| 126 | func (s *SimpleNameInterface) Rename(oldName string, newName string, namespace Namespace) (errs []error) { |
| 127 | existingGroup, exists := s.modules[newName] |
| 128 | if exists { |
Colin Cross | 61fa603 | 2018-04-16 14:41:40 -0700 | [diff] [blame] | 129 | return []error{ |
Jeff Gaston | d70bf75 | 2017-11-10 15:12:08 -0800 | [diff] [blame] | 130 | // 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", |
Colin Cross | 5df74a8 | 2020-08-24 16:18:21 -0700 | [diff] [blame] | 133 | oldName, newName, existingGroup.modules.firstModule().pos), |
Colin Cross | 61fa603 | 2018-04-16 14:41:40 -0700 | [diff] [blame] | 134 | } |
Jeff Gaston | d70bf75 | 2017-11-10 15:12:08 -0800 | [diff] [blame] | 135 | } |
| 136 | |
Colin Cross | 61fa603 | 2018-04-16 14:41:40 -0700 | [diff] [blame] | 137 | 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 Gaston | d70bf75 | 2017-11-10 15:12:08 -0800 | [diff] [blame] | 141 | s.modules[newName] = group |
| 142 | delete(s.modules, group.name) |
| 143 | group.name = newName |
Colin Cross | 61fa603 | 2018-04-16 14:41:40 -0700 | [diff] [blame] | 144 | return nil |
Jeff Gaston | d70bf75 | 2017-11-10 15:12:08 -0800 | [diff] [blame] | 145 | } |
| 146 | |
| 147 | func (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 | |
| 170 | func (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 | |
| 174 | func (s *SimpleNameInterface) GetNamespace(ctx NamespaceContext) Namespace { |
| 175 | return nil |
| 176 | } |
Jeff Gaston | 0e90759 | 2017-12-01 17:10:52 -0800 | [diff] [blame] | 177 | |
| 178 | func (s *SimpleNameInterface) UniqueName(ctx NamespaceContext, name string) (unique string) { |
| 179 | return name |
| 180 | } |