github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/blueprint/name_interface.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 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) 72 73 // returns a deterministic, unique, arbitrary string for the given name in the given namespace 74 UniqueName(ctx NamespaceContext, name string) (unique string) 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 { 80 ModulePath() string 81 } 82 83 type namespaceContextImpl struct { 84 modulePath string 85 } 86 87 func newNamespaceContext(moduleInfo *moduleInfo) (ctx NamespaceContext) { 88 return &namespaceContextImpl{moduleInfo.pos.Filename} 89 } 90 91 func (ctx *namespaceContextImpl) ModulePath() string { 92 return ctx.modulePath 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"+ 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 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 { 129 errs = append(errs, 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", 133 oldName, newName, existingGroup.modules[0].pos), 134 ) 135 return errs 136 } 137 138 group := s.modules[oldName] 139 s.modules[newName] = group 140 delete(s.modules, group.name) 141 group.name = newName 142 return []error{} 143 } 144 145 func (s *SimpleNameInterface) AllModules() []ModuleGroup { 146 groups := make([]ModuleGroup, 0, len(s.modules)) 147 for _, group := range s.modules { 148 groups = append(groups, group) 149 } 150 151 duplicateName := "" 152 less := func(i, j int) bool { 153 if groups[i].name == groups[j].name { 154 duplicateName = groups[i].name 155 } 156 return groups[i].name < groups[j].name 157 } 158 sort.Slice(groups, less) 159 if duplicateName != "" { 160 // It is permitted to have two moduleGroup's with the same name, but not within the same 161 // Namespace. The SimpleNameInterface should catch this in NewModule, however, so this 162 // should never happen. 163 panic(fmt.Sprintf("Duplicate moduleGroup name %q", duplicateName)) 164 } 165 return groups 166 } 167 168 func (s *SimpleNameInterface) MissingDependencyError(depender string, dependerNamespace Namespace, dependency string) (err error) { 169 return fmt.Errorf("%q depends on undefined module %q", depender, dependency) 170 } 171 172 func (s *SimpleNameInterface) GetNamespace(ctx NamespaceContext) Namespace { 173 return nil 174 } 175 176 func (s *SimpleNameInterface) UniqueName(ctx NamespaceContext, name string) (unique string) { 177 return name 178 }