Managing a Go Environment in Ubuntu

February 10, 2015

Many moons ago, I wrote about setting up a Go environment in Ubuntu. After writing that post, I dropped Go development for nearly a year. Today I run the Indy Golang meetup, and soon I’ll be starting a new work project where I’ll be recommending a Go-based tech stack. I’ve learned a thing or two about Go and managing its dependencies since I wrote that initial blog post, and I intend to give a short presentation to my meetup about my recent findings. Before I do, I thought I’d write a preliminary blog post detailing the tools I use to keep my Go environment sane.

Installing Go

The easiest way to install Go in Ubuntu is through <code class="codecolorer ruby default"><span class="ruby">aptitude</span>. However, the default version in the Ubuntu repos gets stale fast. I found a tool similar to <code class="codecolorer ruby default"><span class="ruby">rvm</span> for downloading and installing local versions of Go called gvm. For better or worse, <code class="codecolorer ruby default"><span class="ruby">gvm</span> is installed through a bash script. Fortunately, it doesn’t require sudo:

$ bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)

At this point I removed all my previous finaglig with <code class="codecolorer ruby default"><span class="ruby"><span class="re0">$GOROOT</span></span> and <code class="codecolorer ruby default"><span class="ruby"><span class="re0">$GOPATH</span></span> from my dot files. You can use <code class="codecolorer ruby default"><span class="ruby">gvm listall</span> to see all available versions of Go. As of the writing of this blog post, <code class="codecolorer ruby default"><span class="ruby">go1.4.1</span> is the latest release; however, go1.4 is the most recent release available with <code class="codecolorer ruby default"><span class="ruby">gvm</span>. I’m not sure when the list is updated, but I have confidence that it is fairly regular. To install a Go and set it as the default Go:

$ gvm install go1.4 –default $ which go /home/lrp/.gvm/gos/go1.4/bin/go

Managing Packages

This is where I come to a fork in the road: <code class="codecolorer ruby default"><span class="ruby">gvm</span>, the tool we used to install the desired version of Go, has a concept of pkgset similar to <code class="codecolorer ruby default"><span class="ruby">rvm gemset</span>. However, I find the syntax for using a pkgset tiresome every time I come into a directory. I prefer something more automatic. As an additional pain, <code class="codecolorer ruby default"><span class="ruby">gvm</span> does not provide a mechanism for installing dependencies from a list of known dependencies. I sought out other tools to address these pains and found gpm and gvp.

<code class="codecolorer ruby default"><span class="ruby">gpm</span> is a tool used to manage Go packages. It reads in a file called <code class="codecolorer ruby default"><span class="ruby">Godeps</span> which contains a list of packages with versions and can install them from their individual sources. I’m currently infatuated with <code class="codecolorer ruby default"><span class="ruby">gpm</span> as it addresses a lot of concerns I had when initially learning Go: shared local dependencies, unclear versioning, and installing dependencies from a fresh clone. Install <code class="codecolorer ruby default"><span class="ruby">gvm</span> and <code class="codecolorer ruby default"><span class="ruby">gvp</span>:

$ pushd /tmp $ git clone https://github.com/pote/gvp.git && cd gvp $ ./configure && sudo make install $ cd /tmp $ git clone https://github.com/pote/gpm.git && cd gpm $ ./configure && sudo make install $ popd

We can follow two paths here: using <code class="codecolorer ruby default"><span class="ruby">gvm pkgset</span> or using a local <code class="codecolorer ruby default"><span class="ruby">.<span class="me1">godeps</span></span> directory to store our dependencies discretely. For these examples, I’ll create a directory called <code class="codecolorer ruby default"><span class="ruby">gotest</span> with a single file in it:

package main import “github.com/go-martini/martini” func main() { server := martini.Classic() server.Get(“/”, func() string { return ”

Hello, world!

” }) server.Run() }

Method 1: gvm pkgset alongside gpm

Create and start using a new pkgset:

