From: Jay Conrod Date: Mon, 17 Jun 2019 21:03:55 +0000 (-0400) Subject: cmd/go/internal/modload: query correct "latest" version through proxy X-Git-Tag: go1.13beta1~62 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=53f628e56029573729ce6ac8844f87cc08f62a7a;p=gostls13.git cmd/go/internal/modload: query correct "latest" version through proxy This fixes a regression introduced in CL 180337. When we query a module at "latest" that has no tagged versions, we tried to use "" as the version because we used info.Name instead of info.Version. This only happened when using a proxy: in direct mode, info.Name is set to the underlying VCS revision, which is fine. Also: serve "/mod/path/@latest" through our test proxy. Previously, we served a 404, which made this bug hard to detect. Fixes #32636 Change-Id: I5c60975656297f862cad66675170e819685ebd39 Reviewed-on: https://go-review.googlesource.com/c/go/+/182697 Run-TryBot: Jay Conrod TryBot-Result: Gobot Gobot Reviewed-by: Bryan C. Mills --- diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go index 9cd7881696..614592806d 100644 --- a/src/cmd/go/internal/modload/query.go +++ b/src/cmd/go/internal/modload/query.go @@ -241,7 +241,7 @@ func queryProxy(proxy, path, query, current string, allowed func(module.Version) // Special case for "latest": if no tags match, use latest commit in repo, // provided it is not excluded. if latest, err := repo.Latest(); err == nil && allowed(module.Version{Path: path, Version: latest.Version}) { - return lookup(latest.Name) + return lookup(latest.Version) } } diff --git a/src/cmd/go/proxy_test.go b/src/cmd/go/proxy_test.go index 5718ca325f..6919d32184 100644 --- a/src/cmd/go/proxy_test.go +++ b/src/cmd/go/proxy_test.go @@ -182,6 +182,57 @@ func proxyHandler(w http.ResponseWriter, r *http.Request) { return } + // Module proxy request: /mod/path/@latest + // Rewrite to /mod/path/@v/.info where is the semantically + // latest version, including pseudo-versions. + if i := strings.LastIndex(path, "/@latest"); i >= 0 { + enc := path[:i] + modPath, err := module.DecodePath(enc) + if err != nil { + if !quiet { + fmt.Fprintf(os.Stderr, "go proxy_test: %v\n", err) + } + http.NotFound(w, r) + return + } + + // Imitate what "latest" does in direct mode and what proxy.golang.org does. + // Use the latest released version. + // If there is no released version, use the latest prereleased version. + // Otherwise, use the latest pseudoversion. + var latestRelease, latestPrerelease, latestPseudo string + for _, m := range modList { + if m.Path != modPath { + continue + } + if modfetch.IsPseudoVersion(m.Version) && (latestPseudo == "" || semver.Compare(latestPseudo, m.Version) > 0) { + latestPseudo = m.Version + } else if semver.Prerelease(m.Version) != "" && (latestPrerelease == "" || semver.Compare(latestPrerelease, m.Version) > 0) { + latestPrerelease = m.Version + } else if latestRelease == "" || semver.Compare(latestRelease, m.Version) > 0 { + latestRelease = m.Version + } + } + var latest string + if latestRelease != "" { + latest = latestRelease + } else if latestPrerelease != "" { + latest = latestPrerelease + } else if latestPseudo != "" { + latest = latestPseudo + } else { + http.NotFound(w, r) + return + } + + encVers, err := module.EncodeVersion(latest) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + path = fmt.Sprintf("%s/@v/%s.info", enc, encVers) + } + // Module proxy request: /mod/path/@v/version[.suffix] i := strings.Index(path, "/@v/") if i < 0 { @@ -198,16 +249,22 @@ func proxyHandler(w http.ResponseWriter, r *http.Request) { return } if file == "list" { - n := 0 + // list returns a list of versions, not including pseudo-versions. + // If the module has no tagged versions, we should serve an empty 200. + // If the module doesn't exist, we should serve 404 or 410. + found := false for _, m := range modList { - if m.Path == path && !modfetch.IsPseudoVersion(m.Version) { + if m.Path != path { + continue + } + found = true + if !modfetch.IsPseudoVersion(m.Version) { if err := module.Check(m.Path, m.Version); err == nil { fmt.Fprintf(w, "%s\n", m.Version) - n++ } } } - if n == 0 { + if !found { http.NotFound(w, r) } return diff --git a/src/cmd/go/testdata/mod/example.com_notags_v0.0.0-20190507143103-cc8cbe209b64.txt b/src/cmd/go/testdata/mod/example.com_notags_v0.0.0-20190507143103-cc8cbe209b64.txt new file mode 100644 index 0000000000..259774d542 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_notags_v0.0.0-20190507143103-cc8cbe209b64.txt @@ -0,0 +1,9 @@ +Written by hand. +The "latest" version of a module without any tags. + +-- .mod -- +module example.com/notags +-- .info -- +{"Version":"v0.0.0-20190507143103-cc8cbe209b64","Time":"2019-05-07T07:31:03-07:00"} +-- notags.go -- +package notags diff --git a/src/cmd/go/testdata/script/mod_get_latest_pseudo.txt b/src/cmd/go/testdata/script/mod_get_latest_pseudo.txt new file mode 100644 index 0000000000..825ee8cf89 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_latest_pseudo.txt @@ -0,0 +1,10 @@ +# Check that we can build a module with no tagged versions by querying +# "@latest" through a proxy. +# Verifies golang.org/issue/32636 + +env GO111MODULE=on + +go mod init m +go list example.com/notags +go list -m all +stdout '^example.com/notags v0.0.0-20190507143103-cc8cbe209b64$'