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  }