Skip to content

Commit

Permalink
modfile: be less strict about go version syntax in dependency go.mod …
Browse files Browse the repository at this point in the history
…files

It is unclear what the future holds for the go line in go.mod files.
Perhaps at some point we will switch to semver numbering.
Perhaps at some point we will allow specifying minor versions
or even betas and release candidates.
Those kinds of changes are difficult today because the go line
is parsed in dependency modules, meaning that older
versions of the Go toolchain need to understand newer go lines.

This CL makes that case - parsing a go line in a dependency's
go.mod file - a bit more lax about how to find the version.
It allows a leading v and any trailing non-digit-prefixed string
after the MAJOR.MINOR section.

There are no concrete plans to make use of any of these changes,
but if in the future we want to make them, having a few Go releases
under out belt that will accept the syntax in dependencies will
make any changes significantly easier.

See also CL 317690 in the main repo.

Change-Id: I7c7733c62259b3f25683ed618bc4918c98061396
Reviewed-on: https://go-review.googlesource.com/c/mod/+/317689
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
  • Loading branch information
rsc committed May 12, 2021
1 parent 67f1c1e commit 6088ed8
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 11 deletions.
42 changes: 33 additions & 9 deletions modfile/read_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -424,9 +424,10 @@ func TestModulePath(t *testing.T) {
}

func TestGoVersion(t *testing.T) {
for _, test := range []struct {
tests := []struct {
desc, input string
ok bool
laxOK bool // ok=true implies laxOK=true; only set if ok=false
}{
{desc: "empty", input: "module m\ngo \n", ok: false},
{desc: "one", input: "module m\ngo 1\n", ok: false},
Expand All @@ -435,15 +436,38 @@ func TestGoVersion(t *testing.T) {
{desc: "before", input: "module m\ngo v1.2\n", ok: false},
{desc: "after", input: "module m\ngo 1.2rc1\n", ok: false},
{desc: "space", input: "module m\ngo 1.2 3.4\n", ok: false},
} {
t.Run(test.desc, func(t *testing.T) {
if _, err := Parse("go.mod", []byte(test.input), nil); err == nil && !test.ok {
t.Error("unexpected success")
} else if err != nil && test.ok {
t.Errorf("unexpected error: %v", err)
}
})
{desc: "alt1", input: "module m\ngo 1.2.3\n", ok: false, laxOK: true},
{desc: "alt2", input: "module m\ngo 1.2rc1\n", ok: false, laxOK: true},
{desc: "alt3", input: "module m\ngo 1.2beta1\n", ok: false, laxOK: 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},
}
t.Run("Strict", 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 {
t.Error("unexpected success")
} else if err != nil && test.ok {
t.Errorf("unexpected error: %v", err)
}
})
}
})
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) {
t.Error("unexpected success")
} else if err != nil && test.ok {
t.Errorf("unexpected error: %v", err)
}
})
}
})
}

func TestComments(t *testing.T) {
Expand Down
14 changes: 12 additions & 2 deletions modfile/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (parse
}

var GoVersionRE = lazyregexp.New(`^([1-9][0-9]*)\.(0|[1-9][0-9]*)$`)
var laxGoVersionRE = lazyregexp.New(`^v?(([1-9][0-9]*)\.(0|[1-9][0-9]*))([^0-9].*)$`)

func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, args []string, fix VersionFixer, strict bool) {
// If strict is false, this module is a dependency.
Expand Down Expand Up @@ -267,8 +268,17 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a
errorf("go directive expects exactly one argument")
return
} else if !GoVersionRE.MatchString(args[0]) {
errorf("invalid go version '%s': must match format 1.23", args[0])
return
fixed := false
if !strict {
if m := laxGoVersionRE.FindStringSubmatch(args[0]); m != nil {
args[0] = m[1]
fixed = true
}
}
if !fixed {
errorf("invalid go version '%s': must match format 1.23", args[0])
return
}
}

f.Go = &Go{Syntax: line}
Expand Down

0 comments on commit 6088ed8

Please sign in to comment.