Commit e161b1e8 authored by Russ Cox's avatar Russ Cox

cmd/go/internal/module: allow v0.0.0 pseudoversion for gopkg.in/check.v1

It worked once. It needs to keep working.

Change-Id: Iaa43726e1c78f0c4a20b5805c7c2bfa76fab2489
Reviewed-on: https://go-review.googlesource.com/124383
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBryan C. Mills <bcmills@google.com>
parent 56deebb3
...@@ -12,6 +12,9 @@ package module ...@@ -12,6 +12,9 @@ package module
// There are many subtle considerations, including Unicode ambiguity, // There are many subtle considerations, including Unicode ambiguity,
// security, network, and file system representations. // security, network, and file system representations.
// //
// This file also defines the set of valid module path and version combinations,
// another topic with many subtle considerations.
//
// Changes to the semantics in this file require approval from rsc. // Changes to the semantics in this file require approval from rsc.
import ( import (
...@@ -50,31 +53,17 @@ func Check(path, version string) error { ...@@ -50,31 +53,17 @@ func Check(path, version string) error {
if !semver.IsValid(version) { if !semver.IsValid(version) {
return fmt.Errorf("malformed semantic version %v", version) return fmt.Errorf("malformed semantic version %v", version)
} }
vm := semver.Major(version) _, pathMajor, _ := SplitPathVersion(path)
_, pathVersion, _ := SplitPathVersion(path) if !MatchPathMajor(version, pathMajor) {
if pathMajor == "" {
if strings.HasPrefix(pathVersion, ".") { pathMajor = "v0 or v1"
// Special-case gopkg.in path requirements.
pathVersion = pathVersion[1:] // cut .
if vm == pathVersion {
return nil
}
} else {
// Standard path requirements.
if pathVersion != "" {
pathVersion = pathVersion[1:] // cut /
}
if vm == "v0" || vm == "v1" {
vm = ""
} }
if vm == pathVersion { if pathMajor[0] == '.' { // .v1
return nil pathMajor = pathMajor[1:]
}
if pathVersion == "" {
pathVersion = "v0 or v1"
} }
return fmt.Errorf("mismatched module path %v and version %v (want %v)", path, version, pathMajor)
} }
return fmt.Errorf("mismatched module path %v and version %v (want %v)", path, version, pathVersion) return nil
} }
// firstPathOK reports whether r can appear in the first element of a module path. // firstPathOK reports whether r can appear in the first element of a module path.
...@@ -328,6 +317,11 @@ func splitGopkgIn(path string) (prefix, pathMajor string, ok bool) { ...@@ -328,6 +317,11 @@ func splitGopkgIn(path string) (prefix, pathMajor string, ok bool) {
// MatchPathMajor reports whether the semantic version v // MatchPathMajor reports whether the semantic version v
// matches the path major version pathMajor. // matches the path major version pathMajor.
func MatchPathMajor(v, pathMajor string) bool { func MatchPathMajor(v, pathMajor string) bool {
if strings.HasPrefix(v, "v0.0.0-") && pathMajor == ".v1" {
// Allow old bug in pseudo-versions that generated v0.0.0- pseudoversion for gopkg .v1.
// For example, gopkg.in/yaml.v2@v2.2.1's go.mod requires gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405.
return true
}
m := semver.Major(v) m := semver.Major(v)
if pathMajor == "" { if pathMajor == "" {
return m == "v0" || m == "v1" return m == "v0" || m == "v1"
......
...@@ -37,6 +37,14 @@ var checkTests = []struct { ...@@ -37,6 +37,14 @@ var checkTests = []struct {
{"gopkg.in/yaml.v1", "v2.1.5", false}, {"gopkg.in/yaml.v1", "v2.1.5", false},
{"gopkg.in/yaml.v1", "v3.0.0", false}, {"gopkg.in/yaml.v1", "v3.0.0", false},
// For gopkg.in, .v1 means v1 only (not v0).
// But early versions of vgo still generated v0 pseudo-versions for it.
// Even though now we'd generate those as v1 pseudo-versions,
// we accept the old pseudo-versions to avoid breaking existing go.mod files.
// For example gopkg.in/yaml.v2@v2.2.1's go.mod requires check.v1 at a v0 pseudo-version.
{"gopkg.in/check.v1", "v0.0.0", false},
{"gopkg.in/check.v1", "v0.0.0-20160102150405-abcdef123456", true},
{"gopkg.in/yaml.v2", "v1.0.0", false}, {"gopkg.in/yaml.v2", "v1.0.0", false},
{"gopkg.in/yaml.v2", "v2.0.0", true}, {"gopkg.in/yaml.v2", "v2.0.0", true},
{"gopkg.in/yaml.v2", "v2.1.5", true}, {"gopkg.in/yaml.v2", "v2.1.5", true},
......
...@@ -834,14 +834,12 @@ func TestModFileNames(t *testing.T) { ...@@ -834,14 +834,12 @@ func TestModFileNames(t *testing.T) {
"rsc.io/badfile3", "rsc.io/badfile3",
"rsc.io/badfile4", "rsc.io/badfile4",
"rsc.io/badfile5", "rsc.io/badfile5",
"rsc.io/badfile6",
) )
tg.grepStderrNot(`unzip .*badfile1.*:`, "badfile1 should be OK") tg.grepStderrNot(`unzip .*badfile1.*:`, "badfile1 should be OK")
tg.grepStderr(`rsc.io/badfile2.*malformed file path "☺.go": invalid char '☺'`, "want diagnosed invalid character") tg.grepStderr(`rsc.io/badfile2.*malformed file path "☺.go": invalid char '☺'`, "want diagnosed invalid character")
tg.grepStderr(`rsc.io/badfile3.*malformed file path "x@y.go": invalid char '@'`, "want diagnosed invalid character") tg.grepStderr(`rsc.io/badfile3.*malformed file path "x\?y.go": invalid char '\?'`, "want diagnosed invalid character")
tg.grepStderr(`rsc.io/badfile4.*case-insensitive file name collision: "x/Y.go" and "x/y.go"`, "want case collision") tg.grepStderr(`rsc.io/badfile4.*case-insensitive file name collision: "x/Y.go" and "x/y.go"`, "want case collision")
tg.grepStderr(`rsc.io/badfile5.*case-insensitive file name collision: "x/y" and "x/Y"`, "want case collision") tg.grepStderr(`rsc.io/badfile5.*case-insensitive file name collision: "x/y" and "x/Y"`, "want case collision")
tg.grepStderr(`rsc.io/badfile6.*malformed file path "x/.gitignore/y": leading dot in path element`, "want leading dot in path element")
} }
func TestModBadDomain(t *testing.T) { func TestModBadDomain(t *testing.T) {
......
...@@ -7,6 +7,6 @@ module rsc.io/badfile3 ...@@ -7,6 +7,6 @@ module rsc.io/badfile3
{"Version":"v1.0.0"} {"Version":"v1.0.0"}
-- go.mod -- -- go.mod --
module rsc.io/badfile3 module rsc.io/badfile3
-- x@y.go -- -- x?y.go --
package x package x
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment