Merge pull request #30 from michaelpj/imp/pills-2

Pills 2-4: edit for style and clarity
This commit is contained in:
Graham Christensen 2017-12-30 18:37:11 -05:00 committed by GitHub
commit c5abff6df4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 308 additions and 301 deletions

View file

@ -18,11 +18,9 @@
</para>
<para>
<link
xlink:href="https://nixos.org/nix/manual/#chap-installation">Nix
installation</link> is as easy as installing any other package.
It will not revolutionize our system, it will stay in its own
place out of our way.
<link xlink:href="https://nixos.org/nix/manual/#chap-installation">Installing
Nix</link> is as easy as installing any other package.
It will not drastically change our system, it will stay out of our way.
</para>
<section>
@ -37,114 +35,114 @@
</para>
<para>
My pills are not a simple tutorial, there's are several articles
out there to learn the basics of nix and unix. We'll instead
walk through the nix system to understand the fundamentals.
These articles are not a tutorial on <emphasis>using</emphasis> Nix.
Instead, we're going to walk through the Nix system to understand the fundamentals.
</para>
<para>
First thing to note: those stuff in nix store refer to software
in nix store itself. It doesn't use libc from our system or
whatelse. It's a self-contained nix bootstrap.
The first thing to note: derivations in the Nix store refer to other
derivations which are themselves in the Nix store. They don't use <literal>libc</literal>
from our system or anywhere else. It's a self-contained store of all the software we need to bootstrap up
to any particular package.
</para>
<para>
Quick note: in a multi-user installation, such as the one used in NixOS,
<note><para>
In a multi-user installation, such as the one used in NixOS,
the store is owned by root and multiple users can install and build
software through a nix daemon. You can read more about multi-user
software through a Nix daemon. You can read more about multi-user
installations here: <link
xlink:href="https://nixos.org/nix/manual/#ssec-multi-user">https://nixos.org/nix/manual/#ssec-multi-user</link>.
</para>
</para></note>
</section>
<section>
<title>So small nix store</title>
<title>The beginnings of the Nix store</title>
<para>
Start inspecting the output of the install command:
Start looking at the output of the install command:
</para>
<screen>copying Nix to /nix/store..........................</screen>
<para>
Effectively, that's right the <literal>/nix/store</literal> we
were talking in the first pill. The contents is the strictly
That's the <filename>/nix/store</filename> we
were talking in the first article. We're copying in the
necessary software to bootstrap a Nix system. You can see bash,
core utils, the toolchain, perl libraries, sqlite and nix itself
coreutils, the C compiler toolchain, perl libraries, sqlite and Nix itself
with its own tools and libnix.
</para>
<para>
You surely noticed that in <literal>/nix/store</literal> not
only directories are allowed, but also files, always in the form
You may have noticed that <filename>/nix/store</filename> can contain
not only directories, but also files, still always in the form
<replaceable>hash-name</replaceable>.
</para>
</section>
<section>
<title>The holy database</title>
<title>The Nix database</title>
<para>
Right after copying the store, the installation process
initializes the database with the current information:
initializes a database:
</para>
<screen>initialising Nix database...</screen>
<para>
Oh Nix also has a database. It's under
<literal>/nix/var/nix/db</literal>. It is an sqlite database
Yes, Nix also has a database. It's stored under
<filename>/nix/var/nix/db</filename>. It is a sqlite database
that keeps track of the dependencies between derivations.
</para>
<para>
The schema is very simple: there's a table of valid paths,
mapping from auto increment integer to store path.
mapping from an auto increment integer to a store path.
</para>
<para>
Then there's a dependency relation from one path to other paths.
Then there's a dependency relation from path to paths upon which they depend.
</para>
<para>
You may inspect it by installing sqlite
(<command>nix-env -iA sqlite -f '&lt;nixpkgs&gt;'</command>) then running
<command>sqlite3 /nix/var/nix/db/db.sqlite</command>
You can inspect the database by installing sqlite
(<command>nix-env -iA sqlite -f '&lt;nixpkgs&gt;'</command>) and then running
<command>sqlite3 /nix/var/nix/db/db.sqlite</command>.
</para>
<note><para>If this is the first time you're using Nix after the
initial installation, remember you must close and open your
terminals first.</para></note>
terminals first, so that your shell environment will be updated.</para></note>
<para>
<emphasis>Important rule:</emphasis> never change
<literal>/nix/store</literal> manually because that wouldn't be
in sync with the sqlite db, unless you know what you are doing.
</para>
<important><para>
Never change <filename>/nix/store</filename> manually. If you do, then it will
no longer be in sync with the sqlite db, unless you <emphasis>really</emphasis>
know what you are doing.
</para></important>
</section>
<section>
<title>The first profile</title>
<para>
Then we discover the <link
xlink:href="https://nixos.org/nix/manual/#sec-profiles">profile</link>
concept during the installation:
Next in the installation, we encounter the concept of the <link
xlink:href="https://nixos.org/nix/manual/#sec-profiles">profile</link>:
</para>
<xi:include href="./02/user-environment.xml" parse="xml" />
<para>
A profile in nix is a general and very convenient concept for
realizing rollbacks. Profiles are used to compose more
components that are spread among multiple paths, under a new
unified path. Not only, profiles are made up of multiple
generations: they are versioned. Whenever you change a profile,
A profile in Nix is a general and convenient concept for
realizing rollbacks. Profiles are used to compose
components that are spread among multiple paths under a new
unified path. Not only that, but profiles are made up of multiple
"generations": they are versioned. Whenever you change a profile,
a new generation is created.
</para>
<para>
Generations thus can be switched and rollback-ed atomatically.
Generations can be switched and rolled back atomically, which makes
them convenient for managing changes to your system.
</para>
<para>
@ -153,45 +151,46 @@
<xi:include href="./02/profile.xml" parse="xml" />
<para>
That <package>nix-1.7</package> derivation in the nix store is
nix itself, with binaries and libraries. The installation
basically reproduced the hierarchy of the
<package>nix-1.7</package> derivation in the profile by means of
That <package>nix-1.7</package> derivation in the Nix store is
Nix itself, with binaries and libraries. The process of "installing"
the derivation in the profile basically reproduces the hierarchy of the
<package>nix-1.7</package> store derivation in the profile by means of
symbolic links.
</para>
<para>
The contents of this profile are special, because only one
program has been installed in our profile, therefore e.g. the
bin directory fully points to the only program being installed.
<filename>bin</filename> directory points to the only program
which has been installed (Nix itself).
</para>
<para>
But that's only the contents of the latest generation of our
profile. In fact, <literal>~/.nix-profile</literal> itself is a
profile. In fact, <filename>~/.nix-profile</filename> itself is a
symbolic link to
<literal>/nix/var/nix/profiles/default</literal>.
<filename>/nix/var/nix/profiles/default</filename>.
</para>
<para>
In turn, that's a symlink to <literal>default-1-link</literal>
in the same directory. Yes, that means it's the generation #1 of
In turn, that's a symlink to <filename>default-1-link</filename>
in the same directory. Yes, that means it's the first generation of
the <literal>default</literal> profile.
</para>
<para>
Finally that's a symlink to the nix store "user-environment"
derivation that you saw printed during the installation process.
Finally, <filename>default-1-link</filename> is a symlink to the nix
store "user-environment" derivation that you saw printed during the installation process.
</para>
<para>
The <filename>manifest.nix</filename> will be meat for the next pill.
We'll talk about <filename>manifest.nix</filename> more in the next article.
</para>
</section>
<section>
<title>Meet nixpkgs expressions</title>
<title>Nixpkgs expressions</title>
<para>
More wild output from the installer:
More output from the installer:
</para>
<screen><xi:include href="./02/nixpkgs-expressions.txt"
@ -203,7 +202,7 @@
expressions</link> are used to describe packages and how to
build them. <link
xlink:href="https://nixos.org/nixpkgs/">Nixpkgs</link> is the
repository containing all these expressions: <link
repository containing all of the expressions: <link
xlink:href="https://github.com/NixOS/nixpkgs">https://github.com/NixOS/nixpkgs</link>.
</para>
@ -213,35 +212,35 @@
</para>
<para>
The second profile we meet is the channels profile.
The second profile we discover is the channels profile.
<filename>~/.nix-defexpr/channels</filename> points to
<filename>/nix/var/nix/profiles/per-user/nix/channels</filename>
which points to <literal>channels-1-link</literal> which points
to a nix store directory containing the downloaded nix
to a Nix store directory containing the downloaded Nix
expressions.
</para>
<para>
Channels are a set of packages and expressions available for
download. Similar to debian stable and unstable, there's a
download. Similar to Debian stable and unstable, there's a
stable and unstable channel. In this installation, we're
tracking nixpkgs unstable.
tracking <literal>nixpkgs-unstable</literal>.
</para>
<para>
Don't bother yet with nix expressions.
Don't worry about Nix expressions yet, we'll get to them later.
</para>
<para>
Finally, for your own convenience, it modified
<filename>~/.profile</filename> to automatically enter the nix
Finally, for your convenience, the installer modified
<filename>~/.profile</filename> to automatically enter the Nix
environment. What
<filename>~/.nix-profile/etc/profile.d/nix.sh</filename> really
does is simply adding <filename>~/.nix-profile/bin</filename> to
does is simply to add <filename>~/.nix-profile/bin</filename> to
<varname>PATH</varname> and
<filename>~/.nix-defexpr/channels/nixpkgs</filename> to
<varname>NIX_PATH</varname>. We'll discuss about
<varname>NIX_PATH</varname> in another pill.
<varname>NIX_PATH</varname>. We'll discuss
<varname>NIX_PATH</varname> later.
</para>
<para>
@ -254,15 +253,15 @@
<title>FAQ: Can I change /nix to something else?</title>
<para>
You can, but there's a strong reason to keep using
<literal>/nix</literal> instead of a different directory. All
the derivations depend on other derivations by absolute path. I
remind you in pill 1 that bash pointed to a
<package>glibc</package> under <filename>/nix/store</filename>.
You can, but there's a good reason to keep using
<filename>/nix</filename> instead of a different directory. All
the derivations depend on other derivations by using absolute paths. We
saw in the first article that bash referenced a
<package>glibc</package> under a specific absolute path in <filename>/nix/store</filename>.
</para>
<para>
You can see now by yourself, don't worry if you see multiple
You can see for yourself, don't worry if you see multiple
bash derivations:
</para>
@ -275,43 +274,48 @@
from debian mirrors) otherwise:
<itemizedlist>
<listitem><para><package>glibc</package> would be installed under <filename>/foo/store</filename></para></listitem>
<listitem><para>thus bash needs to point to <package>glibc</package> under <filename>/foo/store</filename></para></listitem>
<listitem><para>the binary cache won't help, and we'd have to recompile all the stuff by ourselves</para></listitem>
<listitem><para>
<package>glibc</package> would be installed under <filename>/foo/store</filename>
</para></listitem>
<listitem><para>
Thus bash would need to point to <package>glibc</package> under <filename>/foo/store</filename>,
instead of under <filename>/nix/store</filename>
</para></listitem>
<listitem><para>
So the binary cache can't help, because we need a <emphasis>different</emphasis> bash,
and so we'd have to recompile everything ourselves.
</para></listitem>
</itemizedlist>
</para>
<para>
After all <filename>/nix</filename> is a cool place.
After all <filename>/nix</filename> is a sensible place for the store.
</para>
</section>
<section>
<title>Conclusion</title>
<para>
We've installed nix on our system, fully isolated and owned by
the <literal>nix</literal> user as we're still diffident with
We've installed Nix on our system, fully isolated and owned by
the <literal>nix</literal> user as we're still coming to terms with
this new system.
</para>
<para>
We learned some new concepts like profiles and channels. In
particular, with profiles we're able to manage multiple
generations of a composition of packages, while with channels
we're able to download binaries from nixos.org.
we're able to download binaries from <literal>nixos.org</literal>.
</para>
<para>
The installation put everything under <filename>/nix</filename>,
and some symlinks in the nix user home. That's because every
and some symlinks in the Nix user home. That's because every
user is able to install and use software in her own environment.
</para>
<para>
I hope I left nothing uncovered in a way that you think there's
some kind of magic behind. It's all about putting components in
the store and symlinking these components together.
</para>
<para>
Also I hope the commands in this pill were consistent with your
fresh nix installation.
I hope I left nothing uncovered so that you think there's
some kind of magic going on behind the scenes. It's all
about putting components in the store and symlinking
these components together.
</para>
</section>
@ -319,7 +323,7 @@
<title>Next pill...</title>
<para>
...we will enter the nix environment and learn how to interact
...we will enter the Nix environment and learn how to interact
with the store.
</para>
</section>

