Skip to content

Commit aec2053

Browse files
committed
consider GOROOT/api as fallback to determine Go version
1 parent 571a412 commit aec2053

File tree

1 file changed

+68
-14
lines changed

1 file changed

+68
-14
lines changed

builder/env.go

Lines changed: 68 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,34 +13,88 @@ import (
1313
"strings"
1414
)
1515

16+
// parseGorootVersion returns the major and minor version for a given Go version
17+
// string of the form `goX.Y.Z`.
18+
// Returns (0, 0) if the version cannot be determined.
19+
func parseGorootVersion(version string) (int, int, error) {
20+
var (
21+
maj, min int
22+
pch string
23+
)
24+
n, err := fmt.Sscanf(version, "go%d.%d%s", &maj, &min, &pch)
25+
if n == 2 && io.EOF == err {
26+
// Means there were no trailing characters (i.e., not an alpha/beta)
27+
err = nil
28+
}
29+
if nil != err {
30+
return 0, 0, fmt.Errorf("failed to parse version: %s", err)
31+
}
32+
return maj, min, nil
33+
}
34+
1635
// getGorootVersion returns the major and minor version for a given GOROOT path.
17-
// If the goroot cannot be determined, (0, 0) is returned.
18-
func getGorootVersion(goroot string) (major, minor int, err error) {
36+
// If the version cannot be determined, (0, 0) is returned.
37+
func getGorootVersion(goroot string) (int, int, error) {
38+
const errPrefix = "could not parse Go version"
1939
s, err := GorootVersionString(goroot)
2040
if err != nil {
2141
return 0, 0, err
2242
}
2343

24-
if s == "" || s[:2] != "go" {
25-
return 0, 0, errors.New("could not parse Go version: version does not start with 'go' prefix")
44+
if "" == s {
45+
return 0, 0, fmt.Errorf("%s: empty version", errPrefix)
46+
}
47+
48+
if strings.HasPrefix(s, "devel") {
49+
maj, min, err := getGorootApiVersion(goroot)
50+
if nil != err {
51+
return 0, 0, fmt.Errorf("%s: version API invalid: %s", errPrefix, err)
52+
}
53+
return maj, min, nil
54+
}
55+
56+
if !strings.HasPrefix(s, "go") {
57+
return 0, 0, fmt.Errorf("%s: version does not start with 'go' prefix", errPrefix)
2658
}
2759

2860
parts := strings.Split(s[2:], ".")
2961
if len(parts) < 2 {
30-
return 0, 0, errors.New("could not parse Go version: version has less than two parts")
62+
return 0, 0, fmt.Errorf("%s: version has less than two parts", errPrefix)
3163
}
3264

33-
// Ignore the errors, we don't really handle errors here anyway.
34-
var trailing string
35-
n, err := fmt.Sscanf(s, "go%d.%d%s", &major, &minor, &trailing)
36-
if n == 2 && err == io.EOF {
37-
// Means there were no trailing characters (i.e., not an alpha/beta)
38-
err = nil
65+
return parseGorootVersion(s)
66+
}
67+
68+
// getGorootApiVersion returns the major and minor version of the Go API files
69+
// defined for a given GOROOT path.
70+
// If the version cannot be determined, (0, 0) is returned.
71+
func getGorootApiVersion(goroot string) (int, int, error) {
72+
info, err := ioutil.ReadDir(filepath.Join(goroot, "api"))
73+
if nil != err {
74+
return 0, 0, fmt.Errorf("could not read API feature directory: %s", err)
3975
}
40-
if err != nil {
41-
return 0, 0, fmt.Errorf("failed to parse version: %s", err)
76+
maj, min := -1, -1
77+
for _, f := range info {
78+
if !strings.HasPrefix(f.Name(), "go") || f.IsDir() {
79+
continue
80+
}
81+
vers := strings.TrimSuffix(f.Name(), filepath.Ext(f.Name()))
82+
part := strings.Split(vers[2:], ".")
83+
if len(part) < 2 {
84+
continue
85+
}
86+
vmaj, vmin, err := parseGorootVersion(vers)
87+
if nil != err {
88+
continue
89+
}
90+
if vmaj >= maj && vmin > min {
91+
maj, min = vmaj, vmin
92+
}
93+
}
94+
if maj < 0 || min < 0 {
95+
return 0, 0, errors.New("no valid API feature files")
4296
}
43-
return
97+
return maj, min, nil
4498
}
4599

46100
// GorootVersionString returns the version string as reported by the Go

0 commit comments

Comments
 (0)