Command Line Interface

nix-shell

When Nix builds a package, it builds it in an isolated environment. It does this by creating a clean, child shell, then adding only the dependencies the package declares. After setting up the dependencies, it runs the build script, moves the built app into the Nix store, and sets up the environment to point to it. Finally, it destroys this child shell.

But we can ask Nix to not destroy the child shell, and instead let us use it for working iteratively on the app. This is what the nix-shell is about: it will build the dependencies of the specified derivation, but not the derivation itself.

 nix-shell '<nixpkgs>' -p ruby haskellPackages.stack (1)
1 p and -A are mutually exclusive

If a path is not given, nix-shell defaults to shell.nix if it exists, and default.nix otherwise.[1]

This allows for a nice trick. We can decribe a virtual dev environment (of any sort for any language) by decribing a derivation in default.nix like so:

default.nix
with import <nixpkgs> {};

let henv = haskellPackages.ghcWithPackages (p: with p; [shake]);

in
stdenv.mkDerivation {
  name = "haskell-env";
  buildInputs = [ henv pythonPackages.pyyaml];
}

nix-shell will use the NIX_PATH environment variable which by default in user space points to the root nixpkgs channel. That means that (unlike nix-env), even if your channel points to unstable in user space, nix-shell might still use the root stable channel. You can change that behavior by running for instance:

nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-unstable.tar.gz

You can force any script file to run in a nix-shell as such:

#! /usr/bin/env nix-shell
#! nix-shell -i bash

or without a default.nix file:

#! /usr/bin/env nix-shell
#! nix-shell --pure
#! nix-shell -p asciidoctor -p pythonPackages.pygments
#! nix-shell -p "haskellPackages.ghcWithPackages(p: with p; [shake])" (1)
#! nix-shell -i bash
#! /usr/bin/env nix-shell
1 Double quotes are required. Don’t add -p ghc as you will end up with two different ghcs !

In Haskell, we need the --attr env to tell nix-shell to compute the isolated development environment:

shell.nix
with (import <nixpkgs> {}).pkgs;
(haskellPackages.callPackage ./. {}).env (1)
1 callPackage will use the current defined scope to pass matched arguments

default.nix is then generated by cabal2nix to describe how to nix-build the haskell package.

nix-build

nix-build tool does two main jobs:

  • nix-instantiate: parse the .nix file and return the .drv file (the evaluation step)

  • nix-store -r: realise the build product from the input .drv derivation

nix-pull is deprecated and replaced by the use of binary caches

nix-env

nix-env is the command to use to search, install, remove packages locally in user space (or profile). These packages are installed in the nix-store but are only accessible inside one environment (aka user/profile).

nix-env doesn’t require a starting nix expression. As a consequence, nix-env does not use <nixpkgs> as NIX_PATH. It actually uses ~/.nix-defexpr/channels.
If you want to use <nixpkgs>, you would explicitly use the -f (or --file) option on the command line.

  • -q list installed derivations within a profile

  • -qaP list available package with the path

When searching for packages, it is usually more efficient to specify a namespace attribute using the -A option.

# in nixos:
→ nix-env -qaP -A nixos.haskellPackages
→ nix-env -qaP -A nixos.pythonPackages
# outside nixos:
→ nix-env -qaP -A nixpkgs.pythonPackages

You can also omit the channel namespace and specify the input for nixpkgs explicitly with the -f option:

→ nix-env -f '<nixpkgs>' -qaP -A haskellPackages.shake --description
  • -i install derivations

    → nix-env -f '<nixpkgs>' -iA pythonPackages.pyyaml (1)
    → nix-env -f '<nixpkgs>' -i brackets -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/master.tar.gz’ (2)
    1 on nixos, you might use nix-env -iA nixos.pythonPackages.pyyaml
    2 install from master directly
  • -e erase

    → nix-env -e python2.7-PyYAML-3.11
  • -u update

    → nix-env -u

Niv

Niv is an handy tool to manage sources:

niv add cicd-shell -v '3.7.2' -t 'https://github.com/PierreR/cicd-shell/archive/v<version>.tar.gz'
niv update -v 3.7.3 cicd-shell

1. If no such files exists, it will default to <nixpkgs>