mirror of
https://github.com/golang/go.git
synced 2025-11-10 21:51:05 +00:00
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 <jayconrod@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Bryan C. Mills <bcmills@google.com> Trust: Jay Conrod <jayconrod@google.com>
This commit is contained in:
parent
ba76567bc2
commit
7eb31d999c
4 changed files with 65 additions and 25 deletions
|
|
@ -130,25 +130,57 @@ func (e *AmbiguousImportError) Error() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportMissingSumError is reported in readonly mode when we need to check
|
// 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
|
// if a module contains a package, but we don't have a sum for its .zip file.
|
||||||
// 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 {
|
type ImportMissingSumError struct {
|
||||||
importPath string
|
importPath string
|
||||||
modPaths []string
|
found bool
|
||||||
found, inAll bool
|
mods []module.Version
|
||||||
|
importer, importerVersion string // optional, but used for additional context
|
||||||
|
importerIsTest bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ImportMissingSumError) Error() string {
|
func (e *ImportMissingSumError) Error() string {
|
||||||
|
var importParen string
|
||||||
|
if e.importer != "" {
|
||||||
|
importParen = fmt.Sprintf(" (imported by %s)", e.importer)
|
||||||
|
}
|
||||||
var message string
|
var message string
|
||||||
if e.found {
|
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 {
|
} 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 {
|
var hint string
|
||||||
return message + fmt.Sprintf("; to add it:\n\tgo mod download %s", strings.Join(e.modPaths, " "))
|
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 {
|
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.
|
// Check each module on the build list.
|
||||||
var dirs []string
|
var dirs []string
|
||||||
var mods []module.Version
|
var mods []module.Version
|
||||||
var sumErrModPaths []string
|
var sumErrMods []module.Version
|
||||||
for _, m := range buildList {
|
for _, m := range buildList {
|
||||||
if !maybeInModule(path, m.Path) {
|
if !maybeInModule(path, m.Path) {
|
||||||
// Avoid possibly downloading irrelevant modules.
|
// 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
|
// 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
|
// 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
|
// 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.
|
// multiple nested modules to resolve the import.
|
||||||
sumErrModPaths = append(sumErrModPaths, m.Path)
|
sumErrMods = append(sumErrMods, m)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Report fetch error.
|
// Report fetch error.
|
||||||
|
|
@ -275,8 +307,12 @@ func importFromBuildList(ctx context.Context, path string, buildList []module.Ve
|
||||||
if len(mods) > 1 {
|
if len(mods) > 1 {
|
||||||
return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: dirs, Modules: mods}
|
return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: dirs, Modules: mods}
|
||||||
}
|
}
|
||||||
if len(sumErrModPaths) > 0 {
|
if len(sumErrMods) > 0 {
|
||||||
return module.Version{}, "", &ImportMissingSumError{importPath: path, modPaths: sumErrModPaths, found: len(mods) > 0}
|
return module.Version{}, "", &ImportMissingSumError{
|
||||||
|
importPath: path,
|
||||||
|
mods: sumErrMods,
|
||||||
|
found: len(mods) > 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if len(mods) == 1 {
|
if len(mods) == 1 {
|
||||||
return mods[0], dirs[0], nil
|
return mods[0], dirs[0], nil
|
||||||
|
|
|
||||||
|
|
@ -280,9 +280,11 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
|
||||||
checkMultiplePaths()
|
checkMultiplePaths()
|
||||||
for _, pkg := range loaded.pkgs {
|
for _, pkg := range loaded.pkgs {
|
||||||
if pkg.err != nil {
|
if pkg.err != nil {
|
||||||
if pkg.flags.has(pkgInAll) {
|
if sumErr := (*ImportMissingSumError)(nil); errors.As(pkg.err, &sumErr) {
|
||||||
if sumErr := (*ImportMissingSumError)(nil); errors.As(pkg.err, &sumErr) {
|
if importer := pkg.stack; importer != nil {
|
||||||
sumErr.inAll = true
|
sumErr.importer = importer.path
|
||||||
|
sumErr.importerVersion = importer.mod.Version
|
||||||
|
sumErr.importerIsTest = importer.testOf != nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
12
src/cmd/go/testdata/script/mod_sum_ambiguous.txt
vendored
12
src/cmd/go/testdata/script/mod_sum_ambiguous.txt
vendored
|
|
@ -23,19 +23,21 @@ grep '^example.com/ambiguous/a/b v0.0.0-empty h1:' go.sum
|
||||||
# provides the package.
|
# provides the package.
|
||||||
cp go.sum.a-only go.sum
|
cp go.sum.a-only go.sum
|
||||||
! go list example.com/ambiguous/a/b
|
! 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 .
|
! 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
|
cp go.sum.b-only go.sum
|
||||||
! go list example.com/ambiguous/a/b
|
! 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 .
|
! 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
|
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 .
|
! 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 --
|
-- go.mod --
|
||||||
module m
|
module m
|
||||||
|
|
|
||||||
|
|
@ -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.
|
# When a sum is needed to load a .zip file, we get a more specific error.
|
||||||
# The .zip file is not downloaded.
|
# The .zip file is not downloaded.
|
||||||
! go list rsc.io/quote
|
! 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
|
! 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
|
# The error is attached to the package from the missing module. We can load
|
||||||
# a package that imports it without that error.
|
# a package that imports it without that error.
|
||||||
go list -e -deps -f '{{.ImportPath}}{{with .Error}} {{.Err}}{{end}}' .
|
go list -e -deps -f '{{.ImportPath}}{{with .Error}} {{.Err}}{{end}}' .
|
||||||
stdout '^m$'
|
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
|
! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
|
||||||
|
|
||||||
# go.sum should not have been written.
|
# go.sum should not have been written.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue