livebud / bud

The Full-Stack Web Framework for Go
MIT License
5.58k stars 179 forks source link

`bud run` fails if using a different go version within project #217

Closed jmmk closed 2 years ago

jmmk commented 2 years ago

I installed bud using the default install script from https://raw.githubusercontent.com/livebud/bud/main/install.sh. It was placed at /usr/local/bin/bud

I use asdf (https://github.com/asdf-vm/asdf) to manage go versions and set specific versions to use within a given project/directory. The https://github.com/kennyp/asdf-golang plugin sets up the go env vars.

Example in a directory using go 1.18.4:

$ go env GOPATH GOMODCACHE GOROOT
/Users/jmmk/.asdf/installs/golang/1.18.4/packages
/Users/jmmk/.asdf/installs/golang/1.18.4/packages/pkg/mod
/Users/jmmk/.asdf/installs/golang/1.18.4/go

If I try bud run from within this directory, I get the following:

$ bud run
| Listening on http://127.0.0.1:3000
| conjure: generate "bud/internal/app/main.go". app: unable to load state: app: unable to wire. di: unable to wire "<my module name>/bud/program".loadWeb function. di: unable to find definition for param "github.com/livebud/bud/package/router".*Router in "github.com/jmmk/absolute-data-management/bud/internal/app/web".*Server . parser: unable to find declaration for "github.com/livebud/bud/package/router".Router in "bud/internal/app/web/web.go". stat /Users/jmmk/go/pkg/mod/github.com/livebud/bud@v0.2.1: no such file or directory

Where it looks in system default GOMODCACHE: $HOME/go/pkg/mod. The error is similar to https://github.com/livebud/bud/issues/78, but I do not have multiple directories on GOPATH.

If I create the following script and use it instead of bud, it works as expected.

#! /usr/bin/env bash
export GOPATH=/Users/jmmk/.asdf/installs/golang/1.18.4/packages
exec /usr/local/bin/bud "$@"

I don't fully understand what's happening, but I do have one thought:

matthewmueller commented 2 years ago

Ahh interesting, could you see what's happening here in your environment?

https://github.com/livebud/bud/blob/3a251081b908bc8c2dd15cfcaac0352b03e59f82/package/modcache/modcache.go#L376-L388

My guess right now: GOMODCACHE is not in your environment but somehow picked up by go env GOMODCACHE.

jmmk commented 2 years ago

According to https://go.dev/ref/mod#module-cache,

The default location of the module cache is $GOPATH/pkg/mod. To use a different location, set the GOMODCACHE environment variable.

That link states:

The directory where the go command will store downloaded modules and related files. See Module cache for details on the structure of this directory.

If GOMODCACHE is not set, it defaults to $GOPATH/pkg/mod.

The code you pasted above seems to follow this same logic.

If I run a test to see what is in the env:

package main

import (
    "fmt"
    "go/build"
    "os"
)

func main() {
    fmt.Printf("getenv GOPATH=%s\n", os.Getenv("GOPATH"))
    fmt.Printf("getenv GOROOT=%s\n", os.Getenv("GOROOT"))
    fmt.Printf("getenv GOMODCACHE=%s\n", os.Getenv("GOMODCACHE"))
    fmt.Printf("build.default GOPATH=%s\n", build.Default.GOPATH)
    fmt.Printf("build.default GOROOT=%s\n", build.Default.GOROOT)
}

Here is the output when run using go run main.go:

/tmp/go-env-test $ go run main.go
getenv GOPATH=/Users/jmmk/.asdf/installs/golang/1.18.4/packages
getenv GOROOT=/Users/jmmk/.asdf/installs/golang/1.18.4/go
getenv GOMODCACHE=
build.default GOPATH=/Users/jmmk/.asdf/installs/golang/1.18.4/packages
build.default GOROOT=/Users/jmmk/.asdf/installs/golang/1.18.4/go

which is consistent with go env output (just that GOMODCACHE is a computed value and is not set explicitly)

/tmp/go-env-test $ go env GOPATH GOROOT GOMODCACHE
/Users/jmmk/.asdf/installs/golang/1.18.4/packages
/Users/jmmk/.asdf/installs/golang/1.18.4/go
/Users/jmmk/.asdf/installs/golang/1.18.4/packages/pkg/mod

but when I run go build main.go && ./main I get the following:

/tmp/go-env-test $ go build main.go && ./main
getenv GOPATH=
getenv GOROOT=
getenv GOMODCACHE=
build.default GOPATH=/Users/jmmk/go
build.default GOROOT=/Users/jmmk/.asdf/installs/golang/1.18.4/go

So it seems the issue is not with bud itself.

The compiled binaries are not using the same environment as the shell. At first glance, it seems the way asdf manages the environment is specific to executables for that package (in this case, the go binary and any binary installed with go install for a given version of go).

Possible solutions

matthewmueller commented 2 years ago

Thanks for the details @jmmk!

One other potential solution:

I'm also somewhat tempted to close this issue as "wontfix" since I think it's fairly reasonable for a tool to expect that if go env GOMODCACHE has a custom path, you'd be expected to adjust export GOMODCACHE="..." in your .zshrc or equivalent. What do you think?

jmmk commented 2 years ago

@matthewmueller I think it's fair to close. bud is properly handling the environment variables. It's my shell environment that is not setting them up globally

jmmk commented 2 years ago

I found an existing issue thread on the asdf-golang repo about this: https://github.com/kennyp/asdf-golang/issues/28

There are several suggestions and workarounds, but I ended up following https://github.com/kennyp/asdf-golang/issues/28#issuecomment-863418448 to install https://github.com/asdf-community/asdf-direnv

After setting that up, moving into the project directory sets the proper GOPATH and bud run works as expected.

matthewmueller commented 2 years ago

Thanks for circling back with a solution!