cuelang.org/go@v0.13.0/cue/build/import.go (about) 1 // Copyright 2018 The CUE Authors 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 build 16 17 import ( 18 "maps" 19 "slices" 20 "strconv" 21 22 "cuelang.org/go/cue/errors" 23 "cuelang.org/go/cue/token" 24 ) 25 26 type LoadFunc func(pos token.Pos, path string) *Instance 27 28 type cueError = errors.Error 29 30 type buildError struct { 31 cueError 32 inputs []token.Pos 33 } 34 35 func (e *buildError) InputPositions() []token.Pos { 36 return e.inputs 37 } 38 39 func (inst *Instance) complete() errors.Error { 40 // TODO: handle case-insensitive collisions. 41 // dir := inst.Dir 42 // names := []string{} 43 // for _, src := range sources { 44 // names = append(names, src.path) 45 // } 46 // f1, f2 := str.FoldDup(names) 47 // if f1 != "" { 48 // return nil, fmt.Errorf("case-insensitive file name collision: %q and %q", f1, f2) 49 // } 50 51 var ( 52 c = inst.ctxt 53 imported = map[string][]token.Pos{} 54 ) 55 56 for _, f := range inst.Files { 57 for _, spec := range f.Imports { 58 quoted := spec.Path.Value 59 path, err := strconv.Unquote(quoted) 60 if err != nil { 61 inst.Err = errors.Append(inst.Err, 62 errors.Newf( 63 spec.Path.Pos(), 64 "%s: parser returned invalid quoted string: <%s>", 65 f.Filename, quoted)) 66 } 67 imported[path] = append(imported[path], spec.Pos()) 68 } 69 } 70 71 paths := make([]string, 0, len(imported)) 72 for path := range imported { 73 paths = append(paths, path) 74 if path == "" { 75 return &buildError{ 76 errors.Newf(token.NoPos, "empty import path"), 77 imported[path], 78 } 79 } 80 } 81 82 slices.Sort(paths) 83 84 if inst.loadFunc != nil { 85 for i, path := range paths { 86 // isLocal := IsLocalImport(path) 87 // if isLocal { 88 // path = dirToImportPath(filepath.Join(dir, path)) 89 // } 90 91 imp := c.imports[path] 92 if imp == nil { 93 pos := token.NoPos 94 if len(imported[path]) > 0 { 95 pos = imported[path][0] 96 } 97 imp = inst.loadFunc(pos, path) 98 if imp == nil { 99 continue 100 } 101 if imp.Err != nil { 102 return errors.Wrapf(imp.Err, pos, "import failed") 103 } 104 imp.ImportPath = path 105 // imp.parent = inst 106 c.imports[path] = imp 107 // imp.parent = nil 108 } else if imp.parent != nil { 109 // TODO: report a standard cycle message. 110 // cycle is now handled explicitly in loader 111 } 112 paths[i] = imp.ImportPath 113 114 inst.addImport(imp) 115 if imp.Incomplete { 116 inst.Incomplete = true 117 } 118 } 119 } 120 121 inst.ImportPaths = paths 122 inst.ImportPos = imported 123 124 // Build full dependencies 125 deps := make(map[string]*Instance) 126 var q []*Instance 127 q = append(q, inst.Imports...) 128 for i := 0; i < len(q); i++ { 129 p1 := q[i] 130 path := p1.ImportPath 131 // The same import path could produce an error or not, 132 // depending on what tries to import it. 133 // Prefer to record entries with errors, so we can report them. 134 // p0 := deps[path] 135 // if err0, err1 := lastError(p0), lastError(p1); p0 == nil || err1 != nil && (err0 == nil || len(err0.ImportStack) > len(err1.ImportStack)) { 136 // deps[path] = p1 137 // for _, p2 := range p1.Imports { 138 // if deps[p2.ImportPath] != p2 { 139 // q = append(q, p2) 140 // } 141 // } 142 // } 143 if _, ok := deps[path]; !ok { 144 deps[path] = p1 145 } 146 } 147 inst.Deps = slices.Sorted(maps.Keys(deps)) 148 149 for _, dep := range inst.Deps { 150 p1 := deps[dep] 151 if p1 == nil { 152 panic("impossible: missing entry in package cache for " + dep + " imported by " + inst.ImportPath) 153 } 154 if p1.Err != nil { 155 inst.DepsErrors = append(inst.DepsErrors, p1.Err) 156 } 157 } 158 159 return nil 160 }