--- title: Nix Tips toc: true --- Just a random collection of things to reference about [nix](https://nixos.org/nix/). # Minimal nix derivation ```nix with import {}; stdenv.mkDerivation { name = "env"; buildInputs = [ bashInteractive ]; } ``` This is useful for writing a quick and dirty, non-language specific `default.nix` as a starting point to potentially packaging something. If you need some tooling for a project, drop the tools in `buildInputs`, then when you `nix-shell`, you'll have them available. Like: ```nix with import {}; stdenv.mkDerivation { name = "env"; buildInputs = [ awscli python36 nodejs-8_x ]; } ``` # mkShell If you only want a shell environment, you can use `mkShell` in a `shell.nix`, which is slightly shorter: ```nix with import {}; mkShell { buildInputs = [ awscli python36 nodejs-8_x ]; } ``` And also supports the `inputsFrom` parameter, if you want to pull build inputs from other packages ```nix { pkgs ? import {} }: pkgs.mkShell { # this will make all the build inputs from hello and gnutar # available to the shell environment inputsFrom = with pkgs; [ hello gnutar ]; buildInputs = [ pkgs.gnumake ]; } ``` # Pin nixpkgs You'll likely want to do this for any non-trivial project, as it insulates the project from any changes (or breakages) from the global nixpkgs and ensures the same version of nixpkgs for the project is used by every one. ## niv You should probably just use niv to do this. See the [bootstrapping section](https://github.com/nmattia/niv#bootstrapping-a-nix-project) to start. ## nix >= 2.0 If you don't want to use niv and you only need to support nix > 2.0, you can use `builtins.fetchTarball`^[The builtin function supports the a `sha256` param on the function, so it doesn't have to constantly refetch the tarball to check for updates.]. If you need to support < 2.0 nix versions (or a mix), see the next section. ```nix { rev ? "92f0d31b949bcf018262252408b8a69376a6cb68" , sha256 ? "08ir579xsh7414i9y7jaislr2d56q716ayv2jlrrbpsx38gly453" }: let nixpkgsPath = builtins.fetchTarball { url = "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz"; inherit sha256; }; pkgs = import nixpkgsPath { config = { # do whatever you want # packageOverrides = oldPkgs: let newPkgs = oldPkgs.pkgs; in {...} }; }; in # do stuff with pkgs ``` You could also make nixpkgs a parameter and import the source inline, which is more compact. ```nix { rev ? "92f0d31b949bcf018262252408b8a69376a6cb68" , sha256 ? "08ir579xsh7414i9y7jaislr2d56q716ayv2jlrrbpsx38gly453" , nixpkgs ? import (builtins.fetchTarball { url = "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz"; inherit sha256; }) { config = {} } }: # do stuff with nixpkgs ``` ## nix < 2.0 For pre-2.0 nix support, you could use [this fetch-nixpkgs helper][fetch-nixpkgs] or use `fetchFromGitHub`. [fetch-nixpkgs]: https://nixos.wiki/wiki/How_to_fetch_Nixpkgs_with_an_empty_NIX_PATH or With `fetchFromGitHub`: ```nix { hostPkgs ? import {} , rev ? "92f0d31b949bcf018262252408b8a69376a6cb68" , sha256 ? "08ir579xsh7414i9y7jaislr2d56q716ayv2jlrrbpsx38gly453" , nixpkgs ? import (hostPkgs.fetchFromGitHub { owner = "NixOS"; repo = "nixpkgs"; inherit rev sha256; }) { config = {} } }: # do stuff with nixpkgs ``` ## In environment You can also set `NIX_PATH` to a location to use for ``, which if set in some file sourced by the project (say a `.env` or `.envrc`), pins the version. Either a specific commit: ```bash export NIX_PATH=nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/628ba24e77b2c6f82f4c2d9e8a31d93fa06f2743.tar.gz:. ``` Or a channel: ```bash export NIX_PATH=nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-19.03-small.tar.gz:. ``` # nix-shell as an interpreter The nix manual has a [nice section on this](https://nixos.org/nix/manual/#use-as-a-interpreter). Older, but longer [tutorial on this](http://iam.travishartwell.net/2015/06/17/nix-shell-shebang/). Package script dependencies: ```bash #! /usr/bin/env nix-shell #! nix-shell -i bash -p opusTools -p graphicsmagick -p file -p parallel -p flac # do script things as normal ``` Run Haskell as a script: ```bash #! /usr/bin/env nix-shell #! nix-shell -i runghc -p "haskellPackages.ghcWithPackages (ps: with ps; [])" main :: IO () main = putStrLn "Hello World!" ``` Pairs well with something like [turtle](https://hackage.haskell.org/package/turtle). # nix + direnv Just have a `default.nix` or `shell.nix` setup for you project. And an `.envrc` containing: ```{.bash} use nix ``` After a `direnv allow` in the directory, every time you move into the directory you'll have a `nix-shell` environment setup for you automatically, in your own familiar shell. Combine this with an editor plugin for `direnv` and as you move around in your editor, your project dependencies will be setup for you automatically. Very convenient. The upstream nix function in direnv is pretty simple. You'll probably want to use a modified one to speed up direnv, particularly if you have it integrated with you editor. See the [section on a persistent and cached shell](https://github.com/direnv/direnv/wiki/Nix#persistent-shell-for-speeding-things-up) for nix with direnv. # Haskell The Haskell infrastructure in nix is extensive, the [section in the manual](https://nixos.org/nixpkgs/manual/#users-guide-to-the-haskell-infrastructure) is a useful read. ## Basic dev environment Probably the quickest way to get going developing a Haskell package is with [haskellPackges.developPackage](https://github.com/NixOS/nixpkgs/blob/f3282c8d1e0ce6ba5d9f6aeddcfad51d879c7a4a/pkgs/development/haskell-modules/make-package-set.nix#L215): Have a cabal file for your project, then your `default.nix` can just be: ```nix { pkgs ? import {} }: pkgs.haskellPackages.developPackage { root = ./.; } ``` This automatically calls `cabal2nix`, makes it easy to specify overrides and such. If you want to fix a compiler version, say the default is too new for you: ```nix { pkgs ? import {} , ghcVersion ? "ghc842" }: pkgs.haskell.packages."${ghcVersion}".developPackage { root = ./.; } ``` There's a little more on this in [the manual](https://nixos.org/nixpkgs/manual/#how-to-specify-source-overrides-for-your-haskell-package), particularly for when you need to override a dependencies packaged version. # Nix: Under the hood Good talk covering the basics of how nix works, simply. # Test your NixOS config https://twitter.com/IotaSamurai/status/1045220406792048640 ``` nix repl '' ``` You can poke at your config without having to `nixos-rebuild`. # LaTeX Arbitrary, one-off environments: `nix-shell -E 'with import {}; mkShell { buildInputs = [(texlive.combine { inherit (pkgs.texlive) scheme-small standalone latexmk cm-super; })]; }'`