modfile: add parsing support for toolchain
Add new toolchain directive to go.mod and go.work parser.
Also fix error checking in parsing tests.
For golang/go#57001.
Change-Id: Ib7603f82cbd667f2152ed6b0c5989f08c28ceb1c
Reviewed-on: https://go-review.googlesource.com/c/mod/+/497399
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
diff --git a/modfile/read_test.go b/modfile/read_test.go
index df4f117..7017ee1 100644
--- a/modfile/read_test.go
+++ b/modfile/read_test.go
@@ -181,7 +181,13 @@
pf1, err := Parse(base, data, nil)
if err != nil {
switch base {
- case "testdata/replace2.in", "testdata/gopkg.in.golden":
+ case "testdata/block.golden",
+ "testdata/block.in",
+ "testdata/comment.golden",
+ "testdata/comment.in",
+ "testdata/rule1.golden":
+ // ignore
+ default:
t.Errorf("should parse %v: %v", base, err)
}
}
@@ -425,12 +431,13 @@
}
}
-func TestGoVersion(t *testing.T) {
+func TestParseVersions(t *testing.T) {
tests := []struct {
desc, input string
ok bool
laxOK bool // ok=true implies laxOK=true; only set if ok=false
}{
+ // go lines
{desc: "empty", input: "module m\ngo \n", ok: false},
{desc: "one", input: "module m\ngo 1\n", ok: false},
{desc: "two", input: "module m\ngo 1.22\n", ok: true},
@@ -438,15 +445,23 @@
{desc: "before", input: "module m\ngo v1.2\n", ok: false},
{desc: "after", input: "module m\ngo 1.2rc1\n", ok: true},
{desc: "space", input: "module m\ngo 1.2 3.4\n", ok: false},
- {desc: "alt1", input: "module m\ngo 1.2.3\n", ok: true, laxOK: true},
- {desc: "alt2", input: "module m\ngo 1.2rc1\n", ok: true, laxOK: true},
- {desc: "alt3", input: "module m\ngo 1.2beta1\n", ok: true, laxOK: true},
+ {desc: "alt1", input: "module m\ngo 1.2.3\n", ok: true},
+ {desc: "alt2", input: "module m\ngo 1.2rc1\n", ok: true},
+ {desc: "alt3", input: "module m\ngo 1.2beta1\n", ok: true},
{desc: "alt4", input: "module m\ngo 1.2.beta1\n", ok: false, laxOK: true},
{desc: "alt1", input: "module m\ngo v1.2.3\n", ok: false, laxOK: true},
{desc: "alt2", input: "module m\ngo v1.2rc1\n", ok: false, laxOK: true},
{desc: "alt3", input: "module m\ngo v1.2beta1\n", ok: false, laxOK: true},
{desc: "alt4", input: "module m\ngo v1.2.beta1\n", ok: false, laxOK: true},
{desc: "alt1", input: "module m\ngo v1.2\n", ok: false, laxOK: true},
+
+ // toolchain lines
+ {desc: "tool", input: "module m\ntoolchain go1.2\n", ok: true},
+ {desc: "tool1", input: "module m\ntoolchain go1.2.3\n", ok: true},
+ {desc: "tool2", input: "module m\ntoolchain go1.2rc1\n", ok: true},
+ {desc: "tool3", input: "module m\ntoolchain gccgo-go1.2rc1\n", ok: true},
+ {desc: "tool4", input: "module m\ntoolchain local\n", ok: true},
+ {desc: "tool5", input: "module m\ntoolchain inconceivable!\n", ok: false, laxOK: true},
}
t.Run("Strict", func(t *testing.T) {
for _, test := range tests {
@@ -462,7 +477,7 @@
t.Run("Lax", func(t *testing.T) {
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
- if _, err := Parse("go.mod", []byte(test.input), nil); err == nil && !(test.ok || test.laxOK) {
+ if _, err := ParseLax("go.mod", []byte(test.input), nil); err == nil && !(test.ok || test.laxOK) {
t.Error("unexpected success")
} else if err != nil && test.ok {
t.Errorf("unexpected error: %v", err)
diff --git a/modfile/rule.go b/modfile/rule.go
index 3306f6f..45e7b6a 100644
--- a/modfile/rule.go
+++ b/modfile/rule.go
@@ -375,6 +375,21 @@
f.Go = &Go{Syntax: line}
f.Go.Version = args[0]
+ case "toolchain":
+ if f.Toolchain != nil {
+ errorf("repeated toolchain statement")
+ return
+ }
+ if len(args) != 1 {
+ errorf("toolchain directive expects exactly one argument")
+ return
+ } else if strict && !ToolchainRE.MatchString(args[0]) {
+ errorf("invalid toolchain version '%s': must match format go1.23 or local", args[0])
+ return
+ }
+ f.Toolchain = &Toolchain{Syntax: line}
+ f.Toolchain.Name = args[0]
+
case "module":
if f.Module != nil {
errorf("repeated module statement")
@@ -623,6 +638,22 @@
f.Go = &Go{Syntax: line}
f.Go.Version = args[0]
+ case "toolchain":
+ if f.Toolchain != nil {
+ errorf("repeated toolchain statement")
+ return
+ }
+ if len(args) != 1 {
+ errorf("toolchain directive expects exactly one argument")
+ return
+ } else if !ToolchainRE.MatchString(args[0]) {
+ errorf("invalid toolchain version '%s': must match format go1.23 or local", args[0])
+ return
+ }
+
+ f.Toolchain = &Toolchain{Syntax: line}
+ f.Toolchain.Name = args[0]
+
case "use":
if len(args) != 1 {
errorf("usage: %s local/dir", verb)
diff --git a/modfile/testdata/goline.golden b/modfile/testdata/goline.golden
new file mode 100644
index 0000000..1f07989
--- /dev/null
+++ b/modfile/testdata/goline.golden
@@ -0,0 +1,3 @@
+go 1.2.3
+
+toolchain local
diff --git a/modfile/testdata/goline.in b/modfile/testdata/goline.in
new file mode 100644
index 0000000..498c1b8
--- /dev/null
+++ b/modfile/testdata/goline.in
@@ -0,0 +1,2 @@
+go 1.2.3
+toolchain local
diff --git a/modfile/testdata/work/goline.golden b/modfile/testdata/work/goline.golden
new file mode 100644
index 0000000..1f07989
--- /dev/null
+++ b/modfile/testdata/work/goline.golden
@@ -0,0 +1,3 @@
+go 1.2.3
+
+toolchain local
diff --git a/modfile/testdata/work/goline.in b/modfile/testdata/work/goline.in
new file mode 100644
index 0000000..498c1b8
--- /dev/null
+++ b/modfile/testdata/work/goline.in
@@ -0,0 +1,2 @@
+go 1.2.3
+toolchain local
diff --git a/modfile/work_test.go b/modfile/work_test.go
index 46115a5..096ed5c 100644
--- a/modfile/work_test.go
+++ b/modfile/work_test.go
@@ -332,10 +332,7 @@
pf1, err := ParseWork(base, data, nil)
if err != nil {
- switch base {
- case "testdata/replace2.in", "testdata/gopkg.in.golden":
- t.Errorf("should parse %v: %v", base, err)
- }
+ t.Errorf("should parse %v: %v", base, err)
}
if err == nil {
pf2, err := ParseWork(base, ndata, nil)