Dead Simple Dependencies in Go

Keep it simple and keep your sanity.

Emil Davtyan
3 min readFeb 2, 2015

Go’s authors realized that package versioning is a complex issue better left to the community to figure out. Imports were left as string literals so people could experiment and build tools to address the issue.

However, their own versioning method was hidden quietly in Go’s FAQ :

If you’re using an externally supplied package and worry that it might change in unexpected ways, the simplest solution is to copy it to your local repository. (This is the approach Google takes internally.) Store the copy under a new import path that identifies it as a local copy.

Simply copy a package into your repository and update the import paths. This eliminates issues with locking down a version and ensuring availability. It does not require you or anyone else to alter a GOPATH, get dependencies, or install some other tool to work with your code. It simply works.

To help, I made a tool that allows you to easily get started with vending your own Go packages.

As a demonstration, let’s vend the dependencies of the following package :

package mainimport (
_ “code.google.com/p/go-sqlite/go1/sqlite3"
_ “code.google.com/p/go-uuid/uuid”
_ “code.google.com/p/gopacket”
_ “github.com/PuerkitoBio/goquery”
_ “github.com/Shopify/sarama”
_ “github.com/astaxie/beego”
_ “github.com/codegangsta/cli”
_ “github.com/coopernurse/gorp”
_ “github.com/garyburd/redigo/redis”
_ “github.com/gin-gonic/gin”
_ “github.com/go-martini/martini”
_ “github.com/go-sql-driver/mysql”
_ “github.com/gorilla/mux”
_ “github.com/gorilla/websocket”
_ “github.com/lib/pq”
_ “github.com/streadway/amqp”
_ “golang.org/x/crypto/bcrypt”
_ “golang.org/x/crypto/ssh”
_ “golang.org/x/mobile/app”
_ “golang.org/x/net/context”
_ “golang.org/x/net/html”
_ “golang.org/x/tools/go/types”
_ “gopkg.in/mgo.v2"
)

Then in the directory containing the package run vend init to place the packages into the lib subdirectory :

vend init lib

All the dependencies will now be located in subdirectories with their package name :

.
└── lib
├── amqp
├── app
├── bcrypt
├── beego
├── cli
├── context
├── gin
├── gopacket
├── goquery
├── gorp
├── html
├── martini
├── mgo
├── mux
├── mysql
├── pq
├── redis
├── sarama
├── sqlite3
├── ssh
├── types
├── uuid
└── websocket
24 directories

And the imports in the package will be modified accordingly :

package mainimport (
_ “github.com/example/lib/sqlite3"
_ “github.com/example/lib/uuid”
_ “github.com/example/lib/gopacket”
_ “github.com/example/lib/goquery”
_ “github.com/example/lib/sarama”
_ “github.com/example/lib/beego”
_ “github.com/example/lib/cli”
_ “github.com/example/lib/gorp”
_ “github.com/example/lib/redis”
_ “github.com/example/lib/gin”
_ “github.com/example/lib/martini”
_ “github.com/example/lib/mysql”
_ “github.com/example/lib/mux”
_ “github.com/example/lib/websocket”
_ “github.com/example/lib/pq”
_ “github.com/example/lib/amqp”
_ “github.com/example/lib/bcrypt”
_ “github.com/example/lib/ssh”
_ “github.com/example/lib/app”
_ “github.com/example/lib/context”
_ “github.com/example/lib/html”
_ “github.com/example/lib/types”
_ “github.com/example/lib/mgo”
)

If multiple packages were found to be using the same name it would output an error, an example from the Camlistore project :

Error : duplicate packages names found :
sqlite found at camlistore.org/pkg/sorted/sqlite, camlistore.org/third_party/github.com/mattn/go-sqlite3
mongo found at camlistore.org/pkg/sorted/mongo, camlistore.org/pkg/blobserver/mongo
...

To resolve this you can just copy duplicate packages into unique folders with vend cp and then run vend init again to copy over the rest of the packages.

Updating Packages

To update a package, first update it in the GOPATH with :

go get -u github.com/lib/pq

Then overwrite the package in your vend directory :

vend cp -f github.com/lib/pq lib/pq

From then on, you can think of your GOPATH as a collection of the latest versions of any given package.

As is often the case, the simplest solution is best. So give it a try and vend your own Go packages.

--

--