As many Go developers likely know, the
goimports tool is great for managing all of the imports in your file. It checks the signature of functions, variables, etc. that are called on undefined variables, then looks for any available imports in your
$GOPATH with a matching signature, and updates your code with that import (and removes unused imports).
My problem is that I have several Go projects that are using similar syntax (they have some functions with equivalent signatures), and
goimports sometimes chooses to import from the wrong repository. The solution was obvious: set up a separate
$GOPATH for each project - that way,
goimports would only load libraries in the
$GOPATH of said project. Implementing that solution was ... less obvious. Here's my specific implementation:
First, I needed to add to my
.zshrc so that every time my working directory changed, zsh would check for a
$GOPATH in the working directory and all parent directories. I've restricted it to
$HOME, so that it doesn't keep looking in parent directories all the way up to the root of the drive, but basically it just looks for any directories containing a file named
.gopath - that's my way of signaling that the directory is a valid
$GOPATH. Here is a gist containing the relevant chpwd function.
Second, I needed emacs (my editor of choice) to set up buffer-local variables for both
exec-path (emacs' version of
$PATH) every time I open a Go file. It turns out emacs automatically looks for a file named
.dir-locals.el in the directory of any files opened and all parent directories. This file can be set up to define certain variables based on the language of the file that's opened. Here is my implementation - I just symlink that file to
$GOPATH/.dir-locals.el. Side note, that repository contains my full emacs config in the
project init script
go-get-project projectImportPath [destDir]
Overall, it seems to be working well. In each
$GOPATH, I only work on the project that the
$GOPATH is set up for, which also encourages me to write unit tests instead of relying on other projects to test functionality.