Nix
Nix is not a configuration management tool alike Puppet
or Chef
.
It is more accurately described as a (universal) package manager or build tool.
Nix operates within its store (usually located in '/nix') to gather packages called derivations
.
In that regard, unless you are running nixos
, nix won’t configure systemd services for instance.
Nix aims to offer:
-
best possible build reproducibility
-
self-contained environments
-
easy rollback
-
composability
Tips and tricks
- Overlays
-
You can override derivation attributes in user space without forking the nixpkgs repository by using one or multiple overlays:
~/.config/nixpgks/overlays/default.nixself: super: let hlib = super.haskell.lib; in { haskellPackages = super.haskellPackages.override { overrides = curr: prev: { cicd-shell = hlib.dontCheck (hlib.dontHaddock (curr.callCabal2nix "cicd-shell" (super.fetchgit { (1) url = "http://stash.cirb.lan/scm/cicd/cicd-shell.git"; rev = "d76c532d69e4d01bdaf2c716533d9557371c28ea"; sha256 = "0yval6k6rliw1q79ikj6xxnfz17wdlnjz1428qbv8yfl8692p13h"; }) { protolude = prev.protolude_0_2; } )); }; }; }
1 callCabal2nix
allows to automatically fetch and build any haskell package from the web - Pinned a version of nixpkgs
-
let nixpkgs = builtins.fromJSON (builtins.readFile ./.nixpkgs.json); in import (fetchTarball { url = "https://github.com/NixOS/nixpkgs/archive/${nixpkgs.rev}.tar.gz"; inherit (nixpkgs) sha256; })
Updating
.nixpkgs.json
is realized with such a zsh function:function updateNixpkgs () { nix-prefetch-git https://github.com/NixOS/nixpkgs.git "$1" > ~/.config/nixpkgs/.nixpkgs.json }
It is easier to manage pinned/sha using niv.
- Private packages
-
You can also extend
nixpkgs
with private derivations without any forking. For instance using a custom file:dotfiles.nixwith import <nixpkgs> {}; (1) let xmonadEnv = haskellPackages.ghcWithPackages (p: with p; [xmonad xmonad-contrib]); (2) in stdenv.mkDerivation { name = "devbox_dotfiles-0.1"; src = fetchFromGitHub { owner = "CIRB"; repo = "devbox-dotfiles"; rev = "801f66f3c7d657f5648963c60e89743d85133b1a" ; sha256 = "1w4vaqp21dmdd1m5akmzq4c3alabyn0mp94s6lqzzp1qpla0sdx0" ; }; buildInputs = [ xmonadEnv ]; installPhase = '' ${xmonadEnv}/bin/ghc --make .xmonad/xmonad.hs -o .xmonad/xmonad-x86_64-linux (3) cp -R ./. $out (4) ''; meta = { description = "Dot files for the devbox"; }; }
1 dependencies provided by nixpkgs
using $NIX_PATH2 ghc with module deps included 3 at this stage, the shell is inside a temp dir with the src included 4 copy the content of the current dir into $out You then build the derivation or install it in the user environment.
→ nix-build dotfiles.nix → nix-env -f dotfiles.nix -i devbox_dotfiles (1)
1 nix-env -i
takes the name attribute and strip the version (first numeric after-
) - Overrides haskell packages for the
ghc821
compiler -
self: super: let hlib = super.haskell.lib; in { haskell = super.haskell // { packages = super.haskell.packages // { ghc821 = super.haskell.packages.ghc821.override { (1) overrides = hpkgs: _hpkgs: { containers = hlib.dontCheck(_hpkgs.containers); }; };};}; }
1 haskell
equalssuper.haskell
except packages, which equalssuper.haskell.packages
except forghc821
, which is the overriden version ofsuper 821
- Caching the list of all available package into a local file
-
nix-env -qaP --description '*' > ~/allpkgs.desc
- Reproduce any hydra build locally
-
bash <(curl https://hydra.nixos.org/build/57055021/reproduce)
- Installed nixpkgs version
-
nix-instantiate --eval -E '(import <nixpkgs> {}).lib.version'
- Refering to an attribute that contains dot (e.g:
foo-1.2.0
) -
You will need to escape the
.
:
nix-build -A '"foo-1.2.0"'
- Convert an attribute set into a string representation
-
Attribute set are not automatically converted into string. That said, you can provide an implementation by using the outPath field:
builtins.fromJSON fromCUE // { outPath = fromCUE; }
Pitfall
When you create a derivation, a path value will auto-magically be interpolated with its generated outpath:
pkgs.runCommand "hello" { buildInputs = []; } ''
cp ${./talk.adoc} $out (1)
''
1 | path → /nix/store/xxxx |
The tricky part arises when you want to use a string variable to describe this path. To force the coersing from string → path you need to use +:
let
cueSchema = "${config.home.homeDirectory}/bootstrap/user/schema.cue";
cueConfig = "${sharedDir}/box.cue";
in
pkgs.runCommand "fromCue" { } ''
${pkgs.cue}/bin/cue export ${/. + cueSchema } ${/. + cueConfig} > $out;
''