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 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) 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 79type NamespaceContext interface { 80 ModulePath() string 81} 82 83type namespaceContextImpl struct { 84 modulePath string 85} 86 87func newNamespaceContext(moduleInfo *moduleInfo) (ctx NamespaceContext) { 88 return &namespaceContextImpl{moduleInfo.pos.Filename} 89} 90 91func (ctx *namespaceContextImpl) ModulePath() string { 92 return ctx.modulePath 93} 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 { 129 return []error{ 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 } 136 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 } 141 s.modules[newName] = group 142 delete(s.modules, group.name) 143 group.name = newName 144 return nil 145} 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} 177 178func (s *SimpleNameInterface) UniqueName(ctx NamespaceContext, name string) (unique string) { 179 return name 180} 181