Skip to content

Commit 4c3cb1e

Browse files
committed
internal/gocommand: add GoVersionString
Unlike the existing GoVersion that returns the minor version number of the go command, GoVersionString returns the part that indicates the major/minor/patch version from `go version` output. The full go version info is necessary when analyzing vulnerabilities. Change-Id: I5ea624e877e02009148ad906e6475cb1aba40b3a Reviewed-on: https://go-review.googlesource.com/c/tools/+/453595 Run-TryBot: Hyang-Ah Hana Kim <[email protected]> TryBot-Result: Gopher Robot <[email protected]> gopls-CI: kokoro <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent e29d1ed commit 4c3cb1e

File tree

4 files changed

+68
-0
lines changed

4 files changed

+68
-0
lines changed

gopls/internal/lsp/cache/view.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ type workspaceInformation struct {
119119
// The Go version in use: X in Go 1.X.
120120
goversion int
121121

122+
// The Go version reported by go version command. (e.g. go1.19.1, go1.20-rc.1, go1.21-abcdef01)
123+
goversionString string
124+
122125
// hasGopackagesDriver is true if the user has a value set for the
123126
// GOPACKAGESDRIVER environment variable or a gopackagesdriver binary on
124127
// their machine.
@@ -836,6 +839,10 @@ func (s *Session) getWorkspaceInformation(ctx context.Context, folder span.URI,
836839
if err != nil {
837840
return nil, err
838841
}
842+
goversionString, err := gocommand.GoVersionString(ctx, inv, s.gocmdRunner)
843+
if err != nil {
844+
return nil, err
845+
}
839846

840847
// Make sure to get the `go env` before continuing with initialization.
841848
envVars, env, err := s.getGoEnv(ctx, folder.Filename(), goversion, options.EnvSlice())
@@ -863,6 +870,7 @@ func (s *Session) getWorkspaceInformation(ctx context.Context, folder span.URI,
863870
return &workspaceInformation{
864871
hasGopackagesDriver: hasGopackagesDriver,
865872
goversion: goversion,
873+
goversionString: goversionString,
866874
environmentVariables: envVars,
867875
goEnv: env,
868876
}, nil
@@ -1072,6 +1080,10 @@ func (v *View) GoVersion() int {
10721080
return v.workspaceInformation.goversion
10731081
}
10741082

1083+
func (v *View) GoVersionString() string {
1084+
return v.workspaceInformation.goversionString
1085+
}
1086+
10751087
// Copied from
10761088
// https://cs.opensource.google/go/go/+/master:src/cmd/go/internal/str/path.go;l=58;drc=2910c5b4a01a573ebc97744890a07c1a3122c67a
10771089
func globsMatchPath(globs, target string) bool {

gopls/internal/lsp/source/view.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,10 @@ type View interface {
329329

330330
// GoVersion returns the configured Go version for this view.
331331
GoVersion() int
332+
333+
// GoVersionString returns the go version string configured for this view.
334+
// Unlike [GoVersion], this encodes the minor version and commit hash information.
335+
GoVersionString() string
332336
}
333337

334338
// A FileSource maps uris to FileHandles. This abstraction exists both for

internal/gocommand/version.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package gocommand
77
import (
88
"context"
99
"fmt"
10+
"regexp"
1011
"strings"
1112
)
1213

@@ -56,3 +57,23 @@ func GoVersion(ctx context.Context, inv Invocation, r *Runner) (int, error) {
5657
}
5758
return 0, fmt.Errorf("no parseable ReleaseTags in %v", tags)
5859
}
60+
61+
// GoVersionString reports the go version string as shown in `go version` command output.
62+
// When `go version` outputs in non-standard form, this returns an empty string.
63+
func GoVersionString(ctx context.Context, inv Invocation, r *Runner) (string, error) {
64+
inv.Verb = "version"
65+
goVersion, err := r.Run(ctx, inv)
66+
if err != nil {
67+
return "", err
68+
}
69+
return parseGoVersionOutput(goVersion.Bytes()), nil
70+
}
71+
72+
func parseGoVersionOutput(data []byte) string {
73+
re := regexp.MustCompile(`^go version (go\S+|devel \S+)`)
74+
m := re.FindSubmatch(data)
75+
if len(m) != 2 {
76+
return "" // unrecognized version
77+
}
78+
return string(m[1])
79+
}

internal/gocommand/version_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2022 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package gocommand
6+
7+
import (
8+
"strconv"
9+
"testing"
10+
)
11+
12+
func TestParseGoVersionOutput(t *testing.T) {
13+
tests := []struct {
14+
args string
15+
want string
16+
}{
17+
{"go version go1.12 linux/amd64", "go1.12"},
18+
{"go version go1.18.1 darwin/amd64", "go1.18.1"},
19+
{"go version go1.19.rc1 windows/arm64", "go1.19.rc1"},
20+
{"go version devel d5de62df152baf4de6e9fe81933319b86fd95ae4 linux/386", "devel d5de62df152baf4de6e9fe81933319b86fd95ae4"},
21+
{"go version devel go1.20-1f068f0dc7 Tue Oct 18 20:58:37 2022 +0000 darwin/amd64", "devel go1.20-1f068f0dc7"},
22+
{"v1.19.1 foo/bar", ""},
23+
}
24+
for i, tt := range tests {
25+
t.Run(strconv.Itoa(i), func(t *testing.T) {
26+
if got := parseGoVersionOutput([]byte(tt.args)); got != tt.want {
27+
t.Errorf("parseGoVersionOutput() = %v, want %v", got, tt.want)
28+
}
29+
})
30+
}
31+
}

0 commit comments

Comments
 (0)