$ gvm pkgset create gotest $ echo $GOPATH /home/lrp/.gvm/pkgsets/go1.4/global $ gvm pkgset use gotest $ echo $GOPATH /home/lrp/.gvm/pkgsets/go1.4/gotest:/home/lrp/.gvm/pkgsets/go1.4/global

What this means is that we are now using our <code class="codecolorer ruby default"><span class="ruby">gotest</span> pkgset as default, but the global pkgset will be used to dig up any missing packages. In order to install any dependencies, we need to create a <code class="codecolorer ruby default"><span class="ruby">Godeps</span> file for <code class="codecolorer ruby default"><span class="ruby">gpm</span> to consume. Our application from above has a dependency on <code class="codecolorer ruby default"><span class="ruby">go<span class="sy0">-</span>martini</span>, so let’s add a dependency to <code class="codecolorer ruby default"><span class="ruby">v1.0</span> in our Godeps file:

github.com/go-martini/martini v1.0

After you run <code class="codecolorer ruby default"><span class="ruby">go build</span> to verify that the dependencies aren’t installed, run <code class="codecolorer ruby default"><span class="ruby">gpm install</span> to pull the required packages into your specified pkgset. Run <code class="codecolorer ruby default"><span class="ruby">go build</span> again and revel in your own brilliance.

That was pretty great, right? The only issue is remembering to type <code class="codecolorer ruby default"><span class="ruby">gvm pkgset use gotest</span> every time you restart your terminal or switch projects. Otherwise, <code class="codecolorer ruby default"><span class="ruby">gvm</span> is practically a replacement for one of my favorite ruby tools <code class="codecolorer ruby default"><span class="ruby">rvm</span>.

Method 2: gpm and gvp

<code class="codecolorer ruby default"><span class="ruby">gpm</span> is intended to be similar to <code class="codecolorer ruby default"><span class="ruby">npm</span> a package management tool for NodeJS. The author suggests using a tool called <code class="codecolorer ruby default"><span class="ruby">gvp</span> to set the <code class="codecolorer ruby default"><span class="ruby">GOPATH</span> without much thought. If we start a fresh terminal in our example directory, we can use <code class="codecolorer ruby default"><span class="ruby">gvp</span> to set up our <code class="codecolorer ruby default"><span class="ruby">GOPATH</span>:

$ echo $GOPATH /home/lrp/.gvm/pkgsets/go1.4/global $ source gvp $ echo $GOPATH /home/lrp/Projects/2015/gotest/.godeps:/home/lrp/Projects/2015/gotest

You can note the difference in our <code class="codecolorer ruby default"><span class="ruby">GOPATH</span> here relative to <code class="codecolorer ruby default"><span class="ruby">gvm</span>: we will be using our current directory as a source of code in addition to a local <code class="codecolorer ruby default"><span class="ruby">.<span class="me1">godeps</span></span> directory. Go ahead and add <code class="codecolorer ruby default"><span class="ruby">.<span class="me1">godeps</span></span> to your <code class="codecolorer ruby default"><span class="ruby">.<span class="me1">gitignore</span></span> file or equivalent. We can use the same <code class="codecolorer ruby default"><span class="ruby">Godeps</span> file as before:

github.com/go-martini/martini v1.0

We run <code class="codecolorer ruby default"><span class="ruby">gpm install</span> to install the dependencies to our local <code class="codecolorer ruby default"><span class="ruby">.<span class="me1">godeps</span></span> directory.

I prefer this method to using pkgsets. I’ve had better luck building projects with complicated structures, and it’s a lot easier for me to run <code class="codecolorer ruby default"><span class="ruby">source gvp</span> than it is to remember the name of my pkgset. Both methods work pretty well and give me warm fuzzies about managing my dependencies. I’m certain that as Go continues to mature more solutions will come available. I’ve also been researching using Docker with gpm only, which requires very little tweaking to what I’ve already discussed here.

This post was originally posted here:https://larry-price.com/blog/2015/01/18/managing-a-go-environment-in-ubuntu/#disqus_thread