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