Skip to content

Commit 7eb31d9

Browse files
author
Jay Conrod
committed
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>
1 parent ba76567 commit 7eb31d9

File tree

4 files changed

+65
-25
lines changed

4 files changed

+65
-25
lines changed

src/cmd/go/internal/modload/import.go

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -130,25 +130,57 @@ func (e *AmbiguousImportError) Error() string {
130130
}
131131

132132
// ImportMissingSumError is reported in readonly mode when we need to check
133-
// if a module in the build list contains a package, but we don't have a sum
134-
// for its .zip file.
133+
// if a module contains a package, but we don't have a sum for its .zip file.
134+
// We might need sums for multiple modules to verify the package is unique.
135+
//
136+
// TODO(#43653): consolidate multiple errors of this type into a single error
137+
// that suggests a 'go get' command for root packages that transtively import
138+
// packages from modules with missing sums. load.CheckPackageErrors would be
139+
// a good place to consolidate errors, but we'll need to attach the import
140+
// stack here.
135141
type ImportMissingSumError struct {
136-
importPath string
137-
modPaths []string
138-
found, inAll bool
142+
importPath string
143+
found bool
144+
mods []module.Version
145+
importer, importerVersion string // optional, but used for additional context
146+
importerIsTest bool
139147
}
140148

141149
func (e *ImportMissingSumError) Error() string {
150+
var importParen string
151+
if e.importer != "" {
152+
importParen = fmt.Sprintf(" (imported by %s)", e.importer)
153+
}
142154
var message string
143155
if e.found {
144-
message = fmt.Sprintf("missing go.sum entry needed to verify package %s is provided by exactly one module", e.importPath)
156+
message = fmt.Sprintf("missing go.sum entry needed to verify package %s%s is provided by exactly one module", e.importPath, importParen)
145157
} else {
146-
message = fmt.Sprintf("missing go.sum entry for module providing package %s", e.importPath)
158+
message = fmt.Sprintf("missing go.sum entry for module providing package %s%s", e.importPath, importParen)
147159
}
148-
if e.inAll {
149-
return message + fmt.Sprintf("; to add it:\n\tgo mod download %s", strings.Join(e.modPaths, " "))
160+
var hint string
161+
if e.importer == "" {
162+
// Importing package is unknown, or the missing package was named on the
163+
// command line. Recommend 'go mod download' for the modules that could
164+
// provide the package, since that shouldn't change go.mod.
165+
args := make([]string, len(e.mods))
166+
for i, mod := range e.mods {
167+
args[i] = mod.Path
168+
}
169+
hint = fmt.Sprintf("; to add:\n\tgo mod download %s", strings.Join(args, " "))
170+
} else {
171+
// Importing package is known (common case). Recommend 'go get' on the
172+
// current version of the importing package.
173+
tFlag := ""
174+
if e.importerIsTest {
175+
tFlag = " -t"
176+
}
177+
version := ""
178+
if e.importerVersion != "" {
179+
version = "@" + e.importerVersion
180+
}
181+
hint = fmt.Sprintf("; to add:\n\tgo get%s %s%s", tFlag, e.importer, version)
150182
}
151-
return message
183+
return message + hint
152184
}
153185

154186
func (e *ImportMissingSumError) ImportPath() string {
@@ -239,7 +271,7 @@ func importFromBuildList(ctx context.Context, path string, buildList []module.Ve
239271
// Check each module on the build list.
240272
var dirs []string
241273
var mods []module.Version
242-
var sumErrModPaths []string
274+
var sumErrMods []module.Version
243275
for _, m := range buildList {
244276
if !maybeInModule(path, m.Path) {
245277
// Avoid possibly downloading irrelevant modules.
@@ -253,8 +285,8 @@ func importFromBuildList(ctx context.Context, path string, buildList []module.Ve
253285
// We can't verify that the package is unique, and we may not find
254286
// the package at all. Keep checking other modules to decide which
255287
// error to report. Multiple sums may be missing if we need to look in
256-
// multiple nested modules to resolve the import; we'll report them all.
257-
sumErrModPaths = append(sumErrModPaths, m.Path)
288+
// multiple nested modules to resolve the import.
289+
sumErrMods = append(sumErrMods, m)
258290
continue
259291
}
260292
// Report fetch error.
@@ -275,8 +307,12 @@ func importFromBuildList(ctx context.Context, path string, buildList []module.Ve
275307
if len(mods) > 1 {
276308
return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: dirs, Modules: mods}
277309
}
278-
if len(sumErrModPaths) > 0 {
279-
return module.Version{}, "", &ImportMissingSumError{importPath: path, modPaths: sumErrModPaths, found: len(mods) > 0}
310+
if len(sumErrMods) > 0 {
311+
return module.Version{}, "", &ImportMissingSumError{
312+
importPath: path,
313+
mods: sumErrMods,
314+
found: len(mods) > 0,
315+
}
280316
}
281317
if len(mods) == 1 {
282318
return mods[0], dirs[0], nil

src/cmd/go/internal/modload/load.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,9 +280,11 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
280280
checkMultiplePaths()
281281
for _, pkg := range loaded.pkgs {
282282
if pkg.err != nil {
283-
if pkg.flags.has(pkgInAll) {
284-
if sumErr := (*ImportMissingSumError)(nil); errors.As(pkg.err, &sumErr) {
285-
sumErr.inAll = true
283+
if sumErr := (*ImportMissingSumError)(nil); errors.As(pkg.err, &sumErr) {
284+
if importer := pkg.stack; importer != nil {
285+
sumErr.importer = importer.path
286+
sumErr.importerVersion = importer.mod.Version
287+
sumErr.importerIsTest = importer.testOf != nil
286288
}
287289
}
288290

src/cmd/go/testdata/script/mod_sum_ambiguous.txt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,21 @@ grep '^example.com/ambiguous/a/b v0.0.0-empty h1:' go.sum
2323
# provides the package.
2424
cp go.sum.a-only go.sum
2525
! go list example.com/ambiguous/a/b
26-
stderr '^missing go.sum entry needed to verify package example.com/ambiguous/a/b is provided by exactly one module$'
26+
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$'
2727
! go list -deps .
28-
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$'
28+
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$'
2929

3030
cp go.sum.b-only go.sum
3131
! go list example.com/ambiguous/a/b
32-
stderr '^missing go.sum entry for module providing package example.com/ambiguous/a/b$'
32+
stderr '^missing go.sum entry for module providing package example.com/ambiguous/a/b; to add:\n\tgo mod download example.com/ambiguous/a$'
3333
! go list -deps .
34-
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$'
34+
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$'
3535

3636
cp go.sum.buildlist-only go.sum
37+
! go list example.com/ambiguous/a/b
38+
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$'
3739
! go list -deps .
38-
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$'
40+
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$'
3941

4042
-- go.mod --
4143
module m

src/cmd/go/testdata/script/mod_sum_readonly.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,14 @@ stderr '^no required module provides package example.com/doesnotexist; to add it
4040
# When a sum is needed to load a .zip file, we get a more specific error.
4141
# The .zip file is not downloaded.
4242
! go list rsc.io/quote
43-
stderr '^missing go.sum entry for module providing package rsc.io/quote$'
43+
stderr '^missing go.sum entry for module providing package rsc.io/quote; to add:\n\tgo mod download rsc.io/quote$'
4444
! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
4545

4646
# The error is attached to the package from the missing module. We can load
4747
# a package that imports it without that error.
4848
go list -e -deps -f '{{.ImportPath}}{{with .Error}} {{.Err}}{{end}}' .
4949
stdout '^m$'
50-
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$'
50+
stdout '^rsc.io/quote missing go.sum entry for module providing package rsc.io/quote \(imported by m\); to add:\n\tgo get m$'
5151
! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
5252

5353
# go.sum should not have been written.

0 commit comments

Comments
 (0)