TL;DR

“genv” is a Go tool which creates a Go development environment complete with your desired go version and all the things required to isolate it from all the other Go clutter on your computer. It behaves the same way as Python’s virtualenv or venv module. The source code is here

Why Do I Need This?

Here are my frustrations with the Go ecosystem circa 2021

  1. Once you download a version of Go, you are stuck with it. In order to use later (or earlier) versions of Go, you will need to delete the already installed binary, download a new version packet, move the binary to a path recognized by your environment, and maybe create a symlink. Go has ways of managing installations which is a much better option, but you still have to create a symlink.
  2. In order to work on a project hosted on a remote location like GitHub, you need to clone the project in the location Go expects it to be i.e. in a path matching the module path. For modules that have the same module path as the remote URL, this is a bit of an inconvenience but doable with mkdir -p and git clone. For vanity import paths, this is completely obscured, unless you go to the vanity URL, look at the meta link which may have the code hosted somewhere that is downloadable.
  3. Go modules are essentially frozen from development. By that I mean the dependent files are read only, they may or may not be pinned to a version that is tracable, and go.mod files may be full of “replace” clauses routing the declared names to a different location. After a little while, I lose track of what I was looking at and how it is related to the thing I am debugging. It doesn’t help if every project I look at exists in a single location. I suppose this is OK if all the code came from a single source of truth, but this is certainly not the case with Open Source projects.
  4. Hacking on a Go module is painful due to the frozen nature of the modules. Even if you did clone the dependency in the required location, you cannot rebuild the module unless you add a replace clause in your go.mod file. There is a tool called gohack that does this, but it seems one cannot give it a custom path to clone the project in. It does, however, do the replacing of the go.mod file.
  5. I would personally like to get a list of github projects cloned, hacked on with their git references so I can submit PRs to upstream dependencies. Unfortunately the go.sum file is very difficult to parse (and is only really required to validate the downloaded packages). I have found myself cd-ing to and from the various dependencies I had cloned to hack on a module just to get information about git branches and commits. But as I had listed above, I don’t think the ecosystem is built with development in mind (for now anyway).

What’s working now

  1. Creating environments with specific go versions
    genv -version go1.16.5 myenv
    cd myenv
    source bin/activate
    
  2. Creating environments with a specific project to clone
    genv -project git@github.com/nishakm/genv myenv
    cd myenv
    source bin/activate
    cd gopath/src/github.com/nishakm/genv
    

That’s basically it, and it’s enough to make my Go development much less painful on my Linux development environment. As you can see, there’s a lot of work to be done, and I won’t guarantee that this works on Mac OSX and Windows as these are not systems I work on. Hopefully, someone finds this useful and compelling enough to submit enhancement PRs.

In Conclusion

Go modules is actually a huge step forward in the Go ecosystem in terms of pinning and verifying modules and their dependencies. I was very happy when it arrived. However, as I learn enough to be dangerous, it gets more and more frustrtrating to manipulate the projects in order to understand them better. I hope there is a future with a good balance of development and release pinning.