Last week I was writing a small server application that I wanted to use as a playground for finally giving gb a real try. I’ve heard great things about it and given that my application was about to become a consumer of multiple libraries rather than a library itself it kind of sounded like a good idea.
I’ve used godep previously but didn’t like the idea of import path rewriting hence the check for alternatives.
gb makes quite a few things about working on projects extremely easy. Out of the
box it will build the whole project and install the resulting binary into a
clean bin
folder when running gb build
no matter where. When combined with
the vendor plugin it also solves dependencies quite nicely.
Sadly, I also ran into a few problems when wanting to integrate it into go-mode for Emacs. At first I thought setting the GOPATH accordingly to reflect the distinction between the project’s source code and dependencies should do the trick:
$ export GOPATH=$PROJECTROOT:$PROJECTROOT/vendor
Or do the equivalent in Emacs:
(defun zerok/setup-gb-gopath ()
(interactive)
(make-local-variable 'process-environment)
(let ((srcPath (_zerok/get-gb-src-folder buffer-file-name)))
(when srcPath
(let* ((projectPath (string-remove-suffix "/" (file-name-directory srcPath)))
(vendorPath (string-remove-suffix "/" (concat projectPath "/vendor")))
(gopath (concat vendorPath ":" projectPath)))
(message "Updating GOPATH to %s" gopath)
(setenv "GOPATH" gopath)))))
(add-hook 'go-mode-hook 'zerok/setup-gb-gopath)
(defun _zerok/get-gb-src-folder (path)
(let ((parent (directory-file-name (file-name-directory path)))
(basename (file-name-nondirectory path)))
(cond ((equal "src" basename)
(string-remove-suffix "/" path))
((equal "/" parent)
nil)
(t
(_zerok/get-gb-src-folder parent)))))
This helped with basically everything I was using from go-mode (goimports, …)
except for the autocompletion support that is built around gocode. After a
lot of debugging while waiting for one or the other plane to take me home from
Poznan I noticed the issue here being that gb places all dependency binaries not
in $PROJECTROOT/vendor/pkg
but in $PROJECTROOT/pkg
. Something that seems to
confuse either the go-tool or gocode itself quite a bit.
To get around this I wrote a little helper script (this repo also contains
the elisp snippet from above) that I’d from then on use right after changing
anything about my project’s dependencies. What it does is it copies the compiled
binaries around into vendor that would make it look more like a GOPATH
than it
actually is. Admittedly quite a hackey approach but it seems to work.
While talking with a couple of folks in the Gophers community on Slack John
Asmuth mentioned his own workspace tool for Go called wgo which surprisingly
has a folder structure nearly identical to gb’s but treats the vendor folder as
its own GOPATH segment. As it basically just wraps the go-tool, binaries will
then be placed in vendor/pkg
which solves my integration issue with gocode.
The downside is that wgo offers less convenience. For instance to build my little tool I had to do this:
$ cd src/cmd/myapp && wgo install
instead of just doing
$ gb build
On the other hand, gb doesn’t yet support an easy path for cross-platform compilation, which was also a big requirement for me here.
So right now wgo looks like the better fit for me. It lacks some of the comfort-features of gb, but it tries to keep everything as compatible to a multi-GOPATH-setup as possible. That, in turn, makes integrating it with other tools of the go-toolchain a lot easier π
That being said, I really hope that integration-story of gb improves, as it looks like a great tool and I’d really love to give it a try again in the future!
Do you want to give me feedback about this article in private? Please send it to comments@zerokspot.com.
Alternatively, this website also supports Webmentions. If you write a post on a blog that supports this technique, I should get notified about your link π