@@ -16,7 +16,15 @@ func IsInstalled() bool {
16
16
return err == nil
17
17
}
18
18
19
+ // The default Go version that is available on a system and a set of all versions
20
+ // that we know are installed on the system.
19
21
var goVersion = ""
22
+ var goVersions = map [string ]struct {}{}
23
+
24
+ // Adds an entry to the set of installed Go versions for the normalised `version` number.
25
+ func addGoVersion (version string ) {
26
+ goVersions [semver .Canonical (version )] = struct {}{}
27
+ }
20
28
21
29
// Returns the current Go version as returned by 'go version', e.g. go1.14.4
22
30
func GetEnvGoVersion () string {
@@ -34,10 +42,57 @@ func GetEnvGoVersion() string {
34
42
}
35
43
36
44
goVersion = parseGoVersion (string (out ))
45
+ addGoVersion (goVersion )
37
46
}
38
47
return goVersion
39
48
}
40
49
50
+ // Determines whether, to our knowledge, `version` is available on the current system.
51
+ func HasGoVersion (version string ) bool {
52
+ _ , found := goVersions [semver .Canonical (version )]
53
+ return found
54
+ }
55
+
56
+ // Attempts to install the Go toolchain `version`.
57
+ func InstallVersion (workingDir string , version string ) bool {
58
+ // No need to install it if we know that it is already installed.
59
+ if HasGoVersion (version ) {
60
+ return true
61
+ }
62
+
63
+ // Construct a command to invoke `go version` with `GOTOOLCHAIN=go1.N.0` to give
64
+ // Go a valid toolchain version to download the toolchain we need; subsequent commands
65
+ // should then work even with an invalid version that's still in `go.mod`
66
+ toolchainArg := "GOTOOLCHAIN=go" + semver .Canonical (version )
67
+ versionCmd := Version ()
68
+ versionCmd .Dir = workingDir
69
+ versionCmd .Env = append (os .Environ (), toolchainArg )
70
+
71
+ log .Printf (
72
+ "Trying to install Go %s using its canonical representation in `%s`." ,
73
+ version ,
74
+ workingDir ,
75
+ )
76
+
77
+ // Run the command. If something goes wrong, report it to the log and signal failure
78
+ // to the caller.
79
+ if versionErr := versionCmd .Run (); versionErr != nil {
80
+ log .Printf (
81
+ "Failed to invoke `%s go version` in %s: %s\n " ,
82
+ toolchainArg ,
83
+ versionCmd .Dir ,
84
+ versionErr .Error (),
85
+ )
86
+
87
+ return false
88
+ }
89
+
90
+ // Add the version to the set of versions that we know are installed and signal
91
+ // success to the caller.
92
+ addGoVersion (version )
93
+ return true
94
+ }
95
+
41
96
// Returns the current Go version in semver format, e.g. v1.14.4
42
97
func GetEnvGoSemVer () string {
43
98
goVersion := GetEnvGoVersion ()
0 commit comments