Building Go projects with gb

Sähköä ilmassa sunset behind power lines
Image courtesy of smerikal

gb is a new build tool for Go created by Dave Cheney. It address the problem of reproducible builds. Building the same functional binary anywhere at any time is a problem of dependency management. Of knowing exactly which library version to use, and having it at hand. gb is a radical tool compared to current dependency solutions, which work with the existing Go toolchain and idioms. gb takes a different approach, it replaces not only dependency management tools, but the Go build tools themselves. Instead of using go build or go install you would use gb build.

Dependency management in Go has always been a little wonky, a little weird. From the beginning there was go get but no other specific tools or process. go get infers a location from the import path about where libraries live, and grabs them. Placing them ever so lovingly in the src directory along side project code. go get knows enough about DVCS to grab the HEAD code, but not much more. There are no options for specifying which, if any, versions should be used, or commit hashes to checkout. The idea was to simply keep everything up to date manually. Keeping everything at HEAD sounds nice, but in practice it has proved problematic.

Realizing this wasn’t a good long-term solution, the Go Team called upon the community to develop ideas and play with solutions. A wonderful idea indeed; practicing and playing will give us better solutions than just pie in the sky thinking would. The results of this are now coming to fruition, the Go Team has called for Vendoring to be the community’s solution to dependency management. They called for a consensus to be reached on a file format for tools doing to dependency management to interoperate.

The idea behind gb

gb’s solution for reproducible builds is based on the idea that the go get command, and associated handling of dependencies, is fundamentally flawed. gb suggests a new way to handle dependencies and build Go applications.

gb replaces go build because it has to. gb stores Go code in two places; first in $GOPATH/src where main.main() is, this represents the project, and then in $GOPATH/vendor/src where 3rd party dependencies are kept. gb looks in both of these location when building the project binary, where go build does not.

Project Based

gb works on projects. A project is “defined as any directory that has a src/ subdirectory.”

~/myProject/src and $GOPATH/src are two examples, each one it’s own project.

To gb a project is an end goal, not to be consumed by other code. Not to be imported and used. Projects are not go get’able. They are where main() lives, they compile to a binary you intend to run.

No configuration

gb does not use a configuration file, the source and code structure alone is enough to build a project. Dave Cheney is not opposed to having one; in fact he would rather have one than not. But opted to go without due to lack of consensus by the community on the format.

Respect the Source

gb does not do any import rewriting. This is because it has two separate locations for code. gb checks in both src and vendor/src when looking for the source of an import, where go build does not. Tools like godeps have to rewrite import paths for its vendored libraries otherwise the build when fail when go build can’t find them.

I like that I don’t have to do import rewriting for my dependency’s dependencies. I want to use a library and never have to change it from what the upstream devs intended. This hands-off approach carries over to canonical import paths as well. They are left untouched.

I really like that 3rd party code is separated out into its own directory, and all libraries are flatly organized in that directory. I can look at vendor/src and see all of my dependencies. I don’t have to go hunting and pecking for a vendored package of a vendored package.

Reproducible Builds

The main goal for gb is reproducible builds. It manages this by vendoring. Which takes libraries the project needs and makes them a part of the gb project, and commits them to the projects source control repository. Vendored packages are stored in $PROJECT/vendor/src/.

Any new checkout of the project will have all dependencies needed to build. If one is so daring there you can use git submodules/subtrees to store the dependeny’s history.

Dependency Versioning

gb, in it’s current state, does not manage dependency or which version are used. Rather it delegates this responsibility to gb-vendor, a plugin to the main gb tool.

gb-vendor itself is not special; it is a wrapper around go get -d. It’s only purpose is to grab dependencies that are go-get’able and drop them into the project’s vendor directory at $PROJECT/vendor/src/

gb-vendor is a quick proof of concept that Dave threw together. It lacks many features of a tradition DVCS; which puts it in a tricky position. What is gb-vendor’s role in managing dependency version and how much work should it do before pawning off to a proper DVCS.

Usage

gb is straightforward to use. First you vendor your dependencies, then you build your application.

1
2
3
4
5
6
cd myPackage
git init
gb vendor github.com/thirdParty/lib
gb build myPackage/myApp
git add ./
git commit

or you can use gb build all to build everything in your src directory.

A note about gb vendor; it was a quick plugin that Dave threw together to make his talk go smother. It may or may not stay around. What it actually does is in flux, and its future really depends on how developers use it, and want to use it. There is an open ticket on github for discussing `gb vendor'.

You can find detailed examples in the getting started documentation on github.

A turn in the road

I like gb. I’ve played with it for a couple of days, and it aligns with my personal preferences for Go development and project structure; more so than other dependency solutions currently available. It feels light-weight. It gets out of my way, and lets me manage my code without interfering. It feels good.

gb feels like a departure of sorts; but it isn’t so different than the core Go assumptions about code structure. Rather it looks at them in a different way. I can’t help but feel that this is some sort of significant moment in Go history. One we will look back upon; with reverence or trepidation I don’t know, only time will tell. For now, though, I will use it to build my projects.


Learn more about gb on github. Also, take a look at the slides from the GDG talk in Berlin, or watch the video.

Building Go projects with gb by
  tools  programming  golang 
Like what you read? Share it:
  Facebook   Email