github.com/joomcode/cue@v0.4.4-0.20221111115225-539fe3512047/cue/load/errors.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 load 16 17 import ( 18 "fmt" 19 "path/filepath" 20 "strings" 21 22 "github.com/joomcode/cue/cue/build" 23 "github.com/joomcode/cue/cue/errors" 24 "github.com/joomcode/cue/cue/token" 25 ) 26 27 // A PackageError describes an error loading information about a package. 28 type PackageError struct { 29 ImportStack []string // shortest path from package named on command line to this one 30 Pos token.Pos // position of error 31 errors.Message // the error itself 32 IsImportCycle bool // the error is an import cycle 33 } 34 35 func (p *PackageError) Position() token.Pos { return p.Pos } 36 func (p *PackageError) InputPositions() []token.Pos { return nil } 37 func (p *PackageError) Path() []string { return p.ImportStack } 38 39 func (l *loader) errPkgf(importPos []token.Pos, format string, args ...interface{}) *PackageError { 40 err := &PackageError{ 41 ImportStack: l.stk.Copy(), 42 Message: errors.NewMessage(format, args), 43 } 44 err.fillPos(l.cfg.Dir, importPos) 45 return err 46 } 47 48 func (p *PackageError) fillPos(cwd string, positions []token.Pos) { 49 if len(positions) > 0 && !p.Pos.IsValid() { 50 p.Pos = positions[0] 51 } 52 } 53 54 // TODO(localize) 55 func (p *PackageError) Error() string { 56 // Import cycles deserve special treatment. 57 if p.IsImportCycle { 58 return fmt.Sprintf("%s\npackage %s\n", p.Message, strings.Join(p.ImportStack, "\n\timports ")) 59 } 60 if p.Pos.IsValid() { 61 // Omit import stack. The full path to the file where the error 62 // is the most important thing. 63 return p.Pos.String() + ": " + p.Message.Error() 64 } 65 if len(p.ImportStack) == 0 { 66 return p.Message.Error() 67 } 68 return "package " + strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Message.Error() 69 } 70 71 // NoFilesError is the error used by Import to describe a directory 72 // containing no usable source files. (It may still contain 73 // tool files, files hidden by build tags, and so on.) 74 type NoFilesError struct { 75 Package *build.Instance 76 77 ignored bool // whether any Go files were ignored due to build tags 78 } 79 80 func (e *NoFilesError) Position() token.Pos { return token.NoPos } 81 func (e *NoFilesError) InputPositions() []token.Pos { return nil } 82 func (e *NoFilesError) Path() []string { return nil } 83 84 // TODO(localize) 85 func (e *NoFilesError) Msg() (string, []interface{}) { return e.Error(), nil } 86 87 // TODO(localize) 88 func (e *NoFilesError) Error() string { 89 // Count files beginning with _, which we will pretend don't exist at all. 90 dummy := 0 91 for _, f := range e.Package.IgnoredFiles { 92 if strings.HasPrefix(filepath.Base(f.Filename), "_") { 93 dummy++ 94 } 95 } 96 97 // path := shortPath(e.Package.Root, e.Package.Dir) 98 path := e.Package.DisplayPath 99 100 if len(e.Package.IgnoredFiles) > dummy { 101 b := strings.Builder{} 102 b.WriteString("build constraints exclude all CUE files in ") 103 b.WriteString(path) 104 b.WriteString(":") 105 // CUE files exist, but they were ignored due to build constraints. 106 for _, f := range e.Package.IgnoredFiles { 107 b.WriteString("\n ") 108 b.WriteString(filepath.ToSlash(e.Package.RelPath(f))) 109 if f.ExcludeReason != nil { 110 b.WriteString(": ") 111 b.WriteString(f.ExcludeReason.Error()) 112 } 113 } 114 return b.String() 115 } 116 // if len(e.Package.TestCUEFiles) > 0 { 117 // // Test CUE files exist, but we're not interested in them. 118 // // The double-negative is unfortunate but we want e.Package.Dir 119 // // to appear at the end of error message. 120 // return "no non-test CUE files in " + e.Package.Dir 121 // } 122 return "no CUE files in " + path 123 } 124 125 // MultiplePackageError describes an attempt to build a package composed of 126 // CUE files from different packages. 127 type MultiplePackageError struct { 128 Dir string // directory containing files 129 Packages []string // package names found 130 Files []string // corresponding files: Files[i] declares package Packages[i] 131 } 132 133 func (e *MultiplePackageError) Position() token.Pos { return token.NoPos } 134 func (e *MultiplePackageError) InputPositions() []token.Pos { return nil } 135 func (e *MultiplePackageError) Path() []string { return nil } 136 137 func (e *MultiplePackageError) Msg() (string, []interface{}) { 138 return "found packages %q (%s) and %s (%s) in %q", []interface{}{ 139 e.Packages[0], 140 e.Files[0], 141 e.Packages[1], 142 e.Files[1], 143 e.Dir, 144 } 145 } 146 147 func (e *MultiplePackageError) Error() string { 148 // Error string limited to two entries for compatibility. 149 format, args := e.Msg() 150 return fmt.Sprintf(format, args...) 151 }