return p.path
}
+// versionError returns err wrapped in a ModuleError for p.path.
+func (p *proxyRepo) versionError(version string, err error) error {
+ if version != "" && version != module.CanonicalVersion(version) {
+ return &module.ModuleError{
+ Path: p.path,
+ Err: &module.InvalidVersionError{
+ Version: version,
+ Pseudo: IsPseudoVersion(version),
+ Err: err,
+ },
+ }
+ }
+
+ return &module.ModuleError{
+ Path: p.path,
+ Version: version,
+ Err: err,
+ }
+}
+
func (p *proxyRepo) getBytes(path string) ([]byte, error) {
body, err := p.getBody(path)
if err != nil {
func (p *proxyRepo) Versions(prefix string) ([]string, error) {
data, err := p.getBytes("@v/list")
if err != nil {
- return nil, err
+ return nil, p.versionError("", err)
}
var list []string
for _, line := range strings.Split(string(data), "\n") {
func (p *proxyRepo) latest() (*RevInfo, error) {
data, err := p.getBytes("@v/list")
if err != nil {
- return nil, err
+ return nil, p.versionError("", err)
}
var best time.Time
var bestVersion string
}
}
if bestVersion == "" {
- return nil, fmt.Errorf("no commits")
+ return nil, p.versionError("", codehost.ErrNoCommits)
}
info := &RevInfo{
Version: bestVersion,
func (p *proxyRepo) Stat(rev string) (*RevInfo, error) {
encRev, err := module.EncodeVersion(rev)
if err != nil {
- return nil, err
+ return nil, p.versionError(rev, err)
}
data, err := p.getBytes("@v/" + encRev + ".info")
if err != nil {
- return nil, err
+ return nil, p.versionError(rev, err)
}
info := new(RevInfo)
if err := json.Unmarshal(data, info); err != nil {
- return nil, err
+ return nil, p.versionError(rev, err)
}
if info.Version != rev && rev == module.CanonicalVersion(rev) && module.Check(p.path, rev) == nil {
// If we request a correct, appropriate version for the module path, the
// proxy must return either exactly that version or an error — not some
// arbitrary other version.
- return nil, fmt.Errorf("requested canonical version %s, but proxy returned info for version %s", rev, info.Version)
+ return nil, p.versionError(rev, fmt.Errorf("proxy returned info for version %s instead of requested version", info.Version))
}
return info, nil
}
}
info := new(RevInfo)
if err := json.Unmarshal(data, info); err != nil {
- return nil, err
+ return nil, p.versionError("", err)
}
return info, nil
}
func (p *proxyRepo) GoMod(version string) ([]byte, error) {
if version != module.CanonicalVersion(version) {
- return nil, fmt.Errorf("version %s is not canonical", version)
+ return nil, p.versionError(version, fmt.Errorf("internal error: version passed to GoMod is not canonical"))
}
encVer, err := module.EncodeVersion(version)
if err != nil {
- return nil, err
+ return nil, p.versionError(version, err)
}
data, err := p.getBytes("@v/" + encVer + ".mod")
if err != nil {
- return nil, err
+ return nil, p.versionError(version, err)
}
return data, nil
}
func (p *proxyRepo) Zip(dst io.Writer, version string) error {
if version != module.CanonicalVersion(version) {
- return fmt.Errorf("version %s is not canonical", version)
+ return p.versionError(version, fmt.Errorf("internal error: version passed to Zip is not canonical"))
}
encVer, err := module.EncodeVersion(version)
if err != nil {
- return err
+ return p.versionError(version, err)
}
body, err := p.getBody("@v/" + encVer + ".zip")
if err != nil {
- return err
+ return p.versionError(version, err)
}
defer body.Close()
lr := &io.LimitedReader{R: body, N: codehost.MaxZipFile + 1}
if _, err := io.Copy(dst, lr); err != nil {
- return err
+ return p.versionError(version, err)
}
if lr.N <= 0 {
- return fmt.Errorf("downloaded zip file too large")
+ return p.versionError(version, fmt.Errorf("downloaded zip file too large"))
}
return nil
}
--- /dev/null
+env GO111MODULE=on
+env GOSUMDB=off
+
+go mod download example.com/join@v1.1.0
+
+# If the proxy serves a bogus result for the @latest version,
+# reading that version should cause 'go get' to fail.
+env GOPROXY=file:///$WORK/badproxy
+cp go.mod.orig go.mod
+! go get -d example.com/join/subpkg
+stderr 'go get example.com/join/subpkg: example.com/join/subpkg@v0.0.0-20190624000000-123456abcdef: .*'
+
+# If @v/list is empty, the 'go' command should still try to resolve
+# other module paths.
+env GOPROXY=file:///$WORK/emptysub
+cp go.mod.orig go.mod
+go get -d example.com/join/subpkg
+go list -m example.com/join/...
+! stdout 'example.com/join/subpkg'
+stdout 'example.com/join v1.1.0'
+
+# If @v/list includes a version that the proxy does not actually serve,
+# that version is treated as nonexistent.
+env GOPROXY=file:///$WORK/notfound
+cp go.mod.orig go.mod
+go get -d example.com/join/subpkg
+go list -m example.com/join/...
+! stdout 'example.com/join/subpkg'
+stdout 'example.com/join v1.1.0'
+
+-- go.mod.orig --
+module example.com/othermodule
+go 1.13
+-- $WORK/badproxy/example.com/join/subpkg/@v/list --
+v0.0.0-20190624000000-123456abcdef
+-- $WORK/badproxy/example.com/join/subpkg/@v/v0.0.0-20190624000000-123456abcdef.info --
+This file is not valid JSON.
+-- $WORK/badproxy/example.com/join/@v/list --
+v1.1.0
+-- $WORK/badproxy/example.com/join/@v/v1.1.0.info --
+{"Version": "v1.1.0"}
+-- $WORK/emptysub/example.com/join/subpkg/@v/list --
+-- $WORK/emptysub/example.com/join/@v/list --
+v1.1.0
+-- $WORK/emptysub/example.com/join/@v/v1.1.0.info --
+{"Version": "v1.1.0"}
+-- $WORK/notfound/example.com/join/subpkg/@v/list --
+v1.0.0-does-not-exist
+-- $WORK/notfound/example.com/join/@v/list --
+v1.1.0
+-- $WORK/notfound/example.com/join/@v/v1.1.0.info --
+{"Version": "v1.1.0"}