]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go/internal/modload: query correct "latest" version through proxy
authorJay Conrod <jayconrod@google.com>
Mon, 17 Jun 2019 21:03:55 +0000 (17:03 -0400)
committerJay Conrod <jayconrod@google.com>
Tue, 18 Jun 2019 00:18:19 +0000 (00:18 +0000)
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 <jayconrod@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
src/cmd/go/internal/modload/query.go
src/cmd/go/proxy_test.go
src/cmd/go/testdata/mod/example.com_notags_v0.0.0-20190507143103-cc8cbe209b64.txt [new file with mode: 0644]
src/cmd/go/testdata/script/mod_get_latest_pseudo.txt [new file with mode: 0644]

index 9cd7881696e76747ffdbd0ab812043debd13f2f7..614592806d9ceb629de7b5a1b663973b2417cd6f 100644 (file)
@@ -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)
                }
        }
 
index 5718ca325ff87c70577d8526c3440c2e2c224cb6..6919d32184720df84b9b2c1ea97e43976aae2c14 100644 (file)
@@ -182,6 +182,57 @@ func proxyHandler(w http.ResponseWriter, r *http.Request) {
                return
        }
 
+       // Module proxy request: /mod/path/@latest
+       // Rewrite to /mod/path/@v/<latest>.info where <latest> 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 (file)
index 0000000..259774d
--- /dev/null
@@ -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 (file)
index 0000000..825ee8c
--- /dev/null
@@ -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$'