mirror of https://github.com/golang/go.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 <jayconrod@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Bryan C. Mills <bcmills@google.com>
This commit is contained in:
parent
263db9b680
commit
53f628e560
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
9
src/cmd/go/testdata/mod/example.com_notags_v0.0.0-20190507143103-cc8cbe209b64.txt
vendored
Normal file
9
src/cmd/go/testdata/mod/example.com_notags_v0.0.0-20190507143103-cc8cbe209b64.txt
vendored
Normal file
|
|
@ -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
|
||||
|
|
@ -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$'
|
||||
Loading…
Reference in New Issue