urfave/gimme

Use shim approach instead of modifying `PATH`

meatballhat opened this issue ยท 8 comments

A pattern that's been adopted by other language version managers like rbenv and pyenv is to generate "shim" executables so that the value of PATH can remain stable. I think this would be a reasonable enhancement for gimme, too ๐ŸŽ‰

We could also accomplish something similar with a current (or similar) symlink such that there's only one PATH modification instead of one per usage (or a combination of both approaches with a current directory symlink and then per-tool symlinks into that current folder).

I don't know how common it is for users of gimme to use multiple versions concurrently (where the localized PATH modifications are not only useful but desirable), but at least in CI that's probably really uncommon.

@tianon I can contribute an anecdata point in that I use gimme via direnv in multiple projects with different go version needs. In that usage, a stable current wouldn't work, IIUC ๐Ÿค”

That sounds like an argument for the shims being optional and possibly even non-default. sweat_smile

@tianon oh! I was thinking that the shims would help with this situation ๐Ÿค” The shim would take into account the cwd and env and use the correct version, maybe bail with an error if the version isn't already installed? Although bailing early would be more like the behavior of {thing}env tools, it would be different than current gimme expectations which attempts to install whatever you ask for.

So you're thinking gimme would keep track of which version corresponds to each directory or some kind of sentinel file? (perhaps abusing go.mod's go X.YY?)

So you're thinking gimme would keep track of which version corresponds to each directory or some kind of sentinel file? (perhaps abusing go.mod's go X.YY?)

Right (I think) ๐Ÿค” There's precedent in other tooling to use a .{thing}-version file, which maybe gimme should learn how to respect, and there's the current support for abusing go.mod, and the long-time support for respecting GIMME_GO_VERSION which could be set via whatever env var management tool one prefers (I usually use direnv). I think the biggest behavioral difference here would be to bail early if the requested version isn't already available locally, so a generated/managed shim file would set something like GIMME_BAIL_ON_UNAVAILABLE=1 and then gimme would echo something helpful for human consumption to stderr. WDYT?

Seems pretty reasonable! Because I think better in code (especially Bash), here's a really rough example of my interpretation of your thoughts into a /usr/local/bin/go type wrapper:

#!/usr/bin/env bash
set -Eeuo pipefail

e="$(GIMME_BAIL_ON_UNAVAILABLE=1 gimme "${GIMME_GO_VERSION:-module}")"
eval "$e"

exec go "$@"
# perhaps even instead something like:
tool="$(basename "$0")"
exec "$tool" "$@"
# (so this same script can be symlinked to all the possible "go" tools we might want to invoke?  are there more than just "go" that are interesting?  I suppose "gofmt" is probably the only one, since it's the only other entry in Go's "bin/" directory)

@tianon Yes! and thank you!