aez-notes
Table of Contents
Further reading
Blog posts
Blog posts I want to read
- Nix Workshop
- How to Learn Nix is a series looking at starting with Nix from the ground up.
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 dependenciescabal-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
- When choosing a commit, see the listed versions status.nixos.org.
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
ishaskellPackage.ghc
. - Adding the following to your
stack.yaml
appears to enable development within the specifiednix-shell
.
nix: enable: true shell-file: shell.nix
{ghc}: with (import <nixpkgs> {}); haskell.lib.buildStackProject { inherit ghc; name = "myEnv"; buildInputs = [ glpk pcre ]; }