Merge pull request #386 from fricklerhandwerk/nix-language-tutorial

Nix language tutorial: add explanation on how `pkgs.lib` is obtained
This commit is contained in:
Valentin Gagarin 2022-11-18 17:15:15 +01:00 committed by GitHub
commit dd8e3f6aa3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1288,11 +1288,13 @@ We recommend to at least skim them to familiarise yourself with what is availabl
[operators]: https://nixos.org/manual/nix/stable/language/operators.html
(builtins)=
### `builtins`
Also known as “primitive operations” or “primops”.
Nix comes with many functions that are built into the language.
They are implemented in C++ as part of the Nix language interpreter.
:::{note}
The Nix manual lists all [Built-in Functions][nix-builtins], and shows how to use them.
@ -1308,9 +1310,6 @@ builtins.toString
<PRIMOP>
Some of them have equivalents in `pkgs.lib`.
But since most `builtins` are implemented in C++ as part of the Nix language interpreter, they usually execute faster.
[nix-operators]: https://nixos.org/manual/nix/unstable/language/operators.html
[nix-builtins]: https://nixos.org/manual/nix/stable/language/builtins.html
@ -1321,7 +1320,6 @@ A notable exception is `import`, which is also available at the top level.
`import` takes a path to a Nix file, reads it to evaluate the contained Nix expression, and returns the resulting value.
Example:
```console
@ -1394,22 +1392,118 @@ Parentheses are required to separate function declaration from function applicat
</details>
(pkgs-lib)=
### `pkgs.lib`
The [`nixpkgs`][nixpkgs] repository contains an attribute set called [`lib`][nixpkgs-lib], which provides a large number of useful functions.
They are implemented in the Nix language, as opposed to [`builtins`](builtins), which are part of the language itself.
:::{note}
The Nixpkgs manual lists all [Nixpkgs library functions][nixpkgs-functions].
:::
These functions are usually accessed through `pkgs.lib`.
[nixpkgs-functions]: https://nixos.org/manual/nixpkgs/stable/#sec-functions-library
[nixpkgs-lib]: https://github.com/NixOS/nixpkgs/blob/master/lib/default.nix
These functions are usually accessed through `pkgs.lib`, as the Nixpkgs attribute set is given the name `pkgs` by convention.
Example:
pkgs.lib.strings.toUpper
```nix
let
pkgs = import <nixpkgs> {};
in
pkgs.lib.strings.toUpper "search paths considered harmful"
```
[nixpkgs-functions]: https://nixos.org/manual/nixpkgs/stable/#sec-functions-library
[nixpkgs-lib]: https://github.com/NixOS/nixpkgs/blob/master/lib/default.nix
SEARCH PATHS CONSIDERED HARMFUL
<details><summary>Detailed explanation</summary>
This is a more complex example, but by now you should be familiar with all its components.
The name `pkgs` is declared to be the expression `import`ed from some file.
That file's path is determined by the value of the search path `<nixpkgs>`, which in turn is determined by the `$NIX_PATH` environment variable at the time this expression is evaluated.
As this expression happens to be a function, it requires an argument to evaluate, and in this case passing an empty attribute set `{}` is sufficient.
Now that `pkgs` is in scope of `let ... in ...`, its attributes can be accessed.
From the Nixpkgs manual one can determine that there exists a function under [`lib.strings.toUpper`].
[`lib.strings.toUpper`]: https://nixos.org/manual/nixpkgs/stable/#function-library-lib.strings.toUpper
For brevity, this example uses a search path to obtain *some version* of Nixpkgs.
The function `toUpper` is trivial enough that we can expect it not to produce different results for different versions of Nixpkgs.
Yet, more sophisticated software is likely to suffer from such problems.
A fully reproducible example would therefore look like this:
```nix
let
nixpkgs = fetchTarball https://github.com/NixOS/nixpkgs/archive/3590f02e7d5760e52072c1a729ee2250b5560746.tar.gz;
pkgs = import nixpkgs {};
in
pkgs.lib.strings.toUpper "always pin your sources"
```
ALWAYS PIN YOUR SOURCES
See [](pinning-nixpkgs) for details.
What you will also often see is that `pkgs` is passed as an argument to a function.
By convention one can assume that it refers to the Nixpkgs attribute set, which has a `lib` attribute:
```nix
{ pkgs, ... }:
pkgs.lib.strings.removePrefix "no " "no true scotsman"
```
<LAMBDA>
To make this function produce a result, you can write it to a file (e.g. `file.nix`) and pass it an argument through `nix-instantiate`:
```console
nix-instantiate --eval test.nix --arg pkgs 'import <nixpkgs> {}'
```
"true scotsman"
Oftentimes you will see in NixOS configurations, and also within Nixpkgs, that `lib` is passed directly.
In that case one can assume that this `lib` is equivalent to `pkgs.lib` where only `pkgs` is available.
Example:
```nix
{ lib, ... }:
let
to-be = true;
in
lib.trivial.or to-be (! to-be)
```
<LAMBDA>
To make this function produce a result, you can write it to a file (e.g. `file.nix`) and pass it an argument through `nix-instantiate`:
```console
nix-instantiate --eval file.nix --arg lib '(import <nixpkgs> {}).lib'
```
true
Sometimes both `pkgs` and `lib` are passed as arguments.
In that case, one can assume `pkgs.lib` and `lib` to be equivalent.
This is done to improve readability by avoiding repeated use of `pkgs.lib`.
Example:
```nix
{ pkgs, lib, ... }:
# ... multiple uses of `pkgs`
# ... multiple uses of `lib`
```
</details>
For historical reasons, some of the functions in `pkgs.lib` are equivalent to [`builtins`](builtins) of the same name.
(impurities)=
## Impurities