From 7cd10c1149e51a9d2f0868babaf66b8091b9c0b9 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Tue, 27 Jul 2021 10:22:35 -0700 Subject: cmd/go: use .mod instead of .zip to determine if version has go.mod file When checking for updates, the go command checks whether the highest compatible version has a go.mod file in order to determine whether +incompatible versions may be considered "latest". Previously, to perform this check, the go command would download the content of the module (the .zip file) to see whether a go.mod file was present at the root. This is slower than necessary, and it caused 'go list -m -u' to try to save the sum for the .zip file in go.sum in some cases. With this change, the go command only downloads the .mod file and checks whether it appears to be a fake file generated for a version that didn't have a go.mod file. This is faster and requires less verification. Fake files only have a "module" directive. It's possible to commit a file that passes this test, but it would be difficult to do accidentally: Go 1.12 and later at least add a "go" directive. A false positive here would cause version queries to have slightly different results but would not affect builds. Fixes #47377 Change-Id: Ie5ffd0b45e39bd0921328a60af99a9f6e5ab6346 Reviewed-on: https://go-review.googlesource.com/c/go/+/337850 Trust: Jay Conrod Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Michael Matloob --- src/cmd/go/internal/modload/modfile.go | 83 ++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 40 deletions(-) (limited to 'src/cmd/go/internal/modload/modfile.go') diff --git a/src/cmd/go/internal/modload/modfile.go b/src/cmd/go/internal/modload/modfile.go index d280945ea6..6145e8b2f0 100644 --- a/src/cmd/go/internal/modload/modfile.go +++ b/src/cmd/go/internal/modload/modfile.go @@ -595,47 +595,14 @@ func rawGoModSummary(m module.Version) (*modFileSummary, error) { } c := rawGoModSummaryCache.Do(m, func() interface{} { summary := new(modFileSummary) - var f *modfile.File - if m.Version == "" { - // m is a replacement module with only a file path. - dir := m.Path - if !filepath.IsAbs(dir) { - dir = filepath.Join(ModRoot(), dir) - } - gomod := filepath.Join(dir, "go.mod") - var data []byte - var err error - if gomodActual, ok := fsys.OverlayPath(gomod); ok { - // Don't lock go.mod if it's part of the overlay. - // On Plan 9, locking requires chmod, and we don't want to modify any file - // in the overlay. See #44700. - data, err = os.ReadFile(gomodActual) - } else { - data, err = lockedfile.Read(gomodActual) - } - if err != nil { - return cached{nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(gomod), err))} - } - f, err = modfile.ParseLax(gomod, data, nil) - if err != nil { - return cached{nil, module.VersionError(m, fmt.Errorf("parsing %s: %v", base.ShortPath(gomod), err))} - } - } else { - if !semver.IsValid(m.Version) { - // Disallow the broader queries supported by fetch.Lookup. - base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", m.Path, m.Version) - } - - data, err := modfetch.GoMod(m.Path, m.Version) - if err != nil { - return cached{nil, err} - } - f, err = modfile.ParseLax("go.mod", data, nil) - if err != nil { - return cached{nil, module.VersionError(m, fmt.Errorf("parsing go.mod: %v", err))} - } + name, data, err := rawGoModData(m) + if err != nil { + return cached{nil, err} + } + f, err := modfile.ParseLax(name, data, nil) + if err != nil { + return cached{nil, module.VersionError(m, fmt.Errorf("parsing %s: %v", base.ShortPath(name), err))} } - if f.Module != nil { summary.module = f.Module.Mod summary.deprecated = f.Module.Deprecated @@ -671,6 +638,42 @@ func rawGoModSummary(m module.Version) (*modFileSummary, error) { var rawGoModSummaryCache par.Cache // module.Version → rawGoModSummary result +// rawGoModData returns the content of the go.mod file for module m, ignoring +// all replacements that may apply to m. +// +// rawGoModData cannot be used on the Target module. +// +// Unlike rawGoModSummary, rawGoModData does not cache its results in memory. +// Use rawGoModSummary instead unless you specifically need these bytes. +func rawGoModData(m module.Version) (name string, data []byte, err error) { + if m.Version == "" { + // m is a replacement module with only a file path. + dir := m.Path + if !filepath.IsAbs(dir) { + dir = filepath.Join(ModRoot(), dir) + } + gomod := filepath.Join(dir, "go.mod") + if gomodActual, ok := fsys.OverlayPath(gomod); ok { + // Don't lock go.mod if it's part of the overlay. + // On Plan 9, locking requires chmod, and we don't want to modify any file + // in the overlay. See #44700. + data, err = os.ReadFile(gomodActual) + } else { + data, err = lockedfile.Read(gomodActual) + } + if err != nil { + return gomod, nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(gomod), err)) + } + } else { + if !semver.IsValid(m.Version) { + // Disallow the broader queries supported by fetch.Lookup. + base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", m.Path, m.Version) + } + data, err = modfetch.GoMod(m.Path, m.Version) + } + return "go.mod", data, err +} + // queryLatestVersionIgnoringRetractions looks up the latest version of the // module with the given path without considering retracted or excluded // versions. -- cgit v1.2.3-54-g00ecf From 9eee0ed4391942c73157c868a9ddcfdef48982f9 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Wed, 28 Jul 2021 11:52:14 -0700 Subject: cmd/go: fix go.mod file name printed in error messages for replacements This fixes a logic error introduced in CL 337850. Fixes #47444 Change-Id: I6a49c8fc71fdde4ecb7f2e3329ad1f2cd286b7eb Reviewed-on: https://go-review.googlesource.com/c/go/+/338189 Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Michael Matloob Trust: Jay Conrod --- src/cmd/go/internal/modload/modfile.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/cmd/go/internal/modload/modfile.go') diff --git a/src/cmd/go/internal/modload/modfile.go b/src/cmd/go/internal/modload/modfile.go index 6145e8b2f0..03e02e73b6 100644 --- a/src/cmd/go/internal/modload/modfile.go +++ b/src/cmd/go/internal/modload/modfile.go @@ -652,8 +652,8 @@ func rawGoModData(m module.Version) (name string, data []byte, err error) { if !filepath.IsAbs(dir) { dir = filepath.Join(ModRoot(), dir) } - gomod := filepath.Join(dir, "go.mod") - if gomodActual, ok := fsys.OverlayPath(gomod); ok { + name = filepath.Join(dir, "go.mod") + if gomodActual, ok := fsys.OverlayPath(name); ok { // Don't lock go.mod if it's part of the overlay. // On Plan 9, locking requires chmod, and we don't want to modify any file // in the overlay. See #44700. @@ -662,16 +662,17 @@ func rawGoModData(m module.Version) (name string, data []byte, err error) { data, err = lockedfile.Read(gomodActual) } if err != nil { - return gomod, nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(gomod), err)) + return "", nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(name), err)) } } else { if !semver.IsValid(m.Version) { // Disallow the broader queries supported by fetch.Lookup. base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", m.Path, m.Version) } + name = "go.mod" data, err = modfetch.GoMod(m.Path, m.Version) } - return "go.mod", data, err + return name, data, err } // queryLatestVersionIgnoringRetractions looks up the latest version of the -- cgit v1.2.3-54-g00ecf