]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: make mod init disallow invalid major version suffixes
authorPaschalis Tsilias <paschalis.tsilias@gmail.com>
Tue, 2 Feb 2021 13:25:21 +0000 (15:25 +0200)
committerJay Conrod <jayconrod@google.com>
Tue, 17 Aug 2021 21:34:32 +0000 (21:34 +0000)
This CL reuses the SplitPathVersion function from the module package to
detect invalid major version suffixes and return a relevant error
message along with a suggested fix.

Fixes #44052
Fixes #46085

Change-Id: I6c06f31a134e864a1d9b6e00c048ca1c59b4365e
Reviewed-on: https://go-review.googlesource.com/c/go/+/288712
Reviewed-by: Jay Conrod <jayconrod@google.com>
Trust: Jay Conrod <jayconrod@google.com>
Trust: Bryan C. Mills <bcmills@google.com>
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>

src/cmd/go/internal/modload/init.go
src/cmd/go/testdata/script/mod_init_invalid_major.txt [new file with mode: 0644]

index d5f9d1042233816b3563978895cdf5b71fcdcaa3..862b00773995c4984c81c0935ecf488c9af2739e 100644 (file)
@@ -523,6 +523,13 @@ func CreateModFile(ctx context.Context, modPath string) {
                        }
                }
                base.Fatalf("go: %v", err)
+       } else if _, _, ok := module.SplitPathVersion(modPath); !ok {
+               if strings.HasPrefix(modPath, "gopkg.in/") {
+                       invalidMajorVersionMsg := fmt.Errorf("module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN:\n\tgo mod init %s", suggestGopkgIn(modPath))
+                       base.Fatalf(`go: invalid module path "%v": %v`, modPath, invalidMajorVersionMsg)
+               }
+               invalidMajorVersionMsg := fmt.Errorf("major version suffixes must be in the form of /vN and are only allowed for v2 or later:\n\tgo mod init %s", suggestModulePath(modPath))
+               base.Fatalf(`go: invalid module path "%v": %v`, modPath, invalidMajorVersionMsg)
        }
 
        fmt.Fprintf(os.Stderr, "go: creating new go.mod: module %s\n", modPath)
