@@ -22,30 +22,81 @@ package cli
2222import (
2323 "fmt"
2424 "os"
25- "os/exec"
2625 "path/filepath"
26+ "regexp"
2727
28+ "github.com/Masterminds/semver/v3"
29+ "github.com/pkg/errors"
2830 "github.com/urfave/cli/v2"
2931)
3032
3133func use (ctx * cli.Context ) error {
3234 vname := ctx .Args ().First ()
3335 if vname == "" {
34- return cli .ShowSubcommandHelp (ctx )
36+ // Uses go.mod if available and version is omitted
37+ goModData , err := os .ReadFile ("go.mod" )
38+ if err != nil {
39+ if errors .Is (err , os .ErrNotExist ) {
40+ return cli .Exit (wrapstring ("No go.mod file found" ), 1 )
41+ }
42+ return cli .Exit (errstring (err ), 1 )
43+ }
44+
45+ goDirective := getGoDirective (goModData )
46+ wd , err := os .Getwd ()
47+ if err != nil {
48+ wd = "."
49+ }
50+ if goDirective == "" {
51+ return cli .Exit (wrapstring (fmt .Sprintf ("Go directive does not exist in %q files" , filepath .Join (wd , "go.mod" ))), 1 )
52+ }
53+ fmt .Printf ("Found %q with version <%s>\n " , filepath .Join (wd , "go.mod" ), goDirective )
54+ vname = goDirective
3555 }
36- targetV := filepath .Join (versionsDir , vname )
3756
38- if finfo , err := os .Stat (targetV ); err != nil || ! finfo .IsDir () {
39- return cli .Exit (fmt .Sprintf ("[g] The %q version does not exist, please install it first." , vname ), 1 )
57+ versions , err := listLocalVersions (versionsDir )
58+ if err != nil {
59+ return cli .Exit (errstring (err ), 1 )
4060 }
4161
42- _ = os .Remove (goroot )
62+ // Try to match the version number strictly first
63+ for i := range versions {
64+ if versions [i ].Name () != vname {
65+ continue
66+ }
67+ if err = switchVersion (versions [i ].Name ()); err != nil {
68+ return cli .Exit (errstring (err ), 1 )
69+ }
70+ return nil
71+ }
4372
44- if err := mkSymlink (targetV , goroot ); err != nil {
73+ // Try fuzzy matching the version number again
74+ cs , err := semver .NewConstraint (vname )
75+ if err != nil {
4576 return cli .Exit (errstring (err ), 1 )
4677 }
47- if output , err := exec .Command (filepath .Join (goroot , "bin" , "go" ), "version" ).Output (); err == nil {
48- fmt .Print (string (output ))
78+
79+ for j := len (versions ) - 1 ; j >= 0 ; j -- {
80+ if ! versions [j ].MatchConstraint (cs ) {
81+ continue
82+ }
83+ if err = switchVersion (versions [j ].Name ()); err != nil {
84+ return cli .Exit (errstring (err ), 1 )
85+ }
86+ return nil
87+ }
88+
89+ return cli .Exit (wrapstring (fmt .Sprintf ("The %q version does not exist, please install it first." , vname )), 1 )
90+ }
91+
92+ var goDirectiveReg = regexp .MustCompile (`(?m)^go\s+(\d+\.\d+(?:\.\d+)?(?:beta\d+|rc\d+)?)\s*(?:$|//.*)` )
93+
94+ // getGoDirective Extract the go directive from the go.mod file.
95+ func getGoDirective (goModData []byte ) string {
96+ // https://go.dev/ref/mod#go-mod-file-go
97+ match := goDirectiveReg .FindStringSubmatch (string (goModData ))
98+ if len (match ) > 1 {
99+ return match [1 ]
49100 }
50- return nil
101+ return ""
51102}
0 commit comments