mirror of
https://codeberg.org/mhwombat/nix-book.git
synced 2025-12-27 00:34:58 +08:00
initial commit
This commit is contained in:
parent
3d00d41153
commit
3bda18c1db
14 changed files with 533 additions and 0 deletions
34
source/nix-language/attribute-sets.adoc
Normal file
34
source/nix-language/attribute-sets.adoc
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
= Attribute set operations
|
||||
|
||||
The `.` operator selects an attribute from a set.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> animal = { name = { first = "Professor"; last = "Paws"; }; age = 10; species = "cat"; }
|
||||
|
||||
nix-repl> animal . age
|
||||
10
|
||||
|
||||
nix-repl> animal . name . first
|
||||
"Professor"
|
||||
....
|
||||
|
||||
We can use the `?` operator to find out if a set has a particular attribute.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> animal ? species
|
||||
true
|
||||
|
||||
nix-repl> animal ? bicycle
|
||||
false
|
||||
....
|
||||
|
||||
We can use the `//` operator to modify an attribute set.
|
||||
Recall that Nix values are immutable, so the result is a new value (the original is not modified).
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> animal // { species = "tiger"; }
|
||||
{ age = 10; name = { ... }; species = "tiger"; }
|
||||
....
|
||||
50
source/nix-language/booleans.adoc
Normal file
50
source/nix-language/booleans.adoc
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# Boolean operations
|
||||
|
||||
The usual boolean operators are available.
|
||||
Recall that earlier we set `a = 7` and `b = 3`.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> a == 7 # equality test
|
||||
true
|
||||
|
||||
nix-repl> b != 3 # inequality
|
||||
false
|
||||
|
||||
nix-repl> a > 12 # greater than
|
||||
false
|
||||
|
||||
nix-repl> b >= 2 # greater than or equal
|
||||
true
|
||||
|
||||
nix-repl> a < b # less than
|
||||
false
|
||||
|
||||
nix-repl> b <= a # less than or equal
|
||||
true
|
||||
|
||||
nix-repl> !true # logical negation
|
||||
false
|
||||
|
||||
nix-repl> (3 * a == 21) && (a > b) # logical AND
|
||||
true
|
||||
|
||||
nix-repl> (b > a) || (b > 10) # logical OR
|
||||
false
|
||||
....
|
||||
|
||||
One operator that might be unfamiliar to you is _logical implication_, which uses the symbol `->`.
|
||||
The expression `u -> v` is equivalent to `!u || v`.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> u = false
|
||||
|
||||
nix-repl> v = true
|
||||
|
||||
nix-repl> u -> v
|
||||
true
|
||||
|
||||
nix-repl> v -> u
|
||||
false
|
||||
....
|
||||
6
source/nix-language/builtins.adoc
Normal file
6
source/nix-language/builtins.adoc
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
= Built-in functions
|
||||
|
||||
// TODO
|
||||
|
||||
For a complete list of built-in functions, see
|
||||
https://nixos.org/manual/nix/stable/language/builtins
|
||||
31
source/nix-language/dont-read.adoc
Normal file
31
source/nix-language/dont-read.adoc
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
= Stop reading this chapter!
|
||||
|
||||
When I first began using Nix, it seemed logical to start by learning the Nix language.
|
||||
However, after following an in-depth tutorial,
|
||||
I found that I didn't know how to do anything useful with the language!
|
||||
It wasn't until later that I understood what I was missing:
|
||||
a guide to the most useful library functions.
|
||||
|
||||
When working with Nix or NixOS,
|
||||
it's very rare that you'll want to write something from scratch.
|
||||
Instead, you'll use one of the many library functions
|
||||
that make things easier and shield you from the underlying complexity.
|
||||
Many of these functions are language-specific,
|
||||
and the documentation for them may be inadequate.
|
||||
Often the easiest (or only) way to learn to use them
|
||||
is to find an example that does something similar to what you want,
|
||||
and then modify the function parameters to suit your needs.
|
||||
|
||||
At this point you've learned enough of the Nix language
|
||||
to do the majority of common Nix tasks.
|
||||
So when I say "Stop reading this chapter!", I'm only half-joking.
|
||||
Instead I suggest that you _skim_ the rest of this chapter,
|
||||
paying special attention to anything marked with icon:exclamation-circle[].
|
||||
Then move on to the following chapters
|
||||
where you will learn how to develop and package software using Nix.
|
||||
Afterward, come back to this chapter and read it in more detail.
|
||||
|
||||
While writing this book, I anticipated that readers would want to skip around,
|
||||
alternating between pure learning and learning-by-doing.
|
||||
I've tried to structure the book to support that;
|
||||
sometimes repeating information from earlier chapters that you might have skipped.
|
||||
3
source/nix-language/functions.adoc
Normal file
3
source/nix-language/functions.adoc
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
= Functions
|
||||
|
||||
// TODO
|
||||
16
source/nix-language/intro.adoc
Normal file
16
source/nix-language/intro.adoc
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
= Introducing the Nix language
|
||||
|
||||
Nix and NixOS use a functional programming language called _Nix_
|
||||
to specify how to build and install software,
|
||||
and how to configure system, user, and project-specific environments.
|
||||
(Yes, “Nix” is the name of both the package manager and the language it uses.)
|
||||
|
||||
Nix is a _functional_ language.
|
||||
In a _procedural_ language such as C or Java,
|
||||
the focus is on writing a series of _steps_ (statements) to achieve a desired result.
|
||||
By contrast, in a functional language the focus is on _defining_ the desired result.
|
||||
|
||||
In the case of Nix, the desired result is usually a _derivation_:
|
||||
a software package that has been built and is ready for use.
|
||||
The Nix language has been designed for that purpose,
|
||||
and thus has some features you don't typically find in general-purpose languages.
|
||||
9
source/nix-language/lists.adoc
Normal file
9
source/nix-language/lists.adoc
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
= List operations
|
||||
|
||||
Lists can be concatenated using the `++` operator.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> [ 1 2 3 ] ++ [ "apple" "banana" ]
|
||||
[ 1 2 3 "apple" "banana" ]
|
||||
....
|
||||
27
source/nix-language/main.adoc
Normal file
27
source/nix-language/main.adoc
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
= The Nix language
|
||||
|
||||
include::intro.adoc[leveloffset=+1]
|
||||
|
||||
include::types.adoc[leveloffset=+1]
|
||||
|
||||
include::dont-read.adoc[leveloffset=+1]
|
||||
|
||||
include::repl.adoc[leveloffset=+1]
|
||||
|
||||
include::variables.adoc[leveloffset=+1]
|
||||
|
||||
include::numbers.adoc[leveloffset=+1]
|
||||
|
||||
include::strings.adoc[leveloffset=+1]
|
||||
|
||||
include::booleans.adoc[leveloffset=+1]
|
||||
|
||||
include::paths.adoc[leveloffset=+1]
|
||||
|
||||
include::lists.adoc[leveloffset=+1]
|
||||
|
||||
include::attribute-sets.adoc[leveloffset=+1]
|
||||
|
||||
include::functions.adoc[leveloffset=+1]
|
||||
|
||||
include::builtins.adoc[leveloffset=+1]
|
||||
83
source/nix-language/numbers.adoc
Normal file
83
source/nix-language/numbers.adoc
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# Numeric operations
|
||||
|
||||
The usual arithmetic operators are provided.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> 1 + 2 # addition
|
||||
3
|
||||
|
||||
nix-repl> 5 - 3 # subtraction
|
||||
2
|
||||
|
||||
nix-repl> 3 * 4 # multiplication
|
||||
12
|
||||
|
||||
nix-repl> 6 / 2 # division
|
||||
3
|
||||
|
||||
nix-repl> -1 # negation
|
||||
-1
|
||||
....
|
||||
|
||||
[IMPORTANT]
|
||||
====
|
||||
The spaces before and after operators aren't always required.
|
||||
However, you can get unexpected results when you omit them, as shown below.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> 6/2
|
||||
/home/amy/codeberg/nix-book/6/2
|
||||
....
|
||||
|
||||
What happened?
|
||||
Let's use the `:t` command to find out the type of the expression.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> :t 6/2
|
||||
....
|
||||
|
||||
If an expression can be interpreted as a path, Nix will do so.
|
||||
This is useful, because paths are _far_ more commonly used in Nix expressions that arithmetic operators.
|
||||
In this case, Nix interpreted `6/2` as a relative path from the current directory,
|
||||
which in the above example was `/home/amy/codeberg/nix-book`.
|
||||
|
||||
Adding a space after the `/` operator produces the expected result.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> 6/ 2
|
||||
3
|
||||
....
|
||||
|
||||
To avoid surprises and improve readability, I prefer to use spaces before and after all operators.
|
||||
====
|
||||
|
||||
Numbers without a decimal point are assumed to be integers.
|
||||
To ensure that a number is interpreted as a floating-point value, add a decimal point.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> :t 5
|
||||
an integer
|
||||
|
||||
nix-repl> :t 5.0
|
||||
a float
|
||||
|
||||
nix-repl> :t 5.
|
||||
a float
|
||||
....
|
||||
|
||||
In the example below, the first expression results in integer division (rounding down),
|
||||
while the second produces a floating-point result.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> 5 / 3
|
||||
1
|
||||
|
||||
nix-repl> 5.0 / 3
|
||||
1.66667
|
||||
....
|
||||
65
source/nix-language/paths.adoc
Normal file
65
source/nix-language/paths.adoc
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
= Path opearations
|
||||
|
||||
Paths can be concatenated with each other to produce a new path.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> /home/wombat + /bin/sh
|
||||
/home/wombat/bin/sh
|
||||
|
||||
nix-repl> :t /home/wombat + /bin/sh
|
||||
a path
|
||||
....
|
||||
|
||||
[IMPORTANT]
|
||||
====
|
||||
Relative paths become absolute when they are parsed, which occurs before concatenation.
|
||||
This is why the result in the example below is not `/home/amy/file.txt`.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> /home/wombat + ./file.txt
|
||||
/home/wombat/home/amy/codeberg/nix-book/file.txt
|
||||
....
|
||||
====
|
||||
|
||||
|
||||
A path can be concatenated with a string to produce a new path.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> homePath + "/file.txt"
|
||||
/home/wombat/file.txt
|
||||
|
||||
nix-repl> :t homePath + "/myfile.txt"
|
||||
a path
|
||||
....
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
The Nix reference manual says that the string must not "have a string context" that refers to a store path.
|
||||
String contexts are beyond the scope of this book;
|
||||
for more information see https://nixos.org/manual/nix/stable/language/operators#path-concatenation.
|
||||
====
|
||||
|
||||
Strings can be concatenated with paths, but with a side-effect that may surprise you:
|
||||
if the path exists, the file is copied to the Nix store!
|
||||
The result is a string, not a path.
|
||||
|
||||
In the example below, the file `file.txt` is copied to `/nix/store/gp8ba25gpwvbqizqfr58jr014gmv1hd8-file.txt`
|
||||
(not `/home/wombat/nix/store/gp8ba25gpwvbqizqfr58jr014gmv1hd8-file.txt`).
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> "/home/wombat" + ./file.txt
|
||||
"/home/wombat/nix/store/gp8ba25gpwvbqizqfr58jr014gmv1hd8-file.txt"
|
||||
....
|
||||
|
||||
The path must exist.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> "/home/wombat" + ./no-such-file.txt
|
||||
error (ignored): error: end of string reached
|
||||
error: getting status of '/home/amy/codeberg/nix-book/no-such-file.txt': No such file or directory
|
||||
....
|
||||
44
source/nix-language/repl.adoc
Normal file
44
source/nix-language/repl.adoc
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
= The Nix REPL
|
||||
|
||||
The Nix REPL footnote:[REPL is an acronym for (Read-Eval-Print-Loop).]
|
||||
is an interactive environment for evaluating and debugging Nix code.
|
||||
It's also a good place to begin learning Nix.
|
||||
Enter it using the command `nix repl`.
|
||||
Within the REPL, type `:?` to see a list of available commands.
|
||||
|
||||
[source]
|
||||
....
|
||||
$# echo "$ nix repl"
|
||||
Welcome to Nix 2.18.1. Type :? for help.
|
||||
|
||||
nix-repl> :?
|
||||
The following commands are available:
|
||||
|
||||
<expr> Evaluate and print expression
|
||||
<x> = <expr> Bind expression to variable
|
||||
:a, :add <expr> Add attributes from resulting set to scope
|
||||
:b <expr> Build a derivation
|
||||
:bl <expr> Build a derivation, creating GC roots in the
|
||||
working directory
|
||||
:e, :edit <expr> Open package or function in $EDITOR
|
||||
:i <expr> Build derivation, then install result into
|
||||
current profile
|
||||
:l, :load <path> Load Nix expression and add it to scope
|
||||
:lf, :load-flake <ref> Load Nix flake and add it to scope
|
||||
:p, :print <expr> Evaluate and print expression recursively
|
||||
:q, :quit Exit nix-repl
|
||||
:r, :reload Reload all files
|
||||
:sh <expr> Build dependencies of derivation, then start
|
||||
nix-shell
|
||||
:t <expr> Describe result of evaluation
|
||||
:u <expr> Build derivation, then start nix-shell
|
||||
:doc <expr> Show documentation of a builtin function
|
||||
:log <expr> Show logs for a derivation
|
||||
:te, :trace-enable [bool] Enable, disable or toggle showing traces for
|
||||
errors
|
||||
:?, :help Brings up this help menu
|
||||
....
|
||||
|
||||
A command that is useful to beginners is `:t`, which tells you the type of an expression.
|
||||
|
||||
Note that the command to exit the REPL is `:q` (or `:quit` if you prefer).
|
||||
42
source/nix-language/strings.adoc
Normal file
42
source/nix-language/strings.adoc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# String operations
|
||||
|
||||
String concatenation uses the `+` operator.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> "Hello, " + "world!"
|
||||
"Hello, world!"
|
||||
....
|
||||
|
||||
You can use the `${_variable_}` syntax to insert the value of a variable within a string.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> name = "Wombat"
|
||||
|
||||
nix-repl> "Hi, I'm ${name}."
|
||||
"Hi, I'm Wombat."
|
||||
....
|
||||
|
||||
[IMPORTANT]
|
||||
====
|
||||
You cannot mix numbers and strings.
|
||||
Nix does provide functions for converting between types; we'll see these later.
|
||||
Earlier we set `a = 7`, so the following expression fails.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> "My favourite number is ${a}."
|
||||
error:
|
||||
… while evaluating a path segment
|
||||
|
||||
at «string»:1:25:
|
||||
|
||||
1| "My favourite number is ${a}."
|
||||
| ^
|
||||
|
||||
error: cannot coerce an integer to a string
|
||||
....
|
||||
====
|
||||
|
||||
// TODO Talk about "strings with context" https://shealevy.com/blog/2018/08/05/understanding-nixs-string-context/
|
||||
90
source/nix-language/types.adoc
Normal file
90
source/nix-language/types.adoc
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
= Data types
|
||||
|
||||
== Strings
|
||||
|
||||
Strings are enclosed by double quotes (`"`), or _two_ single quotes (`'`).
|
||||
|
||||
"Hello, world!"
|
||||
|
||||
''This string contains "double quotes"''
|
||||
|
||||
They can span multiple lines.
|
||||
|
||||
''Old pond
|
||||
A frog jumps in
|
||||
The sound of water
|
||||
-- Basho''
|
||||
|
||||
== Integers
|
||||
|
||||
7
|
||||
256
|
||||
|
||||
== Floating point numbers
|
||||
|
||||
3.14
|
||||
6.022e23
|
||||
|
||||
== Boolean
|
||||
|
||||
The Boolean values in Nix are `true` and `false`.
|
||||
|
||||
== Paths
|
||||
|
||||
File paths are play an important role in building software, so Nix has a special data type for them.
|
||||
Paths may be absolute (e.g. `/bin/sh`) or relative (e.g. `./data/file1.csv`).
|
||||
Note that paths are not enclosed in quotation marks; they are not strings!
|
||||
|
||||
Enclosing a path in angle brackets, e.g. <nixpkgs> causes the directories
|
||||
listed in the environment variable NIX_PATH to be searched for the given
|
||||
file or directory name.
|
||||
These are called _lookup paths_.
|
||||
|
||||
== Lists
|
||||
|
||||
List elements are enclosed in square brackets and separated by spaces (not commas).
|
||||
The elements need not be of the same type.
|
||||
|
||||
[ "apple" 123 ./build.sh false ]
|
||||
|
||||
Lists can be empty.
|
||||
|
||||
[]
|
||||
|
||||
List elements can be of any type, and can even be lists themselves.
|
||||
|
||||
[ [ 1 2 ] [ 3 4 ] ]
|
||||
|
||||
== Attribute sets
|
||||
|
||||
Attribute sets associate keys with values.
|
||||
They are enclosed in curly brackets, and the associations are terminated by semi-colons.
|
||||
Note that the final semi-colon before the closing bracket is required.
|
||||
|
||||
{ name = "Professor Paws"; age = 10; species = "cat"; }
|
||||
|
||||
|
||||
Attribute sets can be empty.
|
||||
|
||||
{}
|
||||
|
||||
Values of attribute sets can be of any type, and can even be attribute sets themselves.
|
||||
|
||||
{ name = { first = "Professor"; last = "Paws"; }; age = 10; species = "cat"; }
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
In some Nix documentation, and in many articles about Nix,
|
||||
attribute sets are simply called "sets".
|
||||
====
|
||||
|
||||
== Functions
|
||||
|
||||
We'll learn how to write functions later in this chapter.
|
||||
For now, note that functions are "first-class values",
|
||||
meaning that they can be treated like any other data type.
|
||||
For example, a function can be assigned to a variable, appear as an element in a list,
|
||||
or be associated with a key in an attribute set.
|
||||
|
||||
[ "apple" 123 ./build.sh false (x: x*x) ]
|
||||
{ name = "Professor Paws"; age = 10; species = "cat"; formula = (x: x*2); }
|
||||
33
source/nix-language/variables.adoc
Normal file
33
source/nix-language/variables.adoc
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
= Variables
|
||||
|
||||
You can declare variables in Nix and assign values to them.
|
||||
// TODO explain that values are immutable.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> a = 7
|
||||
|
||||
nix-repl> b = 3
|
||||
|
||||
nix-repl> a - b
|
||||
4
|
||||
....
|
||||
|
||||
[IMPORTANT]
|
||||
====
|
||||
As mentioned previously, omitting the spaces around operators can have unexpected results.
|
||||
As Nix allows hyphens (`-`) in variable names,
|
||||
`a-b` is interpreted as the name of a variable in the following example.
|
||||
|
||||
[source]
|
||||
....
|
||||
nix-repl> a-b
|
||||
error: undefined variable 'a-b'
|
||||
|
||||
at «string»:1:1:
|
||||
|
||||
1| a-b
|
||||
| ^
|
||||
....
|
||||
====
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue