nix.mkd 6.96 KB
Newer Older
doshitan's avatar
doshitan committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
---
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 <nixpkgs> {};
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 <nixpkgs> {};
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 <nixpkgs> {};
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 <nixpkgs> {} }:
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 ];
}
```

<https://nixos.org/nixpkgs/manual/#sec-pkgs-mkShell>


# 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.

<https://github.com/nmattia/niv>

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 <nixpkgs> {}
, 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 `<nixpkgs>`, 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

<https://github.com/direnv/direnv/wiki/Nix>

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 <nixpkgs> {} }:

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 <nixpkgs> {}
, 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.

<https://youtu.be/GMQPzv3Sx58>


# Test your NixOS config

https://twitter.com/IotaSamurai/status/1045220406792048640

```
nix repl '<nixpkgs/nixos>'
```

You can poke at your config without having to `nixos-rebuild`.


# LaTeX

Arbitrary, one-off environments:
`nix-shell -E 'with import <nixpkgs> {}; mkShell { buildInputs = [(texlive.combine { inherit (pkgs.texlive) scheme-small standalone latexmk cm-super; })]; }'`