From: Jay Conrod Date: Fri, 8 Jan 2021 20:14:22 +0000 (-0500) Subject: cmd/go: add hints to more missing sum error messages X-Git-Tag: go1.16rc1~85 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=7eb31d999c;p=gostls13.git cmd/go: add hints to more missing sum error messages When a command fails due to a module zip sum missing from go.sum, if the module is in the build list, the go command will print a 'go mod download' command the user can run to fix it. Previously, a hint was only printed if the module provided a package in 'all'. We don't print a 'go get' hint, since we may not want to add a new requirement to go.mod. Fixes #43572 Change-Id: I88c61b1b42ad56c04e4482f6a1bb97ce758aaeff Reviewed-on: https://go-review.googlesource.com/c/go/+/282712 Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills Trust: Jay Conrod --- diff --git a/src/cmd/go/internal/modload/import.go b/src/cmd/go/internal/modload/import.go index 9925d5b905..182429aee4 100644 --- a/src/cmd/go/internal/modload/import.go +++ b/src/cmd/go/internal/modload/import.go @@ -130,25 +130,57 @@ func (e *AmbiguousImportError) Error() string { } // ImportMissingSumError is reported in readonly mode when we need to check -// if a module in the build list contains a package, but we don't have a sum -// for its .zip file. +// if a module contains a package, but we don't have a sum for its .zip file. +// We might need sums for multiple modules to verify the package is unique. +// +// TODO(#43653): consolidate multiple errors of this type into a single error +// that suggests a 'go get' command for root packages that transtively import +// packages from modules with missing sums. load.CheckPackageErrors would be +// a good place to consolidate errors, but we'll need to attach the import +// stack here. type ImportMissingSumError struct { - importPath string - modPaths []string - found, inAll bool + importPath string + found bool + mods []module.Version + importer, importerVersion string // optional, but used for additional context + importerIsTest bool } func (e *ImportMissingSumError) Error() string { + var importParen string + if e.importer != "" { + importParen = fmt.Sprintf(" (imported by %s)", e.importer) + } var message string if e.found { - message = fmt.Sprintf("missing go.sum entry needed to verify package %s is provided by exactly one module", e.importPath) + message = fmt.Sprintf("missing go.sum entry needed to verify package %s%s is provided by exactly one module", e.importPath, importParen) } else { - message = fmt.Sprintf("missing go.sum entry for module providing package %s", e.importPath) + message = fmt.Sprintf("missing go.sum entry for module providing package %s%s", e.importPath, importParen) } - if e.inAll { - return message + fmt.Sprintf("; to add it:\n\tgo mod download %s", strings.Join(e.modPaths, " ")) + var hint string + if e.importer == "" { + // Importing package is unknown, or the missing package was named on the + // command line. Recommend 'go mod download' for the modules that could + // provide the package, since that shouldn't change go.mod. + args := make([]string, len(e.mods)) + for i, mod := range e.mods { + args[i] = mod.Path + } + hint = fmt.Sprintf("; to add:\n\tgo mod download %s", strings.Join(args, " ")) + } else { + // Importing package is known (common case). Recommend 'go get' on the + // current version of the importing package. + tFlag := "" + if e.importerIsTest { + tFlag = " -t" + } + version := "" + if e.importerVersion != "" { + version = "@" + e.importerVersion + } + hint = fmt.Sprintf("; to add:\n\tgo get%s %s%s", tFlag, e.importer, version) } - return message + return message + hint } func (e *ImportMissingSumError) ImportPath() string { @@ -239,7 +271,7 @@ func importFromBuildList(ctx context.Context, path string, buildList []module.Ve // Check each module on the build list. var dirs []string var mods []module.Version - var sumErrModPaths []string + var sumErrMods []module.Version for _, m := range buildList { if !maybeInModule(path, m.Path) { // Avoid possibly downloading irrelevant modules. @@ -253,8 +285,8 @@ func importFromBuildList(ctx context.Context, path string, buildList []module.Ve // We can't verify that the package is unique, and we may not find // the package at all. Keep checking other modules to decide which // error to report. Multiple sums may be missing if we need to look in - // multiple nested modules to resolve the import; we'll report them all. - sumErrModPaths = append(sumErrModPaths, m.Path) + // multiple nested modules to resolve the import. + sumErrMods = append(sumErrMods, m) continue } // Report fetch error. @@ -275,8 +307,12 @@ func importFromBuildList(ctx context.Context, path string, buildList []module.Ve if len(mods) > 1 { return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: dirs, Modules: mods} } - if len(sumErrModPaths) > 0 { - return module.Version{}, "", &ImportMissingSumError{importPath: path, modPaths: sumErrModPaths, found: len(mods) > 0} + if len(sumErrMods) > 0 { + return module.Version{}, "", &ImportMissingSumError{ + importPath: path, + mods: sumErrMods, + found: len(mods) > 0, + } } if len(mods) == 1 { return mods[0], dirs[0], nil diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index cd36da6a87..6d87acc6d3 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -280,9 +280,11 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma checkMultiplePaths() for _, pkg := range loaded.pkgs { if pkg.err != nil { - if pkg.flags.has(pkgInAll) { - if sumErr := (*ImportMissingSumError)(nil); errors.As(pkg.err, &sumErr) { - sumErr.inAll = true + if sumErr := (*ImportMissingSumError)(nil); errors.As(pkg.err, &sumErr) { + if importer := pkg.stack; importer != nil { + sumErr.importer = importer.path + sumErr.importerVersion = importer.mod.Version + sumErr.importerIsTest = importer.testOf != nil } } diff --git a/src/cmd/go/testdata/script/mod_sum_ambiguous.txt b/src/cmd/go/testdata/script/mod_sum_ambiguous.txt index 5344dc0029..07c6659177 100644 --- a/src/cmd/go/testdata/script/mod_sum_ambiguous.txt +++ b/src/cmd/go/testdata/script/mod_sum_ambiguous.txt @@ -23,19 +23,21 @@ grep '^example.com/ambiguous/a/b v0.0.0-empty h1:' go.sum # provides the package. cp go.sum.a-only go.sum ! go list example.com/ambiguous/a/b -stderr '^missing go.sum entry needed to verify package example.com/ambiguous/a/b is provided by exactly one module$' +stderr '^missing go.sum entry needed to verify package example.com/ambiguous/a/b is provided by exactly one module; to add:\n\tgo mod download example.com/ambiguous/a/b$' ! go list -deps . -stderr '^use.go:3:8: missing go.sum entry needed to verify package example.com/ambiguous/a/b is provided by exactly one module; to add it:\n\tgo mod download example.com/ambiguous/a/b$' +stderr '^use.go:3:8: missing go.sum entry needed to verify package example.com/ambiguous/a/b \(imported by m\) is provided by exactly one module; to add:\n\tgo get m$' cp go.sum.b-only go.sum ! go list example.com/ambiguous/a/b -stderr '^missing go.sum entry for module providing package example.com/ambiguous/a/b$' +stderr '^missing go.sum entry for module providing package example.com/ambiguous/a/b; to add:\n\tgo mod download example.com/ambiguous/a$' ! go list -deps . -stderr '^use.go:3:8: missing go.sum entry for module providing package example.com/ambiguous/a/b; to add it:\n\tgo mod download example.com/ambiguous/a$' +stderr '^use.go:3:8: missing go.sum entry for module providing package example.com/ambiguous/a/b \(imported by m\); to add:\n\tgo get m$' cp go.sum.buildlist-only go.sum +! go list example.com/ambiguous/a/b +stderr '^missing go.sum entry for module providing package example.com/ambiguous/a/b; to add:\n\tgo mod download example.com/ambiguous/a example.com/ambiguous/a/b$' ! go list -deps . -stderr '^use.go:3:8: missing go.sum entry for module providing package example.com/ambiguous/a/b; to add it:\n\tgo mod download example.com/ambiguous/a example.com/ambiguous/a/b$' +stderr '^use.go:3:8: missing go.sum entry for module providing package example.com/ambiguous/a/b \(imported by m\); to add:\n\tgo get m$' -- go.mod -- module m diff --git a/src/cmd/go/testdata/script/mod_sum_readonly.txt b/src/cmd/go/testdata/script/mod_sum_readonly.txt index 00b4d7b5d2..57c5bbeefd 100644 --- a/src/cmd/go/testdata/script/mod_sum_readonly.txt +++ b/src/cmd/go/testdata/script/mod_sum_readonly.txt @@ -40,14 +40,14 @@ stderr '^no required module provides package example.com/doesnotexist; to add it # When a sum is needed to load a .zip file, we get a more specific error. # The .zip file is not downloaded. ! go list rsc.io/quote -stderr '^missing go.sum entry for module providing package rsc.io/quote$' +stderr '^missing go.sum entry for module providing package rsc.io/quote; to add:\n\tgo mod download rsc.io/quote$' ! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip # The error is attached to the package from the missing module. We can load # a package that imports it without that error. go list -e -deps -f '{{.ImportPath}}{{with .Error}} {{.Err}}{{end}}' . stdout '^m$' -stdout '^rsc.io/quote missing go.sum entry for module providing package rsc.io/quote; to add it:\n\tgo mod download rsc.io/quote$' +stdout '^rsc.io/quote missing go.sum entry for module providing package rsc.io/quote \(imported by m\); to add:\n\tgo get m$' ! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip # go.sum should not have been written.