You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I want us to fully reconsider how GOPATH/GOROOT are handled. Current behavior is the result of legacy asdf and some patches to modify it but we should take a step back and ask how mise should handle these env vars.
Also note that I am not a go developer—in fact I quite dislike the language. I don't point that out to complain—as much fun as that would be—but so you know where I'm coming from and understand I may be wrong about specifics in go and what is idiomatic so I lean on you go devs to correct anything here that seems off.
This discussion is directly related to #815 but I'm creating a new discussion in order to clearly describe a plan.
Background: GOROOT, GOPATH, GOBIN
These env vars change how go and go tools behave:
GOROOT: set to the location of the current go sdk. Unless I am missing a use-case, this should always be set to where the go binary is located (well, specifically one level up, so /usr/local/go if which go is /usr/local/go/bin/go). go env will default this to that directory if the env var is not set, however some tools (of which I have not seen a concrete example but please send me one if you know of one) seem to rely on GOROOT being set as an env var. This should always be set and should change if the go version changes.
GOPATH: defaults to $HOME/go. Less important now that go modules are a thing but still used especially for go install. It contains 3 subdirectories:
bin go CLIs installed via go install—notably some of these may require GOROOT set as mentioned before. (TODO: does it matter if that GOROOT is not the same go that installed the CLI? I suspect this may be the case for a small minority of tools but have not seen a use-case.)
pkg not totally sure, but seems not super relevant to mise, seems to be cache and manifest stuff. Should work just fine when switching go versions. Probably best to share this across go versions to improve cache and reduce disk space.
src go source code from repositories. Obviously can and should be shared across go versions.
GOBIN: this is just the bin directory mentioned above but gives users the ability to use a completely different directory than $GOPATH/bin—allowing CLIs to go somewhere the pkg and src directories do not go.
Background: asdf
asdf-golang sets GOROOT/GOPATH with the following code (where ASDF_INSTALL_PATH=~/.asdf/installs/golang/1.21.0)
What this means is that GOPATH and GOROOT will be defaulted to be in a version-specific directory unless the user has explicitly set them. My educated guess here—that I can't find out for certain—is that these are each done for quite different reasons.
GOROOT pretty much always needs to be set. My understanding is users basically never modify this themselves. My understanding is this may be problematic because some tool other than asdf may set GOROOT to some sdk, asdf could change go to point to a different sdk and you'd end up with mismatched go and GOROOT values since GOROOT does not override an existing value. Here is an example of what happens when it is not consistent: #815 (comment)
GOPATH is actually kind of a hack if I understand right. The purpose is actually to get GOROOT to work correctly with go-installed CLIs. How this works is ASDF_INSTALL_PATH/packages/bin is added to the asdf "bin-paths" list which cause CLIs installed via go-install to have shims created for them via asdf reshim. Those shims will call bin/exec-env which will set GOROOT when calling the go cli.
To illustrate: if I run go install foo, that will create a bin at ASDF_INSTALL_PATH/packages/bin/foo. When I run asdf reshim, it will create a shim at ~/.asdf/shims/foo. That way when I call foo, it calls the shim which sets GOROOT before calling foo.
I believe that setting GOBIN=ASDF_INSTALL_PATH/bin would've been a less-intrusive (and simpler) solution for asdf since it wouldn't change the pkg and src directories unnecessarily. No clue if that was an accident or I am missing some reason for not going that route.
let gopath = self.gopath(tv).to_string_lossy().to_string();
map.insert("GOPATH".to_string(), gopath);
}
};
Ok(map)
MISE_GO_SET_GOROOT and MISE_GO_SET_GOPATH were added which allow the user to control when GOROOT/GOPATH are set. By default, it will set them if they are not already set. If one of the env vars is "true" it will always overwrite what was set. "false" will make it never modify them. This gives the users a lot more control.
MISE_GO_SET_GOROOT=true notably solves a problem for Goland users because Goland sets GOROOT and if mise doesn't overwrite that setting it will have mismatched GOROOT/go versions which (as already described) causes major problems.
GOPATH changes
GOPATH really doesn't make sense to manage via mise at all. mise should not set this at all unless MISE_GO_SET_GOPATH=true. Even then, we should deprecate that configuration and show a warning—not all the time—but when installing a new go version with mise. If there are use-cases for having GOPATH be inside of ~/.local/share/mise/installs please let me know.
Proposed changes:
change default behavior to not set GOPATH if it is not already set
add a "setting" for MISE_GO_SET_GOPATH
only set GOPATH if MISE_GO_SET_GOPATH=true (make it a 2-way setting)
Show a deprecation warning if MISE_GO_SET_GOPATH=true
update docs to reflect GOPATH changes
GOBIN changes
Currently go does not modify this env var, however shim users may have need for having GOROOT set with go-installed CLIs so we should have a way of making that work. (This is not a problem for mise activate or mise exec users since those commands will already set GOROOT.) If we make the changes to GOPATH above, we will lose the behavior that go-installed CLIs get shims.
To make this work, we will set GOBIN instead of GOPATH to MISE_INSTALL_PATH/bin which will cause go-installed CLIs to get shims for GOROOT behavior. GOPATH/src and GOPATH/pkg will stick with their default language-agnostic directories.
The downside of this is any CLIs installed with a mise-managed go will be lost when changing versions, however ~/.go-default-packages and the go backend are 2 better solutions for that problem.
Proposed changes:
add a new 3-way "setting" for MISE_GO_SET_GOBIN
if GOBIN is not already set, default behavior is to modify GOBIN=MISE_INSTALL_PATH/bin
MISE_GO_SET_GOBIN=false never sets GOBIN even if not set
remove logic to add packages/bin to bin-paths since it will no longer be needed
update docs to reflect GOBIN changes
GOROOT changes
GOROOT should be more aggressively set (meaning by default we set GOROOT even if it is already set) because there is only 1 use-case I can think of for not modifying GOROOT via mise. That's if you manage go via mise but then want to modify the go version with some other tool. If mise is aggressively modifying GOROOT even if PATH is set to use the non-mise go version, it will still modify GOROOT.
This is likely a very rare use-case though, so we just need to provide an option for it but it does not need to be the default behavior which will still happen as it does today with MISE_GO_SET_GOROOT=false.
Proposed changes:
add a "setting" for MISE_GO_SET_GOROOT
make setting default to true instead of 3-way
update docs to reflect GOROOT changes
go backend
The go backend is worth considering here as well. Today, this will simply use whatever go and GOROOT is currently set to in the shell—via mise or whatever else may have set it. It does, however, set GOPATH and GOBIN. In the case of go install go:github.com/DarthShim/[email protected] for example:
Go has new functionality in 1.21.0 for managing and switching go versions built into the go CLI itself. This is very cool but I have not explored it in depth. Despite being heavily related to mise development in go in general, I believe it is a separate item to consider and if anyone wants to discuss it I would encourage a new discussion for that topic since it feels unrelated to this problem—unless you feel that I'm wrong on that point.
Update: I created a discussion: #1639. tl;dr: I think this solution should dovetail nicely with go toolchains but it's a good thing we're moving to GOBIN and not modifying GOPATH like the current behavior. Doing that would cause users to lose their toolchains whenever they change go version with mise.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
I want us to fully reconsider how GOPATH/GOROOT are handled. Current behavior is the result of legacy asdf and some patches to modify it but we should take a step back and ask how mise should handle these env vars.
Also note that I am not a go developer—in fact I quite dislike the language. I don't point that out to complain—as much fun as that would be—but so you know where I'm coming from and understand I may be wrong about specifics in go and what is idiomatic so I lean on you go devs to correct anything here that seems off.
This discussion is directly related to #815 but I'm creating a new discussion in order to clearly describe a plan.
Background: GOROOT, GOPATH, GOBIN
These env vars change how go and go tools behave:
go
binary is located (well, specifically one level up, so/usr/local/go
ifwhich go
is/usr/local/go/bin/go
).go env
will default this to that directory if the env var is not set, however some tools (of which I have not seen a concrete example but please send me one if you know of one) seem to rely on GOROOT being set as an env var. This should always be set and should change if the go version changes.$HOME/go
. Less important now that go modules are a thing but still used especially forgo install
. It contains 3 subdirectories:bin
go CLIs installed viago install
—notably some of these may require GOROOT set as mentioned before. (TODO: does it matter if that GOROOT is not the same go that installed the CLI? I suspect this may be the case for a small minority of tools but have not seen a use-case.)pkg
not totally sure, but seems not super relevant to mise, seems to be cache and manifest stuff. Should work just fine when switching go versions. Probably best to share this across go versions to improve cache and reduce disk space.src
go source code from repositories. Obviously can and should be shared across go versions.bin
directory mentioned above but gives users the ability to use a completely different directory than$GOPATH/bin
—allowing CLIs to go somewhere the pkg and src directories do not go.Background: asdf
asdf-golang sets GOROOT/GOPATH with the following code (where
ASDF_INSTALL_PATH=~/.asdf/installs/golang/1.21.0
)What this means is that GOPATH and GOROOT will be defaulted to be in a version-specific directory unless the user has explicitly set them. My educated guess here—that I can't find out for certain—is that these are each done for quite different reasons.
GOROOT pretty much always needs to be set. My understanding is users basically never modify this themselves. My understanding is this may be problematic because some tool other than asdf may set GOROOT to some sdk, asdf could change
go
to point to a different sdk and you'd end up with mismatchedgo
andGOROOT
values since GOROOT does not override an existing value. Here is an example of what happens when it is not consistent: #815 (comment)GOPATH is actually kind of a hack if I understand right. The purpose is actually to get GOROOT to work correctly with go-installed CLIs. How this works is ASDF_INSTALL_PATH/packages/bin is added to the asdf "bin-paths" list which cause CLIs installed via go-install to have shims created for them via
asdf reshim
. Those shims will callbin/exec-env
which will set GOROOT when calling the go cli.To illustrate: if I run
go install foo
, that will create a bin at ASDF_INSTALL_PATH/packages/bin/foo. When I runasdf reshim
, it will create a shim at ~/.asdf/shims/foo. That way when I callfoo
, it calls the shim which setsGOROOT
before callingfoo
.I believe that setting
GOBIN=ASDF_INSTALL_PATH/bin
would've been a less-intrusive (and simpler) solution for asdf since it wouldn't change the pkg and src directories unnecessarily. No clue if that was an accident or I am missing some reason for not going that route.Related:
$GOPATH
or$GOROOT
are not set & request for a custom place to use my installed go version asdf-community/asdf-golang#28GOPATH
asdf-community/asdf-golang#106Background: mise
The mise go core plugin behaves slightly differently than asdf based on some feedback:
mise/src/plugins/core/go.rs
Lines 188 to 202 in e291cc3
MISE_GO_SET_GOROOT and MISE_GO_SET_GOPATH were added which allow the user to control when GOROOT/GOPATH are set. By default, it will set them if they are not already set. If one of the env vars is "true" it will always overwrite what was set. "false" will make it never modify them. This gives the users a lot more control.
MISE_GO_SET_GOROOT=true notably solves a problem for Goland users because Goland sets GOROOT and if mise doesn't overwrite that setting it will have mismatched GOROOT/go versions which (as already described) causes major problems.
GOPATH changes
GOPATH really doesn't make sense to manage via mise at all. mise should not set this at all unless MISE_GO_SET_GOPATH=true. Even then, we should deprecate that configuration and show a warning—not all the time—but when installing a new go version with mise. If there are use-cases for having GOPATH be inside of
~/.local/share/mise/installs
please let me know.Proposed changes:
GOBIN changes
Currently go does not modify this env var, however shim users may have need for having GOROOT set with go-installed CLIs so we should have a way of making that work. (This is not a problem for
mise activate
ormise exec
users since those commands will already set GOROOT.) If we make the changes to GOPATH above, we will lose the behavior that go-installed CLIs get shims.To make this work, we will set GOBIN instead of GOPATH to MISE_INSTALL_PATH/bin which will cause go-installed CLIs to get shims for GOROOT behavior. GOPATH/src and GOPATH/pkg will stick with their default language-agnostic directories.
The downside of this is any CLIs installed with a mise-managed go will be lost when changing versions, however
~/.go-default-packages
and the go backend are 2 better solutions for that problem.Proposed changes:
GOROOT changes
GOROOT should be more aggressively set (meaning by default we set GOROOT even if it is already set) because there is only 1 use-case I can think of for not modifying GOROOT via mise. That's if you manage go via mise but then want to modify the go version with some other tool. If mise is aggressively modifying GOROOT even if PATH is set to use the non-mise go version, it will still modify GOROOT.
This is likely a very rare use-case though, so we just need to provide an option for it but it does not need to be the default behavior which will still happen as it does today with MISE_GO_SET_GOROOT=false.
Proposed changes:
go backend
The go backend is worth considering here as well. Today, this will simply use whatever
go
andGOROOT
is currently set to in the shell—via mise or whatever else may have set it. It does, however, set GOPATH and GOBIN. In the case ofgo install go:github.com/DarthShim/[email protected]
for example:GOPATH=~/.cache/mise/go-github.com-DarthSim-hivemind/1.0.0
GOBIN=~/.local/share/mise/installs/go-github.com-DarthSim-hivemind/1.0.0
Go toolchains
Go has new functionality in 1.21.0 for managing and switching go versions built into the
go
CLI itself. This is very cool but I have not explored it in depth. Despite being heavily related to mise development in go in general, I believe it is a separate item to consider and if anyone wants to discuss it I would encourage a new discussion for that topic since it feels unrelated to this problem—unless you feel that I'm wrong on that point.Update: I created a discussion: #1639. tl;dr: I think this solution should dovetail nicely with go toolchains but it's a good thing we're moving to GOBIN and not modifying GOPATH like the current behavior. Doing that would cause users to lose their toolchains whenever they change go version with mise.
Beta Was this translation helpful? Give feedback.
All reactions