aez-notes

Home

nix-logo.png

Table of Contents

Further reading

Blog posts I want to read

Documentation

Books

Nix as a language

There is a repl which you can start with nix repl to play around with expressions to see if they behave as expected.

Examples

Uninstalling packages

There are notes on how to uninstall a package here. Bear in mind that after you uninstall a package the files are not deleted, you need to garbage collect to actually remove the files.

nix-env --uninstall firefox
nix-collect-garbage

Jupyter Lab

The following shell.nix provides a shell which has jupyter lab with several useful kernels. It uses the functionality developed by Tweag. To start the server run the following command:

nix-shell --command "jupyter lab"
# shell.nix
let
  jupyter = import (builtins.fetchGit {
    url = https://github.com/tweag/jupyterWith;
    rev = "";
  }) {};

  irkernel = jupyter.kernels.iRWith {
    name = "r";
    packages = p: with p; [ p.ggplot2 ];
  };

  ipython = jupyter.kernels.iPythonWith {
    name = "python";
    packages = p: with p; [ numpy
                            altair
                            statsmodels
                            pandas
                            matplotlib ];
  };

  jupyterEnvironment = jupyter.jupyterlabWith {
    kernels = [ ipython
                irkernel ];
  };
in
  jupyterEnvironment.env
  • There is no rev specified when fetching from git so this is not very reproducible. If you want to make this safer you can add the commit hash there.
  • The irkernel provides an R kernel with ggplot installed.

DOOM

Much of the value of Nix comes from being about to try out a package without needing to properly install it on your system. For example, suppose you want to play DOOM. Looking on search.nixos.org we find that there is crispy-doom, so just run

nix-shell -p crispyDoom

and you are now in a shell that has doom installed! Looking at the help for this program you find it needs a WAD file such as freedoom1.wad which is easy to find only, and then within ten minutes you've got doom running and when you exit the shell it will be gone.

A reproducible R environment

The following provides a shell with a pinned version of R and the packages dplyr and ggplot2, other packages can be found at search.nixos.org. A specific version of the package archive is used here, but if you are starting a fresh project it is probably better to pick an uptodate one at the time. When choosing a commit, see the listed versions status.nixos.org.

# shell.nix
let
  commitHash = "78dc359abf8217da2499a6da0fcf624b139d7ac3";
  tarballUrl = "https://github.com/NixOS/nixpkgs/archive/${commitHash}.tar.gz";
  pkgs = import (fetchTarball tarballUrl) {};
  stdenv = pkgs.stdenv;
in with pkgs; {
  myProject = stdenv.mkDerivation {
    name = "example-r-env";
    version = "1";
    src = if pkgs.lib.inNixShell then null else nix;

    buildInputs = with rPackages; [
      R
      dplyr
      purrr
      magrittr
      ggplot2
    ];
   shellHook = ''
             printf "\n\nWelcome to a reproducible R shell :)\n\n"
      '';
  };
}

Testing fonts work

I have had some trouble getting fonts to work properly with nix, if the following produces sensible output then you are probably in the clear.

png("foo.png"); plot(1:10); dev.off()

The missing fonts appear to be an issue with R-3.6.2 but not with R-4.0.2, so it might just be that I was using an older version when I hit the missing font problem. Recall that you can see the latest commits at status.nixos.org.

Using this with ESS

If you want to use ESS with nix, you'll need to let it know that you want to use the R that comes with the nix shell. To do this open a shell with M-x shell and activate the nix shell, then start an R session within that shell. Once you have a running R session, go to your R buffer and run M-x ess-remote and select the R dialect.

Problems with stringi

If you have problem with a missing shared object for stringi, re-installing the package along with the dependencies using the source from Rstudio seems to fix it

install.packages("stringi", repos="http://cran.rstudio.com/", dependencies=TRUE)

A reproducible python environment

The following example is taken from this blog post on how to set up a development environment for python. Specifically, it demonstrates how to build a python environment which includes a package on PyPi but not provided among the existing nix packages.

