go2nix
go2nix copied to clipboard
Reproducible builds and development environment for Go
go2nix - nix packages for Go applications
go2nix is best suited for Go apps written before dep or modules were introduced.
- If you see a
Gopkgs.lockfile in the source try dep2nix instead. - If you see a
go.modfile in the source try vgo2nix or gomod2nix instead.
For Nixers - packaging Go applications
Concept
go2nix provides an autmatic way to create Nix derivations for Go applications.
- Start with app sources that can be built on your machine with
go build. It means that you need to get all dependencies into currentGOPATH. - Run
go2nix savein application source dir wheremainpackage lives. This will create 2 filesdefault.nixanddeps.nixthat can be moved into its own directory undernixpkgs.
Example
If you are not sure how to organize your directory structure, read this official guide first.
Our project will be called influxdb-demo and this demo will be using the influxdb client library.
-
But first, prepare the project directory:
mkdir example cd example mkdir bin pkg src -
Change into a
shellenvironment which contains GO and GIT:nix-shell -p go git go2nixNote: Make sure
go2nixis at least version 1.1.1 -
Then set the
GOPATH:export GOPATH=`pwd` mkdir -p src/github.com/qknight/influxdb-demo -
Prepare
src/github.com/qknight/influxdb-demo/influxdb-client.go:package main import ( "log" "time" "github.com/influxdata/influxdb/client/v2" ) const ( MyDB = "square_holes" username = "bubba" password = "bumblebeetuna" ) func main() { // Make client c, err := client.NewHTTPClient(client.HTTPConfig{ Addr: "http://localhost:8086", Username: username, Password: password, }) if err != nil { log.Fatalln("Error: ", err) } // Create a new point batch bp, err := client.NewBatchPoints(client.BatchPointsConfig{ Database: MyDB, Precision: "s", }) if err != nil { log.Fatalln("Error: ", err) } // Create a point and add to batch tags := map[string]string{"cpu": "cpu-total"} fields := map[string]interface{}{ "idle": 10.1, "system": 53.3, "user": 46.6, } pt, err := client.NewPoint("cpu_usage", tags, fields, time.Now()) if err != nil { log.Fatalln("Error: ", err) } bp.AddPoint(pt) // Write the batch c.Write(bp) }Note: We use go influxdb client as an external library example.
-
Create a
GITrepositorycd src/github.com/qknight/influxdb-demo git init git add influxdb-client.go git commit -m 'initial commit'Also create the repository on github.com, in this example it would be
github.com/qknight/influxdb-demogit remote add origin [email protected]:qknight/influxdb-demo.git git push -u origin masterNote:
go2nixrequires aGIT repositoryto retrieve thecommit hashand theremoteso it can generate the values asname,version,revandgoPackagePathin thedefault.nixfile. -
Download the dependency the go-way
go getNote:
go getwill populatesrc/github.com/influxdata/influxdbfor you. -
Building the project
go build -
Generate
default.nix/deps.nixIf
gowas able to build the binary, usego2nixto derive thedefault.nixanddeps.nix:go2nix saveNote: This gives you a
default.nixand adeps.nixwhich can be put intonixpkgsbut, if you want to use it withnix-shell, you need some tiny adaptions. -
The
default.nixfile we generated# This file was generated by go2nix. { stdenv, buildGoPackage, fetchgit, fetchhg, fetchbzr, fetchsvn }: buildGoPackage rec { name = "influxdb-demo-${version}"; version = "20161030-${stdenv.lib.strings.substring 0 7 rev}"; rev = "718c85cd733bca964abf03f5371c939d19845f72"; goPackagePath = "github.com/qknight/influxdb-demo"; src = fetchgit { inherit rev; url = "[email protected]:qknight/influxdb-demo.git"; sha256 = "0csbqcnncklimysgcbxlj190bynx1ppvyxvl5viz40fvbcj4l8xb"; }; goDeps = ./deps.nix; # TODO: add metadata https://nixos.org/nixpkgs/manual/#sec-standard-meta-attributes meta = { }; }Note: Update the
fetchgit urlto usehttpsinstead ofsshornix-buildwon't be able to fetch the software later.Note: If you want to use this
default.nixinnixpkgsyou should extend the meta section and correct thegoPackagePath. -
The
deps.nixwe generated# This file was generated by go2nix. [ { goPackagePath = "github.com/influxdata/influxdb"; fetch = { type = "git"; url = "https://github.com/influxdata/influxdb"; rev = "bcb48a8ff2e9c118d5cfa04f03a62134b9c414c7"; sha256 = "1f4jp7p2xxlsxhqbvglcl95y7fhab0w6zsvyqmqglmi0g1c5v21z"; }; } ] -
Building the project using
nix-buildnix-build -E 'with import <nixpkgs> { }; callPackage ./default.nix {}'This will print something like this:
these derivations will be built: /nix/store/8naxqswyhsmhqhjzskz5q0nf33nvyzsf-influxdb-demo-718c85c.drv /nix/store/p9bgjqn683xkmns36fpw2ipz5k57srl3-influxdb-bcb48a8.drv /nix/store/k0q9k2wfq0ccdsy04pyg4l01iqh5j1aa-go1.7-influxdb-demo-20161030-718c85c.drv building path(s) ‘/nix/store/45jjx5jakvlgwzq358pivr5x8xpgdsck-influxdb-bcb48a8’ building path(s) ‘/nix/store/pqlqq2wjgixvf5j6qmrv5qyjh1bc6i8q-influxdb-demo-718c85c’ exporting https://github.com/influxdata/influxdb (rev bcb48a8ff2e9c118d5cfa04f03a62134b9c414c7) into /nix/store/45jjx5jakvlgwzq358pivr5x8xpgdsck-influxdb-bcb48a8 exporting https://github.com/qknight/influxdb-demo.git (rev 718c85cd733bca964abf03f5371c939d19845f72) into /nix/store/pqlqq2wjgixvf5j6qmrv5qyjh1bc6i8q-influxdb-demo-718c85c Initialized empty Git repository in /nix/store/45jjx5jakvlgwzq358pivr5x8xpgdsck-influxdb-bcb48a8/.git/ Initialized empty Git repository in /nix/store/pqlqq2wjgixvf5j6qmrv5qyjh1bc6i8q-influxdb-demo-718c85c/.git/ remote: Counting objects: 3, done. remote: Compressing objects: 100% (2/2), done. remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0 From https://github.com/qknight/influxdb-demo * branch HEAD -> FETCH_HEAD Switched to a new branch 'fetchgit' removing `.git'... remote: Counting objects: 540, done. remote: Compressing objects: 100% (506/506), done. remote: Total 540 (delta 34), reused 179 (delta 6), pack-reused 0 Receiving objects: 100% (540/540), 1.44 MiB | 0 bytes/s, done. Resolving deltas: 100% (34/34), done. From https://github.com/influxdata/influxdb * branch HEAD -> FETCH_HEAD Switched to a new branch 'fetchgit' removing `.git'... building path(s) ‘/nix/store/9k4v7rhs5606fyia8mb341k71m3yrcbq-go1.7-influxdb-demo-20161030-718c85c-bin’, ‘/nix/store/av17zlfgnppl704wwxnh5pjpkcxac9k3-go1.7-influxdb-demo-20161030-718c85c’ unpacking sources unpacking source archive /nix/store/pqlqq2wjgixvf5j6qmrv5qyjh1bc6i8q-influxdb-demo-718c85c source root is influxdb-demo-718c85c patching sources configuring grep: Invalid range end unpacking source archive /nix/store/45jjx5jakvlgwzq358pivr5x8xpgdsck-influxdb-bcb48a8 building github.com/influxdata/influxdb/pkg/escape github.com/influxdata/influxdb/models github.com/influxdata/influxdb/client/v2 github.com/qknight/influxdb-demo installing /tmp/nix-build-go1.7-influxdb-demo-20161030-718c85c.drv-0/go /tmp/nix-build-go1.7-influxdb-demo-20161030-718c85c.drv-0 /tmp/nix-build-go1.7-influxdb-demo-20161030-718c85c.drv-0 post-installation fixup shrinking RPATHs of ELF executables and libraries in /nix/store/9k4v7rhs5606fyia8mb341k71m3yrcbq-go1.7-influxdb-demo-20161030-718c85c-bin shrinking /nix/store/9k4v7rhs5606fyia8mb341k71m3yrcbq-go1.7-influxdb-demo-20161030-718c85c-bin/bin/influxdb-demo stripping (with flags -S) in /nix/store/9k4v7rhs5606fyia8mb341k71m3yrcbq-go1.7-influxdb-demo-20161030-718c85c-bin/bin patching script interpreter paths in /nix/store/9k4v7rhs5606fyia8mb341k71m3yrcbq-go1.7-influxdb-demo-20161030-718c85c-bin shrinking RPATHs of ELF executables and libraries in /nix/store/av17zlfgnppl704wwxnh5pjpkcxac9k3-go1.7-influxdb-demo-20161030-718c85c patching script interpreter paths in /nix/store/av17zlfgnppl704wwxnh5pjpkcxac9k3-go1.7-influxdb-demo-20161030-718c85c /nix/store/9k4v7rhs5606fyia8mb341k71m3yrcbq-go1.7-influxdb-demo-20161030-718c85c-binNote: The resulting binary will be in
/nix/store/9k4v7rhs5606fyia8mb341k71m3yrcbq-go1.7-influxdb-demo-20161030-718c85c-bin. -
Enabling
nix-shellIn order to use
nix-shellyou need to create ashell.nixfile:let pkgs = import <nixpkgs> {}; in pkgs.callPackage ./default.nix {}That will pass the derivations for
stdenv, buildGoPackage, fetchgit, fetchhg, fetchbzr, fetchsvninto your package derivation. It will usenixpkgs(your current channel).After you updated the
default.nixyou can now usenix-shell:nix-shell these paths will be fetched (47.89 MiB download, 248.86 MiB unpacked): /nix/store/28wl3f34vfjpw0y5809bgr6382wqdscf-bash-4.3-p48 /nix/store/7bdn99q835l042d8kcrn7yk61zkcqw6y-go1.7-govers-20150109-3b5f175 /nix/store/aql31436x2fgr3rdj4fwbrgkvzw2kqf4-iana-etc-2.30 /nix/store/bb2njjq32bh1wl2nl1zss0i8w1w2jgrz-tzdata-2016f /nix/store/dp2nf60lqzy1kbhd78ndf5nm3fb3qicd-gcc-wrapper-5.4.0 /nix/store/drfmgb3kd3clxzi919mjrq5cnkw575w0-stdenv /nix/store/fkzyjrmrxv1zgswdq327h11ifbxdfpf9-go1.7-govers-20150109-3b5f175-bin /nix/store/g1pacy3pmx9r846z87xysfs29jz2b42q-parallel-20160722 /nix/store/g4f1bms36hgg5abfd8xc4bj6sfzsy61d-bash-4.3-p48-info /nix/store/i76bwv541a7zj576hkdia62169r2nl0z-bash-4.3-p48-doc /nix/store/jqa9bh404crcxnyxa2lkffag7kw3yxw3-go-1.7.1 /nix/store/jx5fyfd6mkpib1dmgy5rjirxff5vaczm-procps-3.3.11 /nix/store/kx62kzlxcmzxgnxz1c95x7gln72iqd90-ncurses-6.0 /nix/store/njn6il2fwaycjkd0jxbfj22gb25nd5df-perl-5.22.2 fetching path ‘/nix/store/i76bwv541a7zj576hkdia62169r2nl0z-bash-4.3-p48-doc’... fetching path ‘/nix/store/g4f1bms36hgg5abfd8xc4bj6sfzsy61d-bash-4.3-p48-info’... fetching path ‘/nix/store/aql31436x2fgr3rdj4fwbrgkvzw2kqf4-iana-etc-2.30’... fetching path ‘/nix/store/bb2njjq32bh1wl2nl1zss0i8w1w2jgrz-tzdata-2016f’... ...After the dependencies were built you can now use:
go buildto build your software as usual!Note: You can also arrange a
default.nixso that it can be used bynixpkgsandnix-shellbut this is not covered here.
Example Leaps
Some projects are built using go get github.com/jeffail/leaps/cmd/... and for these you need to identify the src directory to run go2nix save from. So here is another example:
nix-shell -p go2nix git gocd $(mktemp -d)export GOPATH=$(pwd)go get github.com/jeffail/leaps/cmd/...cd src/github.com/jeffail/leaps/cmd/leapsgo2nix save
Note: The resulting default.nix and deps.nix are created in the directory you are currently in.
Installation
The preferred way of installing go2nix is to use nix like nix-env -iA go2nix or using it declaratively.
But you can also use go get github.com/kamilchm/go2nix.