View file

@ -4,22 +4,22 @@
version="5.0"
xml:id="enter-environment">
<title>Enter Environment</title>
<title>Enter the Environment</title>
<para>
Welcome to the third Nix pill. In the previous <link
linkend="install-on-your-running-system">second pill</link> we have
Welcome to the third Nix pill. In the <link
linkend="install-on-your-running-system">second pill</link> we
installed Nix on our running system. Now we can finally play with it a
little, things also apply to NixOS users.
little, these things also apply to NixOS users.
</para>
<section>
<title>Enter the environment</title>
<para>
In the previous pill we created a nix user, so let's start by switching
user with <literal>su - nix</literal>. If your
<literal>~/.profile</literal> got evaluated, then your should now be able
In the previous article we created a Nix user, so let's start by switching
to it with <command>su - nix</command>. If your
<filename>~/.profile</filename> got evaluated, then your should now be able
to run commands like <literal>nix-env</literal> and
<literal>nix-store</literal>.
</para>
@ -31,8 +31,8 @@
<screen><xi:include href="./03/source-nix.txt" parse="text" /></screen>
<para>
I remind you, <literal>~/.nix-profile/etc</literal> points to the nix-1.7
derivation. At this point, we are in our nix user profile.
To remind you, <literal>~/.nix-profile/etc</literal> points to the <literal>nix-1.7</literal>
derivation. At this point, we are in our Nix user profile.
</para>
</section>
@ -40,8 +40,8 @@
<title>Install something</title>
<para>
Finally something practical! Installation in the nix environment is an
interesting process. Let's install nix-repl, a simple command line tool
Finally something practical! Installation into the Nix environment is an
interesting process. Let's install <literal>nix-repl</literal>, a simple command line tool
for playing with the Nix language. Yes, Nix is a <link xlink:href="http://nixos.org/nix/manual/#idm47361539226272">
pure, lazy, functional language</link>, not only a set of tools to
manage derivations.
@ -54,19 +54,18 @@
<screen><xi:include href="./03/install-repl.txt" parse="text" /></screen>
<para>
Now you can run nix-repl. Things to notice:
Now you can run <literal>nix-repl</literal>. Things to notice:
</para>
<itemizedlist>
<listitem>
<para>
We did install software as user, only for the nix user.
We installed software as a user, and only for the Nix user.
</para>
</listitem>
<listitem>
<para>
It created a new user environment. That's a new generation of our
nix user profile.
Nix user profile.
</para>
</listitem>
<listitem>
@ -78,31 +77,31 @@
</listitem>
<listitem>
<para>
We installed nix-repl by derivation name minus the version. I repeat:
we did specify the <emphasis role="bold">derivation name</emphasis>
(minus the version) to install.
We installed <literal>nix-repl</literal> by derivation name minus the version. I repeat:
we specified the <emphasis role="bold">derivation name</emphasis>
(minus the version) to install it.
</para>
</listitem>
</itemizedlist>
<para>
We can list generations without walking through the /nix hierarchy:
We can list generations without walking through the <filename>/nix</filename> hierarchy:
</para>
<screen><xi:include href="./03/list-generations.txt" parse="text" /></screen>
<para>
List installed derivations:
Listing installed derivations:
</para>
<screen><xi:include href="./03/list-installed-derivations.txt" parse="text" /></screen>
<para>
So, where did nix-repl really get installed?
So, where did <literal>nix-repl</literal> really get installed?
<literal>which nix-repl</literal> is
<literal>~/.nix-profile/bin/nix-repl</literal> which points to the store.
We can also list the derivation paths with nix-env -q --out-path. So
that's how those derivation paths are called: the
We can also list the derivation paths with <command>nix-env -q --out-path</command>. So
that's what those derivation paths are called: the
<emphasis role="bold">output</emphasis> of a build.
</para>
</section>
@ -111,10 +110,11 @@
<title>Path merging</title>
<para>
At this point you sure have the necessity to run "man". Even if you
already have man system-wide outside of the nix environment, you can
install and use it within nix with <literal>nix-env -i man</literal>. As
usual, a new generation will be created, and ~/.nix-profile will point to
At this point you probably want to run <literal>man</literal> to get some documentation.
Even if you
already have man system-wide outside of the Nix environment, you can
install and use it within Nix with <command>nix-env -i man</command>. As
usual, a new generation will be created, and <filename>~/.nix-profile</filename> will point to
it.
</para>
@ -127,26 +127,26 @@
<screen><xi:include href="./03/ls-nix-profile.txt" parse="text" /></screen>
<para>
Now that's interesting. When only nix-1.7 was installed, bin/ was a
symlink to nix-1.7. Now that we've actually installed some things
(man, nix-repl), it's a real directory, not a symlink.
Now that's interesting. When only <literal>nix-1.7</literal> was installed, <filename>bin</filename> was a
symlink to <literal>nix-1.7</literal>. Now that we've actually installed some things
(<literal>man</literal>, <literal>nix-repl</literal>), it's a real directory, not a symlink.
</para>
<screen><xi:include href="./03/ls-profile-bin.txt" parse="text" /></screen>
<para>
All clear. nix-env merged the paths from the installed derivations.
<literal>which man</literal> points to the nix profile, rather than the
system man, because <literal>~/.nix-profile/bin</literal> is at the head
of <literal>$PATH</literal>.
Okay, that's clearer now. <literal>nix-env</literal> merged the paths from the installed derivations.
<command>which man</command> points to the Nix profile, rather than the
system <literal>man</literal>, because <filename>~/.nix-profile/bin</filename> is at the head
of <varname>$PATH</varname>.
</para>
</section>
<section>
<title>Rollback / switch generation</title>
<title>Rolling back and switching generation</title>
<para>
The last command installed "man". We should be at generation #3, unless
The last command installed <literal>man</literal>. We should be at generation 3, unless
you changed something in the middle. Let's say we want to rollback to the
old generation:
</para>
@ -154,21 +154,20 @@
<screen><xi:include href="./03/rollback.txt" parse="text" /></screen>
<para>
Now <literal>nix-env -q</literal> does not list "man" anymore.
<literal>ls -l `which man`</literal> should now be your system installed
one.
Now <command>nix-env -q</command> does not list <literal>man</literal> anymore.
<command>ls -l `which man`</command> should now be your system copy.
</para>
<para>
Enough with the joke, let's go back to the last generation:
Enough with the rollback, let's go back to the most recent generation:
</para>
<screen><xi:include href="./03/generation-3.txt" parse="text" /></screen>
<para>
I invite you to read the manpage of nix-env. nix-env requires an operation
to perform, then there are common options for all operations, and there
are options specific to an operation.
I invite you to read the manpage of <literal>nix-env</literal>. <literal>nix-env</literal> requires an operation
to perform, then there are common options for all operations, as well as
options specific to each operation.
</para>
<para>
@ -189,43 +188,44 @@
<para>
To query and manipulate the store, there's the
<literal>nix-store</literal> command. We can do neat things, but we'll
<literal>nix-store</literal> command. We can do some interesting things, but we'll
only see some queries for now.
</para>
<para>
Show direct runtime dependencies of nix-repl:
To show the direct runtime dependencies of <literal>nix-repl</literal>:
</para>
<screen><xi:include href="./03/references.txt" parse="text" /></screen>
<para>
The argument to nix-store can be anything as long as it points to the
nix store. It will follow symlinks.
The argument to <literal>nix-store</literal> can be anything as long as it points to the
Nix store. It will follow symlinks.
</para>
<para>
It may not make sense for you right now, but let's print reverse
dependencies of nix-repl:
It may not make sense to you right now, but let's print reverse
dependencies of <literal>nix-repl</literal>:
</para>
<screen><xi:include href="./03/referrers.txt" parse="text" /></screen>
<para>
Did you expect it? Our environments depend upon nix-repl. Yes, the
environments are in the store, and since there are symlinks to nix-repl,
therefore the environment depends upon nix-repl
Was it what you expected? It turns out that our environments depend upon <literal>nix-repl</literal>.
Yes, that means that the environments are in the store, and since they contain symlinks to <literal>nix-repl</literal>,
therefore the environment depends upon <literal>nix-repl</literal>.
</para>
<para>
It lists two environments, generation 2 and generation 3.
Two environments were listed, generation 2 and generation 3, since these are the ones that had
<literal>nix-repl</literal> installed in them.
</para>
<para>
The manifest.nix file contains metadata about the environment, such as
which derivations are installed. So that nix-env can list them, upgrade
or remove them. Guess what, the current manifest.nix can be found in
<literal>~/.nix-profile/manifest.nix</literal>.
The <filename>manifest.nix</filename> file contains metadata about the environment, such as
which derivations are installed. So that <literal>nix-env</literal> can list, upgrade
or remove them. And yet again, the current <filename>manifest.nix</filename> can be found at
<filename>~/.nix-profile/manifest.nix</filename>.
</para>
</section>
@ -233,16 +233,16 @@
<title>Closures</title>
<para>
The closures of a derivation is a list of all dependencies, recursively,
down to the bare minimum necessary to use that derivation.
The closures of a derivation is a list of all its dependencies, recursively,
including absolutely everything necessary to use that derivation.
</para>
<screen><xi:include href="./03/nix-store.txt" parse="text" /></screen>
<para>
Copying all those derivations to the nix store of another machine makes
you able to run "man" out of the box on that other machine. That's the
base of nix deployment, you can already foresee the potential when
Copying all those derivations to the Nix store of another machine makes
you able to run <literal>man</literal> out of the box on that other machine. That's the
base of deployment using Nix, and you can already foresee the potential when
deploying software in the cloud (hint:
<literal>nix-copy-closures</literal> and
<literal>nix-store --export</literal>).
@ -255,16 +255,16 @@
<screen><xi:include href="./03/nix-store-tree.txt" parse="text" /></screen>
<para>
With the above command, you can know exactly why a
<emphasis role="bold">runtime</emphasis> dependency, being it direct or
indirect, has been picked for a given derivation.
With the above command, you can find out exactly why a
<emphasis>runtime</emphasis> dependency, be it direct or
indirect, exists for a given derivation.
</para>
<para>
Same applies to environments of course. As an exercise run
<literal>nix-store -q --tree ~/.nix-profile</literal>, see that the
The same applies to environments. As an exercise, run
<command>nix-store -q --tree ~/.nix-profile</command>, and see that the
first children are direct dependencies of the user environment:
the installed derivations, and the manifest.nix.
the installed derivations, and the <filename>manifest.nix</filename>.
</para>
</section>
@ -272,41 +272,42 @@
<title>Dependency resolution</title>
<para>
There isn't anything like apt which solves a SAT problem in order to
satisfy dependencies with lower and upper bounds on versions. Because
there's no need. A derivation X depends on derivation Y, always.
There isn't anything like <literal>apt</literal> which solves a SAT problem in order to
satisfy dependencies with lower and upper bounds on versions. There's no need
for this because all the dependencies are static: if a derivation X depends on a derivation Y,
then it always depends on it. A version of X which depended on Z would be a different derivation.
</para>
</section>
<section>
<title>Fancy disrupt</title>
<title>Recovering the hard way</title>
<screen><xi:include href="./03/uninstall-all.txt" parse="text" /></screen>
<para>
Ops, that uninstalled all derivations from the environment, including
nix. We are not able to run nix-env, what now?
Oops, that uninstalled all derivations from the environment, including
Nix. That means we can't even run <literal>nix-env</literal>, what now?
</para>
<para>
Environments are a convenience for the user, but Nix is still there, in
the store!
Previously we got <literal>nix-env</literal> from the environment. Environments
are a convenience for the user, but Nix is still there in the store!
</para>
<para>
First pick one nix-1.7 derivation:
<literal>ls /nix/store/*nix-1.7</literal>, say
/nix/store/g21di262aql6xskx15z3qiw3zh3wmjlb-nix-1.7.
First, pick one <literal>nix-1.7</literal> derivation:
<command>ls /nix/store/*nix-1.7</command>, say
<filename>/nix/store/g21di262aql6xskx15z3qiw3zh3wmjlb-nix-1.7</filename>.
</para>
<para>
The first possibility is to rollback:
The first option is to rollback:
</para>
<screen><xi:include href="./03/nix-env-rollback.txt" parse="text" /></screen>
<para>
The second possibility is to install nix, thus creating a new generation:
The second option is to install Nix, thus creating a new generation:
</para>
<screen><xi:include href="./03/install.txt" parse="text" /></screen>
@ -316,9 +317,9 @@
<title>Channels</title>
<para>
So where are we getting packages from? We said something already in
<link linkend="install-on-your-running-system">pill 2</link>.
There's a list of channels from which we get packages, usually we use a
So where are we getting packages from? We said something about this already in the
<link linkend="install-on-your-running-system">second article</link>.
There's a list of channels from which we get packages, although usually we use a
single channel. The tool to manage channels is
<link xlink:href="http://nixos.org/nix/manual/#sec-nix-channel">nix-channel</link>.
</para>
@ -326,20 +327,23 @@
<screen><xi:include href="./03/channel-list.txt" parse="text" /></screen>
<para>
That's basically the contents of <literal>~/.nix-channels</literal>.
Note: <literal>~/.nix-channels</literal> is not a symlink to the
That's essentially the contents of <filename>~/.nix-channels</filename>.
</para>
<note><para>
<filename>~/.nix-channels</filename> is not a symlink to the
nix store!
</para></note>
<para>
To update the channel run <command>nix-channel --update</command>.
That will download the new Nix expressions (descriptions of the packages),
create a new generation of the channels profile and unpack it under
<filename>~/.nix-defexpr/channels</filename>.
</para>
<para>
To update the channel run <literal>nix-channel --update</literal>.
It will download the new nix expressions (descriptions of the packages),
create a new generation of the channels profile and unpack under
<literal>~/.nix-defexpr/channels</literal>.
</para>
<para>
That's much similar to apt-get update.
This is quite similar to <command>apt-get update</command>.
</para>
</section>
@ -348,32 +352,32 @@
<para>
We learned how to query the user environment and to manipulate it by
installing and uninstalling software. Upgrading software is as straight
as it gets by reading
installing and uninstalling software. Upgrading software is also straightforward,
as you can read in
<link xlink:href="http://nixos.org/nix/manual/#idm47361539520832">the manual</link>
(<literal>nix-env -u '*'</literal> will upgrade all packages in the
(<command>nix-env -u</command> will upgrade all packages in the
environment).
</para>
<para>
Everytime we change the environment, a new generation gets created.
Everytime we change the environment, a new generation is created.
Switching between generations is easy and immediate.
</para>
<para>
Then we queried the store. We inspected the dependencies and reverse
Then we leaned how to query the store. We inspected the dependencies and reverse
dependencies of store paths.
</para>
<para>
We still see symlinks to compose paths from the nix store, our lovely
We saw how symlinks are used to compose paths from the Nix store, a useful
trick.
</para>
<para>
Quick analogy with programming languages. You have the heap with all the
objects, that's the nix store. You have objects that point to other
objects, those are the derivations. Will be this the right path?
A quick analogy with programming languages: you have the heap with all the
objects, that corresponds to the Nix store. You have objects that point to other
objects, those correspond to derivations. This is a suggestive metaphor, but will it be the right path?
</para>
</section>
@ -382,9 +386,9 @@
<para>
...we will learn the basics of the Nix language. The Nix language is used
to describe how to build derivations, and it's the base for everything
else including NixOS. Therefore it's very important to understand the
syntax and the semantics.
to describe how to build derivations, and it's the basis for everything
else, including NixOS. Therefore it's very important to understand both the
syntax and the semantics of the language.
</para>
</section>
</chapter>

View file

@ -4,88 +4,90 @@
version="5.0"
xml:id="basics-of-language">
<title>The Basics of Language</title>
<title>The Basics of the Language</title>
<para>
Welcome to the fourth Nix pill. In the previous
<link linkend="enter-environment">third pill</link> we entered the Nix
environment. We installed software as user, managed the profile, switched
between generations, and queried the nix store. That's the very basics of
nix administration somehow.
Welcome to the fourth Nix pill. In the
<link linkend="enter-environment">previous article</link> we learned about Nix
environments. We installed software as a user, managed their profile, switched
between generations, and queried the Nix store. Those are the very basics of
system administration using Nix.
</para>
<para>
The
<link xlink:href="http://nixos.org/nix/manual/#chap-writing-nix-expressions">Nix language</link>
is used to write derivations. The
is used to write expressions that produce derivations. The
<link xlink:href="http://nixos.org/nix/manual/#sec-nix-build">nix-build</link>
tool is used to build derivations. Even as a system administrator that
tool is used to build a derivations from an expression. Even as a system administrator that
wants to customize the installation, it's necessary to master Nix. Using
Nix for your jobs means you get the features we saw in the previous pills
Nix for your jobs means you get the features we saw in the previous articles
for free.
</para>
<para>
The syntax is very uncommon thus looking at existing examples may lead to
thinking that there's a lot of magic behind. In reality, it's only about
writing utility functions for making things convenient.
The syntax of Nix is quite unfamiliar, so looking at existing examples may lead you to
think that there's a lot of magic happening. In reality, it's mostly about
writing utility functions to make things convenient.
</para>
<para>
On the other hand, this same syntax is great for describing packages.
On the other hand, the same syntax is great for describing packages, so learning the language
itself will pay off when writing package expressions.
</para>
<para>
<emphasis role="underline">Important</emphasis>: in Nix, everything is an
expression, there are no statements. This is common to many functional
<important><para>
In Nix, everything is an expression, there are no statements. This is common in functional
languages.
</para>
</para></important>
<para>
<emphasis role="underline">Important</emphasis>: values in Nix are
immutable.
</para>
<important><para>
Values in Nix are immutable.
</para></important>
<section>
<title>Value types</title>
<para>
We've installed nix-repl in the previous pill. If you didn't,
<literal>nix-env -i nix-repl</literal>. The nix-repl syntax is slightly
different than nix syntax when it comes to assigning variables, but no
worries. I prefer playing with nix-repl with you before cluttering your
mind with more complex expressions.
We've installed <literal>nix-repl</literal> in the previous pill. If you didn't,
<command>nix-env -i nix-repl</command>. The <literal>nix-repl</literal> syntax is slightly
different to Nix syntax when it comes to assigning variables, but it shouldn't
be confusing so long as you bear it in mind. I prefer to start with <literal>nix-repl</literal>
before cluttering your mind with more complex expressions.
</para>
<para>
Launch nix-repl. First of all, nix supports basic arithmetic operations:
+, -, and *. The integer division can be done with builtins.div.
Launch <literal>nix-repl</literal>. First of all, Nix supports basic arithmetic operations:
<literal>+</literal>, <literal>-</literal>, and <literal>*</literal>. Integer division can be
done with <literal>builtins.div</literal>.
</para>
<screen><xi:include href="./04/basics.txt" parse="text" /></screen>
<para>
Really, why doesn't nix have basic operations such as division? Because
it's not needed for creating packages. Nix is not a general purpose
You might wonder why Nix doesn't have basic operations such as integer division. The answer is
because it's not needed for creating packages. Nix is not a general purpose
language, it's a domain-specific language for writing packages.
</para>
<para>
Just think that builtins.div is not being used in the whole of our
nixpkgs repository: it's useless.
Just think - <literal>builtins.div</literal> is not used in the whole of the
nixpkgs repository: it's not actually useful if you are writing package expressions.
</para>
<para>
Other operators are ||, &amp;&amp; and ! for booleans, and relational
operators such as !=, ==, &lt;, >, &lt;=, >=. In Nix, &lt;, >, &lt;= and
>= are not much used. There are also other operators we will see in the
Other operators are <literal>||</literal>, <literal>&amp;&amp;</literal> and <literal>!</literal>
for booleans, and relational
operators such as <literal>!=</literal>, <literal>==</literal>, <literal>&lt;</literal>, <literal>></literal>,
<literal>&lt;=</literal>, <literal>>=</literal>. In Nix, <literal>&lt;</literal>, <literal>></literal>,
<literal>&lt;=</literal> and <literal>>=</literal> are not much used. There are also other operators we will see in the
course of this series.
</para>
<para>
Nix has integer (not floating point), string, path, boolean and null
<link xlink:href="http://nixos.org/nix/manual/#ssec-values">simple</link>
types. Then there are lists, sets and functions. These types are enough
types. Then there are also lists, sets and functions. These types are enough
to build an operating system.
</para>
@ -101,14 +103,14 @@
<screen><xi:include href="./04/relative-path.txt" parse="text" /></screen>
<para>
Nix parsed 2/3 as a relative path to the current directory. Paths are
parsed as long as there's a slash. Therefore to specify the current
directory, use <literal>./.</literal> In addition, Nix also parses urls.
Nix parsed <literal>2/3</literal> as a relative path to the current directory. Expressions will
be parsed as paths as long as there's a slash. Therefore to specify the current
directory, use <literal>./.</literal> In addition, Nix also parses urls specially.
</para>
<para>
Not all urls or paths can be parsed this way. If a syntax error occurs,
it's still possible to fallback to plain strings. Parsing urls and paths
it's still possible to fallback to plain strings. Literal urls and paths
are convenient for additional safety.
</para>
</section>
@ -117,15 +119,15 @@
<title>Identifier</title>
<para>
Not much to say, except that dash (-) is allowed in identifiers. That's
convenient since many packages use dash in its name. In fact:
There's not much to say here, except that dash (<literal>-</literal>) is allowed in identifiers. That's
convenient since many packages use dash in their names. In fact:
</para>
<screen><xi:include href="./04/dash.txt" parse="text" /></screen>
<para>
As you can see, <literal>a-b</literal> is parsed as identifier, not as
operation between a and b.
a subtraction.
</para>
</section>
@ -133,183 +135,180 @@
<title>Strings</title>
<para>
It's important to understand the syntax for strings. When reading Nix
expressions at the beginning, you may find dollars ($) ambiguous in their
usage. Strings are enclosed by double quotes ("), or two single quotes
('').
It's important to understand the syntax for strings. When learning to read Nix
expressions, you may find dollars (<literal>$</literal>) ambiguous, but they are very important .
Strings are enclosed by double quotes (<literal>"</literal>), or two single quotes (<literal>''</literal>).
</para>
<screen><xi:include href="./04/strings-basic.txt" parse="text" /></screen>
<para>
In python you can use also single quotes for strings like 'foo', but not
in Nix.
In other languages like Python you can also use single quotes for strings (e.g. <literal>'foo'</literal>),
but not in Nix.
</para>
<para>
It's possible to
<link xlink:href="http://nixos.org/nix/manual/#ssec-values">interpolate</link>
whole Nix expressions inside strings with ${...} and only with ${...},
not $foo or {$foo} or anything else.
whole Nix expressions inside strings with the <literal>${...}</literal> syntax and only that syntax,
not <literal>$foo</literal> or <literal>{$foo}</literal> or anything else.
</para>
<screen><xi:include href="./04/interpolate.txt" parse="text" /></screen>
<para>
Note: ignore the foo = "strval" assignment, it's nix-repl special syntax.
Note: ignore the <literal>foo = "strval"</literal> assignment, special syntax in <literal>nix-repl</literal>.
</para>
<para>
As said previously, you cannot mix integers and strings. You explicitly
need conversion. We'll see this later: function calls are another story.
As said previously, you cannot mix integers and strings. You need to explicitly
include conversions. We'll see this later: function calls are another story.
</para>
<para>
Using the syntax with two single quotes, it's useful for writing double
quotes inside strings instead of escaping:
Using the syntax with two single quotes is useful for writing double
quotes inside strings without needing to escape them:
</para>
<screen><xi:include href="./04/double-quotes.txt" parse="text" /></screen>
<para>
Escaping ${...} within double quoted strings is done with the backslash.
Within two single quotes, it's done with '':
Escaping <literal>${...}</literal> within double quoted strings is done with the backslash.
Within two single quotes, it's done with <literal>''</literal>:
</para>
<screen><xi:include href="./04/escaping.txt" parse="text" /></screen>
<para>
No other magic about strings for now.
</para>
</section>
<section>
<title>Lists</title>
<para>
Lists are a sequence of expressions delimited by space (not comma):
Lists are a sequence of expressions delimited by space (<emphasis>not</emphasis> comma):
</para>
<screen><xi:include href="./04/lists.txt" parse="text" /></screen>
<para>
Lists, like anything else in Nix, are immutable. Adding or removing
Lists, like everything else in Nix, are immutable. Adding or removing
elements from a list is possible, but will return a new list.
</para>
</section>
<section>
<title>Sets</title>
<title>Attribute sets</title>
<para>
Sets are an association between a string key and a Nix expression. Keys
can only be strings. When writing sets you can also use identifiers as
Attribute sets are an association between string keys and a Nix values. Keys
can only be strings. When writing attribute sets you can also use unquoted identifiers as
keys.
</para>
<screen><xi:include href="./04/set-basics.txt" parse="text" /></screen>
<para>
Note: here the string representation from nix is wrong, you can't write
{ 123 = "num"; } because 123 is not an identifier. You need semicolon
(;) after every key-value assignment.
</para>
<note><para>
Here the string representation printed in the repl is wrong, you can't write
<literal>{ 123 = "num"; }</literal>, because 123 is not an identifier. You also need a semicolon
(<literal>;</literal>) after every key-value assignment.
</para></note>
<para>
For those reading Nix expressions from nixpkgs: do not confuse sets with
For those reading Nix expressions from nixpkgs: do not confuse attribute sets with
argument sets used in functions.
</para>
<para>
To access elements in the set:
To access elements in the attribute set:
</para>
<screen><xi:include href="./04/set-access.txt" parse="text" /></screen>
<para>
Yes, you can use strings for non-identifiers to address keys in the set.
Yes, you can use strings for to address keys which aren't valid identifiers.
</para>
<para>
You cannot refer inside a set to elements of the same set:
Inside an attribute set you cannot normally refer to elements of the same attribute set:
</para>
<screen><xi:include href="./04/set-failed.txt" parse="text" /></screen>
<para>
To do so, use
<link xlink:href="http://nixos.org/nix/manual/#idm47361539166560">recursive sets</link>:
<link xlink:href="http://nixos.org/nix/manual/#idm47361539166560">recursive attribute sets</link>:
</para>
<screen><xi:include href="./04/set-recursive.txt" parse="text" /></screen>
<para>
This will be very convenient when defining packages.
This is very convenient when defining packages, which tend to be recursive attribute sets.
</para>
</section>
<section>
<title>If expression</title>
<title>If expressions</title>
<para>
Expressions, not statements.
These are expressions, not statements.
</para>
<screen><xi:include href="./04/if.txt" parse="text" /></screen>
<para>
You can't have only the "then" branch, you must specify also the "else"
You can't have only the <literal>then</literal> branch, you must specify also the <literal>else</literal>
branch, because an expression must have a value in all cases.
</para>
</section>
<section>
<title>Let expression</title>
<title>Let expressions</title>
<para>
This kind of expression is used to define local variables to inner
This kind of expression is used to define local variables for inner
expressions.
</para>
<screen><xi:include href="./04/let-basic.txt" parse="text" /></screen>
<para>
The syntax is: first assign variables, then "in" expression. The overall
result will be the final expression after "in".
The syntax is: first assign variables, then <literal>in</literal>, then an expression which can
use the defined variables. The value of the whole <literal>let</literal> expression will be
the value of the expression after the <literal>in</literal>.
</para>
<screen><xi:include href="./04/let-multiple.txt" parse="text" /></screen>
<para>
Let's write two let expressions, one inside the other:
Let's write two <literal>let</literal> expressions, one inside the other:
</para>
<screen><xi:include href="./04/let-nested.txt" parse="text" /></screen>
<para>
With let you cannot assign twice to the same variable. You can however
With <literal>let</literal> you cannot assign twice to the same variable. Howver, you can
shadow outer variables:
</para>
<screen><xi:include href="./04/let-multiple-assign.txt" parse="text" /></screen>
<para>
You cannot refer to variables in a let expression outside of it:
You cannot refer to variables in a <literal>let</literal> expression outside of it:
</para>
<screen><xi:include href="./04/let-scope.txt" parse="text" /></screen>
<para>
You can refer to variables in the let expression when assigning variables
like with recursive sets:
You can refer to variables in the <literal>let</literal> expression when assigning variables,
like with recursive attribute sets:
</para>
<screen><xi:include href="./04/let-reference.txt" parse="text" /></screen>
<para>
So beware when you want to refer to a variable from the outer scope, but
it's being defined in the current let expression. Same applies to
recursive sets.
it's also defined in the current let expression. The same applies to
recursive attribute sets.
</para>
</section>
@ -317,20 +316,20 @@
<title>With expression</title>
<para>
This kind of expression is something you hardly see in other languages.
Think of it like a more granular "using" of C++, or "from module import
*" from Python. You decide per-expression when to include symbols into
the scope.
This kind of expression is something you rarely see in other languages.
You can think of it like a more granular version of <literal>using</literal>
from C++, or <literal>from module import *</literal> from Python. You decide
per-expression when to include symbols into the scope.
</para>
<screen><xi:include href="./04/with-basic.txt" parse="text" /></screen>
<para>
That's it, it takes a set and includes symbols in the scope of the inner
expression. Of course, only valid identifiers from the set keys will be
included. If a symbol exists in the outer scope and also in the "with"
scope, it will <emphasis role="bold">not</emphasis> be shadowed.
You can however still refer to the set:
That's it, it takes an attribute set and includes symbols from it in the scope of the inner
expression. Of course, only valid identifiers from the keys of the set will be
included. If a symbol exists in the outer scope and would also be introduced by
the <literal>with</literal>, it will <emphasis>not</emphasis> be shadowed.
You can however still refer to the attribute set:
</para>
<screen><xi:include href="./04/with-scope.txt" parse="text" /></screen>
@ -347,9 +346,9 @@
<screen><xi:include href="./04/lazy.txt" parse="text" /></screen>
<para>
Since "a" is not needed, there's no error about division by zero, because
Since <literal>a</literal> is not needed, there's no error about division by zero, because
the expression is not in need to be evaluated. That's why we can have all
the packages defined here, yet access to specific packages very fast.
the packages defined on demand, yet have access to specific packages very quickly.
</para>
</section>