Proposal: go command configuration file

Russ Cox

Last Updated: March 1, 2019.

golang.org/design/30411-env

Discussion at golang.org/issue/30411

Abstract

Setting environment variables for go command configuration is too difficult and system-specific. We propose to add go env -w, to set defaults more easily.

Background

The go command is configured by environment variables: see the output of go env for a partial list, and go help environment for a longer one. Although nearly all variables are optional, it is not uncommon to need to set one or another. The details of setting an environment variable's initial value differs by operating system and even by distribution or terminal program—for example, do you have to log out entirely, or just restart the shell window?—which can make this environment-based configuration quite difficult. (When setting $GOPATH was required to get started with Go, doing so was a major stumbling block for new users.)

It would help all users to have a consistent, simple way to set the default value for these configuration variables.

Proposal

We propose to store in the file os.UserConfigDir()+”/go/env” a list of key-value pairs giving the default settings for configuration variables used by the go command. Environment variables, when set, override the settings in this file.

The go env <NAME> ... command will continue to report the effective values of the named configuration variables, using the current environment, or else the go.env file, or else a computed default.

A new option go env -w <NAME>=<VALUE> ... will set one or more configuration variables in the go.env file. The command will also print a warning if the current environment has $<NAME> defined and it is not set to <VALUE>. For example, a user who needs to set a default $GOPATH could now use:

go env -w GOPATH=$HOME/mygopath

Another popular setting might be:

go env -w GOBIN=$HOME/bin

The command go env -u <NAME>... will unset (delete, remove) entries in the environment file.

Most users will interact with the os.UserConfigDir()/go/env file through the go env and go env -w command line syntax, so the exact stored file format should not matter too much. But for concreteness, the format is a sequence of lines of the form <NAME>=<VALUE>, in which everything after the = is a literal, uninterpreted value—no quoting, no dollar expansion, no multiline values. Blank lines, lines beginning with #, and lines not containing =, are ignored. If the file contains multiple lines beginning with <NAME>=, only the first has any effect. Lines with empty values set the default value to the empty string, possibly overriding a non-empty default.

Only the go command will consult the os.UserConfigDir()/go/env file. The environment variables that control go libraries at runtime—for example, GODEBUG, GOMAXPROCS, and GOTRACEBACK—will not be read from go.env and will be rejected by go env command lines.

Rationale

The go command is already configured by environment variables, simple <KEY>=<VALUE> pairs. An alternative would be to introduce a richer configuration file format, such as JSON, TOML, XML, or YAML, but then we would also need to define how these richer values can be overridden in certain contexts. Continuing to use plain <KEY>=<VALUE> pairs aligns better with the existing environment-based approach and avoids increasing the potential complexity of any particular configuration.

The use of os.UserConfigDir() (see golang.org/issue/29960) seems to be the established correct default for most systems. Traditionally we've stored things in $GOPATH, but we want to allow this file to contain the default value for $GOPATH. It may be necessary—albeit ironic—to add a GOENV environment variable overriding the default location. Obviously, it would not be possible to set the default for GOENV itself in the file.

Compatibility

There are no compatibility issues. It may be surprising in some use cases that an empty environment still uses the go.env settings, but those contexts could avoid creating a go.env in the first place, or (if we add it) set GOENV=off.

Implementation

Russ Cox plans to do the implementation in the go command in Go 1.13.