aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/go/internal/load/pkg.go
diff options
context:
space:
mode:
authorFilippo Valsorda <filippo@golang.org>2019-11-19 15:20:53 -0500
committerFilippo Valsorda <filippo@golang.org>2019-11-19 15:31:40 -0500
commit62ce702c77915c6fddc2fcbd95265df4b2f17a08 (patch)
tree87f1ce85fc3be1123ed5fd659fbcb75c362b2a98 /src/cmd/go/internal/load/pkg.go
parente8f14494a08bde693818a31f38310a82e4e63582 (diff)
parentec732632c2c26dadf424462ac42ebd32dce3ee88 (diff)
downloadgo-62ce702c77915c6fddc2fcbd95265df4b2f17a08.tar.gz
go-62ce702c77915c6fddc2fcbd95265df4b2f17a08.zip
[dev.boringcrypto] all: merge master into dev.boringcrypto
Signing-side signature algorithm selection moved to selectSignatureScheme, so add FIPS logic there. Change-Id: I827e7296d01ecfd36072e2139e74603ef42c6b24
Diffstat (limited to 'src/cmd/go/internal/load/pkg.go')
-rw-r--r--src/cmd/go/internal/load/pkg.go202
1 files changed, 148 insertions, 54 deletions
diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go
index 64267a4a46..b7ba884da6 100644
--- a/src/cmd/go/internal/load/pkg.go
+++ b/src/cmd/go/internal/load/pkg.go
@@ -7,6 +7,7 @@ package load
import (
"bytes"
+ "encoding/json"
"errors"
"fmt"
"go/build"
@@ -40,7 +41,7 @@ var (
ModPackageModuleInfo func(path string) *modinfo.ModulePublic // return module info for Package struct
ModImportPaths func(args []string) []*search.Match // expand import paths
ModPackageBuildInfo func(main string, deps []string) string // return module info to embed in binary
- ModInfoProg func(info string) []byte // wrap module info in .go code for binary
+ ModInfoProg func(info string, isgccgo bool) []byte // wrap module info in .go code for binary
ModImportFromFiles func([]string) // update go.mod to add modules for imports in these files
ModDirImportPath func(string) string // return effective import path for directory
)
@@ -310,9 +311,9 @@ func (p *Package) copyBuild(pp *build.Package) {
type PackageError struct {
ImportStack []string // shortest path from package named on command line to this one
Pos string // position of error
- Err string // the error itself
- IsImportCycle bool `json:"-"` // the error is an import cycle
- Hard bool `json:"-"` // whether the error is soft or hard; soft errors are ignored in some places
+ Err error // the error itself
+ IsImportCycle bool // the error is an import cycle
+ Hard bool // whether the error is soft or hard; soft errors are ignored in some places
}
func (p *PackageError) Error() string {
@@ -323,12 +324,77 @@ func (p *PackageError) Error() string {
if p.Pos != "" {
// Omit import stack. The full path to the file where the error
// is the most important thing.
- return p.Pos + ": " + p.Err
+ return p.Pos + ": " + p.Err.Error()
}
- if len(p.ImportStack) == 0 {
- return p.Err
+
+ // If the error is an ImportPathError, and the last path on the stack appears
+ // in the error message, omit that path from the stack to avoid repetition.
+ // If an ImportPathError wraps another ImportPathError that matches the
+ // last path on the stack, we don't omit the path. An error like
+ // "package A imports B: error loading C caused by B" would not be clearer
+ // if "imports B" were omitted.
+ stack := p.ImportStack
+ var ierr ImportPathError
+ if len(stack) > 0 && errors.As(p.Err, &ierr) && ierr.ImportPath() == stack[len(stack)-1] {
+ stack = stack[:len(stack)-1]
+ }
+ if len(stack) == 0 {
+ return p.Err.Error()
+ }
+ return "package " + strings.Join(stack, "\n\timports ") + ": " + p.Err.Error()
+}
+
+// PackageError implements MarshalJSON so that Err is marshaled as a string
+// and non-essential fields are omitted.
+func (p *PackageError) MarshalJSON() ([]byte, error) {
+ perr := struct {
+ ImportStack []string
+ Pos string
+ Err string
+ }{p.ImportStack, p.Pos, p.Err.Error()}
+ return json.Marshal(perr)
+}
+
+// ImportPathError is a type of error that prevents a package from being loaded
+// for a given import path. When such a package is loaded, a *Package is
+// returned with Err wrapping an ImportPathError: the error is attached to
+// the imported package, not the importing package.
+//
+// The string returned by ImportPath must appear in the string returned by
+// Error. Errors that wrap ImportPathError (such as PackageError) may omit
+// the import path.
+type ImportPathError interface {
+ error
+ ImportPath() string
+}
+
+type importError struct {
+ importPath string
+ err error // created with fmt.Errorf
+}
+
+var _ ImportPathError = (*importError)(nil)
+
+func ImportErrorf(path, format string, args ...interface{}) ImportPathError {
+ err := &importError{importPath: path, err: fmt.Errorf(format, args...)}
+ if errStr := err.Error(); !strings.Contains(errStr, path) {
+ panic(fmt.Sprintf("path %q not in error %q", path, errStr))
}
- return "package " + strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Err
+ return err
+}
+
+func (e *importError) Error() string {
+ return e.err.Error()
+}
+
+func (e *importError) Unwrap() error {
+ // Don't return e.err directly, since we're only wrapping an error if %w
+ // was passed to ImportErrorf.
+ return errors.Unwrap(e.err)
+}
+
+func (e *importError) ImportPath() string {
+ return e.importPath
}
// An ImportStack is a stack of import paths, possibly with the suffix " (test)" appended.
@@ -495,7 +561,7 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS
ImportPath: path,
Error: &PackageError{
ImportStack: stk.Copy(),
- Err: err.Error(),
+ Err: err,
},
},
}
@@ -522,7 +588,7 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS
if !cfg.ModulesEnabled && path != cleanImport(path) {
p.Error = &PackageError{
ImportStack: stk.Copy(),
- Err: fmt.Sprintf("non-canonical import path: %q should be %q", path, pathpkg.Clean(path)),
+ Err: fmt.Errorf("non-canonical import path: %q should be %q", path, pathpkg.Clean(path)),
}
p.Incomplete = true
}
@@ -533,7 +599,7 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS
return setErrorPos(perr, importPos)
}
if mode&ResolveImport != 0 {
- if perr := disallowVendor(srcDir, parent, parentPath, path, p, stk); perr != p {
+ if perr := disallowVendor(srcDir, path, p, stk); perr != p {
return setErrorPos(perr, importPos)
}
}
@@ -542,20 +608,22 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS
perr := *p
perr.Error = &PackageError{
ImportStack: stk.Copy(),
- Err: fmt.Sprintf("import %q is a program, not an importable package", path),
+ Err: ImportErrorf(path, "import %q is a program, not an importable package", path),
}
return setErrorPos(&perr, importPos)
}
if p.Internal.Local && parent != nil && !parent.Internal.Local {
perr := *p
- errMsg := fmt.Sprintf("local import %q in non-local package", path)
+ var err error
if path == "." {
- errMsg = "cannot import current directory"
+ err = ImportErrorf(path, "%s: cannot import current directory", path)
+ } else {
+ err = ImportErrorf(path, "local import %q in non-local package", path)
}
perr.Error = &PackageError{
ImportStack: stk.Copy(),
- Err: errMsg,
+ Err: err,
}
return setErrorPos(&perr, importPos)
}
@@ -1131,7 +1199,7 @@ func reusePackage(p *Package, stk *ImportStack) *Package {
if p.Error == nil {
p.Error = &PackageError{
ImportStack: stk.Copy(),
- Err: "import cycle not allowed",
+ Err: errors.New("import cycle not allowed"),
IsImportCycle: true,
}
}
@@ -1234,7 +1302,7 @@ func disallowInternal(srcDir string, importer *Package, importerPath string, p *
perr := *p
perr.Error = &PackageError{
ImportStack: stk.Copy(),
- Err: "use of internal package " + p.ImportPath + " not allowed",
+ Err: ImportErrorf(p.ImportPath, "use of internal package "+p.ImportPath+" not allowed"),
}
perr.Incomplete = true
return &perr
@@ -1259,11 +1327,10 @@ func findInternal(path string) (index int, ok bool) {
return 0, false
}
-// disallowVendor checks that srcDir (containing package importerPath, if non-empty)
-// is allowed to import p as path.
+// disallowVendor checks that srcDir is allowed to import p as path.
// If the import is allowed, disallowVendor returns the original package p.
// If not, it returns a new package containing just an appropriate error.
-func disallowVendor(srcDir string, importer *Package, importerPath, path string, p *Package, stk *ImportStack) *Package {
+func disallowVendor(srcDir string, path string, p *Package, stk *ImportStack) *Package {
// The stack includes p.ImportPath.
// If that's the only thing on the stack, we started
// with a name given on the command line, not an
@@ -1281,7 +1348,7 @@ func disallowVendor(srcDir string, importer *Package, importerPath, path string,
perr := *p
perr.Error = &PackageError{
ImportStack: stk.Copy(),
- Err: "must be imported as " + path[i+len("vendor/"):],
+ Err: ImportErrorf(path, "%s must be imported as %s", path, path[i+len("vendor/"):]),
}
perr.Incomplete = true
return &perr
@@ -1335,7 +1402,7 @@ func disallowVendorVisibility(srcDir string, p *Package, stk *ImportStack) *Pack
perr := *p
perr.Error = &PackageError{
ImportStack: stk.Copy(),
- Err: "use of vendored package not allowed",
+ Err: errors.New("use of vendored package not allowed"),
}
perr.Incomplete = true
return &perr
@@ -1397,26 +1464,51 @@ var cgoSyscallExclude = map[string]bool{
var foldPath = make(map[string]string)
-// DefaultExecName returns the default executable name
-// for a package with the import path importPath.
+// exeFromImportPath returns an executable name
+// for a package using the import path.
//
-// The default executable name is the last element of the import path.
+// The executable name is the last element of the import path.
// In module-aware mode, an additional rule is used on import paths
// consisting of two or more path elements. If the last element is
// a vN path element specifying the major version, then the
// second last element of the import path is used instead.
-func DefaultExecName(importPath string) string {
- _, elem := pathpkg.Split(importPath)
+func (p *Package) exeFromImportPath() string {
+ _, elem := pathpkg.Split(p.ImportPath)
if cfg.ModulesEnabled {
// If this is example.com/mycmd/v2, it's more useful to
// install it as mycmd than as v2. See golang.org/issue/24667.
- if elem != importPath && isVersionElement(elem) {
- _, elem = pathpkg.Split(pathpkg.Dir(importPath))
+ if elem != p.ImportPath && isVersionElement(elem) {
+ _, elem = pathpkg.Split(pathpkg.Dir(p.ImportPath))
}
}
return elem
}
+// exeFromFiles returns an executable name for a package
+// using the first element in GoFiles or CgoFiles collections without the prefix.
+//
+// Returns empty string in case of empty collection.
+func (p *Package) exeFromFiles() string {
+ var src string
+ if len(p.GoFiles) > 0 {
+ src = p.GoFiles[0]
+ } else if len(p.CgoFiles) > 0 {
+ src = p.CgoFiles[0]
+ } else {
+ return ""
+ }
+ _, elem := filepath.Split(src)
+ return elem[:len(elem)-len(".go")]
+}
+
+// DefaultExecName returns the default executable name for a package
+func (p *Package) DefaultExecName() string {
+ if p.Internal.CmdlineFiles {
+ return p.exeFromFiles()
+ }
+ return p.exeFromImportPath()
+}
+
// load populates p using information from bp, err, which should
// be the result of calling build.Context.Import.
func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
@@ -1436,7 +1528,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
err = base.ExpandScanner(err)
p.Error = &PackageError{
ImportStack: stk.Copy(),
- Err: err.Error(),
+ Err: err,
}
return
}
@@ -1453,11 +1545,11 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
// Report an error when the old code.google.com/p/go.tools paths are used.
if InstallTargetDir(p) == StalePath {
newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1)
- e := fmt.Sprintf("the %v command has moved; use %v instead.", p.ImportPath, newPath)
+ e := ImportErrorf(p.ImportPath, "the %v command has moved; use %v instead.", p.ImportPath, newPath)
p.Error = &PackageError{Err: e}
return
}
- elem := DefaultExecName(p.ImportPath)
+ elem := p.DefaultExecName()
full := cfg.BuildContext.GOOS + "_" + cfg.BuildContext.GOARCH + "/" + elem
if cfg.BuildContext.GOOS != base.ToolGOOS || cfg.BuildContext.GOARCH != base.ToolGOARCH {
// Install cross-compiled binaries to subdirectories of bin.
@@ -1566,7 +1658,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
if f1 != "" {
p.Error = &PackageError{
ImportStack: stk.Copy(),
- Err: fmt.Sprintf("case-insensitive file name collision: %q and %q", f1, f2),
+ Err: fmt.Errorf("case-insensitive file name collision: %q and %q", f1, f2),
}
return
}
@@ -1582,7 +1674,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
if !SafeArg(file) || strings.HasPrefix(file, "_cgo_") {
p.Error = &PackageError{
ImportStack: stk.Copy(),
- Err: fmt.Sprintf("invalid input file name %q", file),
+ Err: fmt.Errorf("invalid input file name %q", file),
}
return
}
@@ -1590,14 +1682,14 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
if name := pathpkg.Base(p.ImportPath); !SafeArg(name) {
p.Error = &PackageError{
ImportStack: stk.Copy(),
- Err: fmt.Sprintf("invalid input directory name %q", name),
+ Err: fmt.Errorf("invalid input directory name %q", name),
}
return
}
if !SafeArg(p.ImportPath) {
p.Error = &PackageError{
ImportStack: stk.Copy(),
- Err: fmt.Sprintf("invalid import path %q", p.ImportPath),
+ Err: ImportErrorf(p.ImportPath, "invalid import path %q", p.ImportPath),
}
return
}
@@ -1643,31 +1735,31 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
// code; see issue #16050).
}
- setError := func(msg string) {
+ setError := func(err error) {
p.Error = &PackageError{
ImportStack: stk.Copy(),
- Err: msg,
+ Err: err,
}
}
// The gc toolchain only permits C source files with cgo or SWIG.
if len(p.CFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() && cfg.BuildContext.Compiler == "gc" {
- setError(fmt.Sprintf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " ")))
+ setError(fmt.Errorf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " ")))
return
}
// C++, Objective-C, and Fortran source files are permitted only with cgo or SWIG,
// regardless of toolchain.
if len(p.CXXFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() {
- setError(fmt.Sprintf("C++ source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CXXFiles, " ")))
+ setError(fmt.Errorf("C++ source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CXXFiles, " ")))
return
}
if len(p.MFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() {
- setError(fmt.Sprintf("Objective-C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.MFiles, " ")))
+ setError(fmt.Errorf("Objective-C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.MFiles, " ")))
return
}
if len(p.FFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() {
- setError(fmt.Sprintf("Fortran source files not allowed when not using cgo or SWIG: %s", strings.Join(p.FFiles, " ")))
+ setError(fmt.Errorf("Fortran source files not allowed when not using cgo or SWIG: %s", strings.Join(p.FFiles, " ")))
return
}
@@ -1676,17 +1768,17 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
if other := foldPath[fold]; other == "" {
foldPath[fold] = p.ImportPath
} else if other != p.ImportPath {
- setError(fmt.Sprintf("case-insensitive import collision: %q and %q", p.ImportPath, other))
+ setError(ImportErrorf(p.ImportPath, "case-insensitive import collision: %q and %q", p.ImportPath, other))
return
}
- if cfg.ModulesEnabled {
+ if cfg.ModulesEnabled && p.Error == nil {
mainPath := p.ImportPath
if p.Internal.CmdlineFiles {
mainPath = "command-line-arguments"
}
p.Module = ModPackageModuleInfo(mainPath)
- if p.Name == "main" {
+ if p.Name == "main" && len(p.DepsErrors) == 0 {
p.Internal.BuildInfo = ModPackageBuildInfo(mainPath, p.Deps)
}
}
@@ -1956,9 +2048,14 @@ func Packages(args []string) []*Package {
// cannot be loaded at all.
// The packages that fail to load will have p.Error != nil.
func PackagesAndErrors(patterns []string) []*Package {
- if len(patterns) > 0 {
- for _, p := range patterns {
- if strings.HasSuffix(p, ".go") {
+ for _, p := range patterns {
+ // Listing is only supported with all patterns referring to either:
+ // - Files that are part of the same directory.
+ // - Explicit package paths or patterns.
+ if strings.HasSuffix(p, ".go") {
+ // We need to test whether the path is an actual Go file and not a
+ // package path or pattern ending in '.go' (see golang.org/issue/34653).
+ if fi, err := os.Stat(p); err == nil && !fi.IsDir() {
return []*Package{GoFilesPackage(patterns)}
}
}
@@ -2078,7 +2175,7 @@ func GoFilesPackage(gofiles []string) *Package {
pkg.Internal.CmdlineFiles = true
pkg.Name = f
pkg.Error = &PackageError{
- Err: fmt.Sprintf("named files must be .go files: %s", pkg.Name),
+ Err: fmt.Errorf("named files must be .go files: %s", pkg.Name),
}
return pkg
}
@@ -2141,11 +2238,8 @@ func GoFilesPackage(gofiles []string) *Package {
pkg.Match = gofiles
if pkg.Name == "main" {
- _, elem := filepath.Split(gofiles[0])
- exe := elem[:len(elem)-len(".go")] + cfg.ExeSuffix
- if cfg.BuildO == "" {
- cfg.BuildO = exe
- }
+ exe := pkg.DefaultExecName() + cfg.ExeSuffix
+
if cfg.GOBIN != "" {
pkg.Target = filepath.Join(cfg.GOBIN, exe)
} else if cfg.ModulesEnabled {