Skip to content

Commit

Permalink
2024-08-19/01: Add "Quick bits: Go automatically downloads a newer to…
Browse files Browse the repository at this point in the history
…olchain if needed"
  • Loading branch information
thiagokokada committed Aug 19, 2024
1 parent 5c595d3 commit ccd9ffe
Showing 1 changed file with 73 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Quick bits: Go automatically downloads a newer toolchain if needed

I am using
[elliotchance/orderedmap](https://github.com/elliotchance/orderedmap/) as my
choice of ordered maps (since Go [doesn't have
one](/2024-08-17/01-an-unordered-list-of-things-i-miss-in-go.md) in standard
library yet). I recently did a
[PR](https://github.com/elliotchance/orderedmap/pull/41) to implement Go 1.23
iterators, because I find them neat, however I was avoiding to use it in the
code that generates this [blog](https://github.com/thiagokokada/blog) since Go
1.23 was just released and is still not the default Go in
[nixpkgs](https://github.com/NixOS/nixpkgs).

I decided that I would create a
[branch](https://github.com/thiagokokada/blog/pull/2) and leave there for a few
months, until I decided to try to run the code locally and got this:

```console
$ go build
go: downloading go1.23.0 (darwin/arm64)
```

Neat. And before you ask, yes, the compiled binary works perfectly:

```console
$ make
./blog > README.md
./blog -rss > rss.xml
```

So how does this work? Take a look at the documentation in the official [Golang
page](https://tip.golang.org/doc/toolchain):

> Starting in Go 1.21, the Go distribution consists of a go command and a
> bundled Go toolchain, which is the standard library as well as the compiler,
> assembler, and other tools. The go command can use its bundled Go toolchain
> as well as other versions that it finds in the local PATH or downloads as
> needed.
There are a bunch of rules here that I am not going to enter in detail (I
recommend you to read the official documentation), but a quick summary:

- Go will download a toolchain when either `go` or `toolchain` lines `go.mod`
is set to a Go version higher than your current `go` binary
+ But only if your `go` binary is at least version 1.21, since this is the
version that introduces this behavior
- You can force a specific toolchain with `GOTOOLCHAIN` environment setting,
e.g.: `GOTOOLCHAIN=1.23`
+ The default value for `GOTOOLCHAIN` is `auto`, that basically has the
behavior described in this post
+ You can also set to `local` to always use the current `go` binary, or the
previous behaviour pre-1.21 Go
+ There is also `<name>+auto` and `path` options, that can be seen in the
docs
- The downloaded toolchains go to whatever your `GOPATH` is, inside
`golang.org/toolchain` module, and version `v0.0.1-goVERSION.GOOS-GOARCH`.

By the way, this only works well because Go binaries are static, one of the
things that make the language [reasonable
good](/2024-07-29/02-go-a-reasonable-good-language.md).

While I don't like a program downloading random binaries from the internet, I
like what Go is doing here. It makes the whole bootstrapping process for a Go
project much easier: as long as you have a reasonable up-to-date `go` binary in
your `PATH`, you should be ready to go (pun intended). And Go modules are
already reasonable secure, ensuring that each module have a proper checksum. As
long as nobody else can publish modules in `golang.org/toolchain` namespace I
can't see much of a security issue here, but I am not a security expert.

But if you don't like this behavior, you can always disable it by setting
`GOTOOLCHAIN=local`. And just do not forget to set this in your
[CI](https://brandur.org/fragments/go-version-matrix), unless you don't care
about Go versions.

0 comments on commit ccd9ffe

Please sign in to comment.