@@ -1197,3 +1204,56 @@ const (
 func modkey(m module.Version) module.Version {
        return module.Version{Path: m.Path, Version: m.Version + "/go.mod"}
 }
+
+func suggestModulePath(path string) string {
+       var m string
+
+       i := len(path)
+       for i > 0 && ('0' <= path[i-1] && path[i-1] <= '9' || path[i-1] == '.') {
+               i--
+       }
+       url := path[:i]
+       url = strings.TrimSuffix(url, "/v")
+       url = strings.TrimSuffix(url, "/")
+
+       f := func(c rune) bool {
+               return c > '9' || c < '0'
+       }
+       s := strings.FieldsFunc(path[i:], f)
+       if len(s) > 0 {
+               m = s[0]
+       }
+       m = strings.TrimLeft(m, "0")
+       if m == "" || m == "1" {
+               return url + "/v2"
+       }
+
+       return url + "/v" + m
+}
+
+func suggestGopkgIn(path string) string {
+       var m string
+       i := len(path)
+       for i > 0 && (('0' <= path[i-1] && path[i-1] <= '9') || (path[i-1] == '.')) {
+               i--
+       }
+       url := path[:i]
+       url = strings.TrimSuffix(url, ".v")
+       url = strings.TrimSuffix(url, "/v")
+       url = strings.TrimSuffix(url, "/")
+
+       f := func(c rune) bool {
+               return c > '9' || c < '0'
+       }
+       s := strings.FieldsFunc(path, f)
+       if len(s) > 0 {
+               m = s[0]
+       }
+
+       m = strings.TrimLeft(m, "0")
+
+       if m == "" {
+               return url + ".v1"
+       }
+       return url + ".v" + m
+}
diff --git a/src/cmd/go/testdata/script/mod_init_invalid_major.txt b/src/cmd/go/testdata/script/mod_init_invalid_major.txt
new file mode 100644 (file)
index 0000000..ae93e70
--- /dev/null
@@ -0,0 +1,82 @@
+env GO111MODULE=on
+env GOFLAGS=-mod=mod
+
+! go mod init example.com/user/repo/v0
+stderr '(?s)^go: invalid module path "example.com/user/repo/v0": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v2$'
+
+! go mod init example.com/user/repo/v02
+stderr '(?s)^go: invalid module path "example.com/user/repo/v02": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v2$'
+
+! go mod init example.com/user/repo/v023
+stderr '(?s)^go: invalid module path "example.com/user/repo/v023": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v23$'
+
+! go mod init example.com/user/repo/v1
+stderr '(?s)^go: invalid module path "example.com/user/repo/v1": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v2$'
+
+! go mod init example.com/user/repo/v2.0
+stderr '(?s)^go: invalid module path "example.com/user/repo/v2.0": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v2$'
+
+! go mod init example.com/user/repo/v2.1.4
+stderr '(?s)^go: invalid module path "example.com/user/repo/v2.1.4": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v2$'
+
+! go mod init example.com/user/repo/v3.5
+stderr '(?s)^go: invalid module path "example.com/user/repo/v3.5": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v3$'
+
+! go mod init example.com/user/repo/v4.1.4
+stderr '(?s)^go: invalid module path "example.com/user/repo/v4.1.4": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v4$'
+
+! go mod init example.com/user/repo/v.2.3
+stderr '(?s)^go: invalid module path "example.com/user/repo/v.2.3": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v2$'
+
+! go mod init example.com/user/repo/v.5.3
+stderr '(?s)^go: invalid module path "example.com/user/repo/v.5.3": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v5$'
+
+! go mod init gopkg.in/pkg
+stderr '(?s)^go: invalid module path "gopkg.in/pkg": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/pkg.v1$'
+
+! go mod init gopkg.in/user/pkg
+stderr '(?s)^go: invalid module path "gopkg.in/user/pkg": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$'
+
+! go mod init gopkg.in/user/pkg/v0
+stderr '(?s)^go: invalid module path "gopkg.in/user/pkg/v0": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$'
+
+! go mod init gopkg.in/user/pkg/v1
+stderr '(?s)^go: invalid module path "gopkg.in/user/pkg/v1": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$'
+
+! go mod init gopkg.in/user/pkg/v2
+stderr '(?s)^go: invalid module path "gopkg.in/user/pkg/v2": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v2$'
+
+! go mod init gopkg.in/user/pkg.v
+stderr '(?s)^go: invalid module path "gopkg.in/user/pkg.v": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$'
+
+! go mod init gopkg.in/user/pkg.v0.1
+stderr '(?s)^go: invalid module path "gopkg.in/user/pkg.v0.1": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$'
+
+! go mod init gopkg.in/user/pkg.v.1
+stderr '(?s)^go: invalid module path "gopkg.in/user/pkg.v.1": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$'
+
+! go mod init gopkg.in/user/pkg.v01
+stderr '(?s)^go: invalid module path "gopkg.in/user/pkg.v01": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$'
+
+! go mod init gopkg.in/user/pkg.v.2.3
+stderr '(?s)^go: invalid module path "gopkg.in/user/pkg.v.2.3": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v2$'
+
+# module paths with a trailing dot are rejected as invalid import paths
+! go mod init example.com/user/repo/v2.
+stderr '(?s)^go: malformed module path "example.com/user/repo/v2.": trailing dot in path element$'
+
+! go mod init example.com/user/repo/v2..
+stderr '(?s)^go: malformed module path "example.com/user/repo/v2..": trailing dot in path element$'
+
+! go mod init gopkg.in/user/pkg.v.2.
+stderr '(?s)^go: malformed module path "gopkg.in/user/pkg.v.2.": trailing dot in path element$'
+
+! go mod init gopkg.in/user/pkg.v.2..
+stderr '(?s)^go: malformed module path "gopkg.in/user/pkg.v.2..": trailing dot in path element$'
+
+# module paths with spaces are also rejected
+! go mod init 'foo bar'
+stderr '(?s)^go: malformed module path "foo bar": invalid char '' ''$'
+
+! go mod init 'foo  bar baz'
+stderr '(?s)^go: malformed module path "foo  bar baz": invalid char '' ''$'