with Nix and home-manager
dustin.lacewell@workiva.com
Workstation Environments?
Ideal Properties
Nix
...a powerful package manager for Linux and other Unix systems that makes package management reliable and reproducible.
It provides atomic upgrades and rollbacks, side-by-side installation of multiple versions of a package, multi-user package management and easy setup of build environments.
"The Purely Functional Package Manager"
Nixlang
Nix
NixOS
NixOps
Disnix
Hydra
Purity
Atomicity
Laziness
Reproducibility
HM
Nix is a package manager
Nixpkgs
Around 6500 packages for Linux and OSX
"On GNU/Linux, the packages in Nixpkgs are ‘pure’, meaning that they have no dependencies on packages outside of the Nix store. This means that they should work on pretty much any GNU/Linux distribution."
#> nix-channel --add https://nixos.org/channels/nixpkgs-unstable
#> nix-env -qa 'firefox.*'
#> nix-channel --update
#> nix-env -i firefox
#> nix-env -e firefox
stdenv.mkDerivation rec {
name = "hello-2.10";
src = fetchurl {
url = "https://ftp.gnu.org/gnu/hello/hello-2.10.tar.gz";
sha256 = "1im1gglfm4k10bh4mdaqzmx3lm3kivnsmxrvl6vyvmfqqzljq75l";
};
meta = {
description = "A program that produces a familiar, friendly greeting";
platforms = stdenv.lib.platforms.all;
};
}
Package Purity
Nixlang's purity -> Nix's reproducibility
/nix/store/r8vvq9kq18pz08v249h8my6r9vs7s0n3-firefox-8.0.1
/nix/store/y15i77ghwd0w0xcw8hl2cl1gs4fi9dj5-firefox-8.0.1
Text
#> nix-env --upgrade firefox #> nix-env --rollback
Nix is a language
It has basic data types
Every file is an expression
# example.nix
{
foo = "bar";
biz = [ 1 "two" 3 ];
}
let expressions are nice
# let <names> in <expr>
let
filename = "config.conf";
prefix = "/etc/foo";
path = "${prefix}/${filename}"
{
file = touchFile path;
}
Functions
# { <args> }: <expr>
let
func = { prefix, filename ? "foo.conf" }: {
fullPath = "${prefix}/${filename}";
ready = false;
};
in func { prefix = "/etc/foo"; }
Files can be imported
# prefix.nix
{ filename, prefix ? "/etc/foo" }:
"${prefix}/${filename}"
# foo.nix
let
prefix = import ./prefix.nix;
in {
fooFile = prefix { filename = "foo.conf"; };
}
# {fooFile="/etc/foo/foo.conf";}
Anatomy of a Package
with import <nixpkgs> {};
stdenv.mkDerivation {
name = "hello-2.1.1";
src = fetchurl {
url = http://nix.cs.uu.nl/dist/tarballs/hello-2.1.1.tar.gz;
md5 = "70c9ccf9fac07f762c24f2df2290784d";
};
buildInputs = [ tar ];
builder = builtins.toFile "builder.sh" "
source $stdenv/setup
tar xvfz $src
cd hello-*
./configure --prefix=$out
make
make install
";
}
with import <nixpkgs> {};
stdenv.mkDerivation {
name = "hello-2.1.1";
src = fetchurl {
url = http://nix.cs.uu.nl/dist/tarballs/hello-2.1.1.tar.gz;
md5 = "70c9ccf9fac07f762c24f2df2290784d";
};
}
stdenv.mkDerivation {
name = "foo-5.4";
buildPhases = [ "buildPhase"
"installPhase" ];
buildPhase = ''
gcc foo.c -o foo
'';
installPhase = ''
mkdir -p $out/bin
cp foo $out/bin
'';
}
Packaging Harbour-CLI
Use a profile?
#> nix-env --switch-profile /nix/var/nix/profiles/harbour-cli
#> nix-env -i go glide git emacs
#> emacs main.go
#> go build, etc
# default.nix
with import <nixpkgs> {};
stdenv.mkDerivation {
name = "harbour-cli";
src = ./.;
buildInputs = [ git go glide ];
}
nix-shell
#> nix-shell
#> which go
/nix/store/2r298x93l2v48yrjp31381vcghyrnlz3-go-1.9.2/bin/go
#> emacs main.go
#> glide install && go build, etc
# default.nix
with import <nixpkgs> {};
stdenv.mkDerivation {
name = "harbour-cli";
src = ./.;
buildInputs = [ git go glide ];
buildPhases = [ "unpackPhase" "buildPhase" ];
builderPhase = ''
glide install
go test --cover
go build -o $out/bin/harbour-cli
'';
}
Installing the package
#> nix-env -i -f .
#> which harbour-cli
/Users/dustinlacewell/.nix-profile/bin/harbour-cli
#> nix-env -i \
https://github.com/Workiva/harbour-cli/archive/master.tar.gz
NixOS
nix-rebuild
Configuration.nix
Syntax Sugar
Repetition Blues
Set Extension
Functions
Higher-order Functions
Modularity
Functions
Configuration Modules