{ pkgs ? import (fetchTarball https://github.com/nixos/nixpkgs/archive/nixos-20.03.tar.gz) {} }:

let
  grpclib = pkgs.python37Packages.buildPythonPackage rec {
    pname = "grpclib";
    version = "0.3.1";

    src = pkgs.python37Packages.fetchPypi {
      inherit pname version;
      sha256 = "0dw7jzw3pf2ckzrl808ayqvk9yqjhc45rj8qhmdxifv4ynwnyjam";
    };

    propagatedBuildInputs = with pkgs.python37Packages; [ h2 multidict ];

    doCheck = false;
  };

  customPython = pkgs.python37.buildEnv.override {
    extraLibs = [ grpclib ];
  };
in

pkgs.mkShell {
  buildInputs = [ customPython ];
}

Where did the sha256 come from? Well if you don't have this, then when you attempt to start the shell it will error out. The output will list a URL. Running the following command with that URL will give the correct hash to include there.

$ nix-prefetch-url mirror://pypi/g/grpclib/grpclib-0.3.1.tar.gz

At the time of writing I'm not entirely sure how the h2 and multidict dependencies where known about. If you don't include these, then the shell will not build and there are error messages explaining which packages are missing so it's not too bad.

Haskell development

The shell.nix file below provides a shell suitable for working with Haskell. If the commit hash is too old, you can find a new one among the listed versions status.nixos.org. To activate the shell use nix-shell.

  • cabal gen-bounds to find the bounds on your dependencies
  • cabal-fmt --inplace myProject.cabal to format the cabal file.
let
  commitHash = "50b5738d6974785514c07b5b87f91641ca3f802d";
  tarballUrl = "https://github.com/NixOS/nixpkgs/archive/${commitHash}.tar.gz";
  pkgs = import (fetchTarball tarballUrl) {};
  stdenv = pkgs.stdenv;
in with pkgs; {
  myProject = stdenv.mkDerivation {
    name = "example-haskell-env";
    version = "1";
    src = if pkgs.lib.inNixShell then null else nix;

    buildInputs = with haskellPackages; [
      ghc
      Cabal_3_2_0_0
      cabal-fmt
    ];
   shellHook = ''
             printf "\n\nWelcome to the Haskell shell :)\n\n"
      '';
  };
}

Dhall

let
  commitHash = "dc326c78a93862efb30a76216f527a56496e6284";
  tarballUrl = "https://github.com/NixOS/nixpkgs/archive/${commitHash}.tar.gz";
  pkgs = import (fetchTarball tarballUrl) {};
  stdenv = pkgs.stdenv;
in with pkgs; {
  myProject = stdenv.mkDerivation {
    name = "example-dhall-env";
    version = "1";
    src = if pkgs.lib.inNixShell then null else nix;

    buildInputs = [
      dhall
      dhall-json
    ];
   shellHook = ''
             printf "\n\nWelcome to the dhall shell :)\n\n"
      '';
  };
}

Rough notes

The following script when run will drop you into an R session which in this case uses R version 4.0.2 but by changing the commit you can get into several other versions of R

#! /usr/bin/env nix-shell
#! nix-shell --pure -i R -p R
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/14cf906f33c39d38741062df2cca0b0575b210ff.tar.gz

Try replacing the commit with these values and see what version of R you find.

14cf906f33c39d38741062df2cca0b0575b210ff
75f4ba05c63be3f147bcc2f7bd4ba1f029cedcb1
f05c380a51daee53ac2edb0bac2fd5f1774e977a
  • The --pure flag means that a shell will not inherit the bash environment which makes things far more reproducible, at the cost of not having all of the stuff you usually use. The -I flag is used to pin the nixpkgs revision so that you get the same package versions each time.
  • Use nix-shell to create a shell with the specified packages available (and at the front of the path).
  • All Haskell related material is stored in packages prefixed with the name haskellPackage.. For example, ghc is haskellPackage.ghc.
  • Adding the following to your stack.yaml appears to enable development within the specified nix-shell.
nix:
  enable: true
  shell-file: shell.nix
{ghc}:
with (import <nixpkgs> {});

haskell.lib.buildStackProject {
  inherit ghc;
  name = "myEnv";
  buildInputs = [ glpk pcre ];
}

Author: Alex Zarebski

Created: 2021-12-13 Mon 16:18

Validate