@@ -20,34 +20,88 @@ var (
2020 GitSha1 string
2121)
2222
23+ // parseGorootVersion returns the major and minor version for a given Go version
24+ // string of the form `goX.Y.Z`.
25+ // Returns (0, 0) if the version cannot be determined.
26+ func parseGorootVersion (version string ) (int , int , error ) {
27+ var (
28+ maj , min int
29+ pch string
30+ )
31+ n , err := fmt .Sscanf (version , "go%d.%d%s" , & maj , & min , & pch )
32+ if n == 2 && io .EOF == err {
33+ // Means there were no trailing characters (i.e., not an alpha/beta)
34+ err = nil
35+ }
36+ if nil != err {
37+ return 0 , 0 , fmt .Errorf ("failed to parse version: %s" , err )
38+ }
39+ return maj , min , nil
40+ }
41+
2342// GetGorootVersion returns the major and minor version for a given GOROOT path.
24- // If the goroot cannot be determined, (0, 0) is returned.
25- func GetGorootVersion (goroot string ) (major , minor int , err error ) {
43+ // If the version cannot be determined, (0, 0) is returned.
44+ func GetGorootVersion (goroot string ) (int , int , error ) {
45+ const errPrefix = "could not parse Go version"
2646 s , err := GorootVersionString (goroot )
2747 if err != nil {
2848 return 0 , 0 , err
2949 }
3050
31- if s == "" || s [:2 ] != "go" {
32- return 0 , 0 , errors .New ("could not parse Go version: version does not start with 'go' prefix" )
51+ if "" == s {
52+ return 0 , 0 , fmt .Errorf ("%s: version string is empty" , errPrefix )
53+ }
54+
55+ if strings .HasPrefix (s , "devel" ) {
56+ maj , min , err := getGorootApiVersion (goroot )
57+ if nil != err {
58+ return 0 , 0 , fmt .Errorf ("%s: invalid GOROOT API version: %s" , errPrefix , err )
59+ }
60+ return maj , min , nil
61+ }
62+
63+ if ! strings .HasPrefix (s , "go" ) {
64+ return 0 , 0 , fmt .Errorf ("%s: version does not start with 'go' prefix" , errPrefix )
3365 }
3466
3567 parts := strings .Split (s [2 :], "." )
3668 if len (parts ) < 2 {
37- return 0 , 0 , errors . New ( "could not parse Go version : version has less than two parts" )
69+ return 0 , 0 , fmt . Errorf ( "%s : version has less than two parts", errPrefix )
3870 }
3971
40- // Ignore the errors, we don't really handle errors here anyway.
41- var trailing string
42- n , err := fmt .Sscanf (s , "go%d.%d%s" , & major , & minor , & trailing )
43- if n == 2 && err == io .EOF {
44- // Means there were no trailing characters (i.e., not an alpha/beta)
45- err = nil
72+ return parseGorootVersion (s )
73+ }
74+
75+ // getGorootApiVersion returns the major and minor version of the Go API files
76+ // defined for a given GOROOT path.
77+ // If the version cannot be determined, (0, 0) is returned.
78+ func getGorootApiVersion (goroot string ) (int , int , error ) {
79+ info , err := ioutil .ReadDir (filepath .Join (goroot , "api" ))
80+ if nil != err {
81+ return 0 , 0 , fmt .Errorf ("could not read API feature directory: %s" , err )
4682 }
47- if err != nil {
48- return 0 , 0 , fmt .Errorf ("failed to parse version: %s" , err )
83+ maj , min := - 1 , - 1
84+ for _ , f := range info {
85+ if ! strings .HasPrefix (f .Name (), "go" ) || f .IsDir () {
86+ continue
87+ }
88+ vers := strings .TrimSuffix (f .Name (), filepath .Ext (f .Name ()))
89+ part := strings .Split (vers [2 :], "." )
90+ if len (part ) < 2 {
91+ continue
92+ }
93+ vmaj , vmin , err := parseGorootVersion (vers )
94+ if nil != err {
95+ continue
96+ }
97+ if vmaj >= maj && vmin > min {
98+ maj , min = vmaj , vmin
99+ }
100+ }
101+ if maj < 0 || min < 0 {
102+ return 0 , 0 , errors .New ("no valid API feature files" )
49103 }
50- return
104+ return maj , min , nil
51105}
52106
53107// GorootVersionString returns the version string as reported by the Go
0 commit comments