@@ -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