<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id='chap-package-management'> <title>Package Management</title> <para>This chapter discusses how to do package management with Nix, i.e., how to obtain, install, upgrade, and erase packages. This is the “user’s” perspective of the Nix system — people who want to <emphasis>create</emphasis> packages should consult <xref linkend='chap-writing-nix-expressions' />.</para> <section><title>Basic package management</title> <para>The main command for package management is <link linkend="sec-nix-env"><command>nix-env</command></link>. You can use it to install, upgrade, and erase packages, and to query what packages are installed or are available for installation.</para> <para>In Nix, different users can have different “views” on the set of installed applications. That is, there might be lots of applications present on the system (possibly in many different versions), but users can have a specific selection of those active — where “active” just means that it appears in a directory in the user’s <envar>PATH</envar>. Such a view on the set of installed applications is called a <emphasis>user environment</emphasis>, which is just a directory tree consisting of symlinks to the files of the active applications. </para> <para>Components are installed from a set of <emphasis>Nix expressions</emphasis> that tell Nix how to build those packages, including, if necessary, their dependencies. There is a collection of Nix expressions called the Nix Package collection that contains packages ranging from basic development stuff such as GCC and Glibc, to end-user applications like Mozilla Firefox. (Nix is however not tied to the Nix Package collection; you could write your own Nix expressions based on it, or completely new ones.) You can download the latest version from <link xlink:href='http://nixos.org/nixpkgs/download.html' />.</para> <para>Assuming that you have downloaded and unpacked a release of Nix Packages, you can view the set of available packages in the release: <screen> $ nix-env -qaf nixpkgs-<replaceable>version</replaceable> '*' ant-blackdown-1.4.2 aterm-2.2 bash-3.0 binutils-2.15 bison-1.875d blackdown-1.4.2 bzip2-1.0.2 ...</screen> where <literal>nixpkgs-<replaceable>version</replaceable></literal> is where you’ve unpacked the release. The flag <option>-q</option> specifies a query operation; <option>-a</option> means that you want to show the “available” (i.e., installable) packages, as opposed to the installed packages; and <option>-f</option> <filename>nixpkgs-<replaceable>version</replaceable></filename> specifies the source of the packages. The argument <literal>'*'</literal> shows all installable packages. (The quotes are necessary to prevent shell expansion.) You can also select specific packages by name: <screen> $ nix-env -qaf nixpkgs-<replaceable>version</replaceable> gcc gcc-3.4.6 gcc-4.0.3 gcc-4.1.1</screen> </para> <para>It is also possible to see the <emphasis>status</emphasis> of available packages, i.e., whether they are installed into the user environment and/or present in the system: <screen> $ nix-env -qasf nixpkgs-<replaceable>version</replaceable> '*' ... -PS bash-3.0 --S binutils-2.15 IPS bison-1.875d ...</screen> The first character (<literal>I</literal>) indicates whether the package is installed in your current user environment. The second (<literal>P</literal>) indicates whether it is present on your system (in which case installing it into your user environment would be a very quick operation). The last one (<literal>S</literal>) indicates whether there is a so-called <emphasis>substitute</emphasis> for the package, which is Nix’s mechanism for doing binary deployment. It just means that Nix knows that it can fetch a pre-built package from somewhere (typically a network server) instead of building it locally.</para> <para>So now that we have a set of Nix expressions we can build the packages contained in them. This is done using <literal>nix-env -i</literal>. For instance, <screen> $ nix-env -f nixpkgs-<replaceable>version</replaceable> -i subversion</screen> will install the package called <literal>subversion</literal> (which is, of course, the <link xlink:href='http://subversion.tigris.org/'>Subversion version management system</link>).</para> <para>When you do this for the first time, Nix will start building Subversion and all its dependencies. This will take quite a while — typically an hour or two on modern machines. Fortunately, there is a faster way (so do a Ctrl-C on that install operation!): you just need to tell Nix that pre-built binaries of all those packages are available somewhere. This is done using the <command>nix-pull</command> command, which must be supplied with a URL containing a <emphasis>manifest</emphasis> describing what binaries are available. This URL should correspond to the Nix Packages release that you’re using. For instance, if you obtained a release from <link xlink:href='http://nixos.org/releases/nixpkgs/nixpkgs-0.12pre11712-4lrp7j8x' />, then you should do: <screen> $ nix-pull http://nixos.org/releases/nixpkgs/nixpkgs-0.12pre11712-4lrp7j8x/MANIFEST</screen> If you then issue the installation command, it should start downloading binaries from <systemitem class='fqdomainname'>nixos.org</systemitem>, instead of building them from source. This might still take a while since all dependencies must be downloaded, but on a reasonably fast connection such as an DSL line it’s on the order of a few minutes.</para> <para>Naturally, packages can also be uninstalled: <screen> $ nix-env -e subversion</screen> </para> <para>Upgrading to a new version is just as easy. If you have a new release of Nix Packages, you can do: <screen> $ nix-env -f nixpkgs-<replaceable>version</replaceable> -u subversion</screen> This will <emphasis>only</emphasis> upgrade Subversion if there is a “newer” version in the new set of Nix expressions, as defined by some pretty arbitrary rules regarding ordering of version numbers (which generally do what you’d expect of them). To just unconditionally replace Subversion with whatever version is in the Nix expressions, use <parameter>-i</parameter> instead of <parameter>-u</parameter>; <parameter>-i</parameter> will remove whatever version is already installed.</para> <para>You can also upgrade all packages for which there are newer versions: <screen> $ nix-env -f nixpkgs-<replaceable>version</replaceable> -u '*'</screen> </para> <para>Sometimes it’s useful to be able to ask what <command>nix-env</command> would do, without actually doing it. For instance, to find out what packages would be upgraded by <literal>nix-env -u '*'</literal>, you can do <screen> $ nix-env ... -u '*' --dry-run (dry run; not doing anything) upgrading `libxslt-1.1.0' to `libxslt-1.1.10' upgrading `graphviz-1.10' to `graphviz-1.12' upgrading `coreutils-5.0' to `coreutils-5.2.1'</screen> </para> </section> <section xml:id="sec-profiles"><title>Profiles</title> <para>Profiles and user environments are Nix’s mechanism for implementing the ability to allow different users to have different configurations, and to do atomic upgrades and rollbacks. To understand how they work, it’s useful to know a bit about how Nix works. In Nix, packages are stored in unique locations in the <emphasis>Nix store</emphasis> (typically, <filename>/nix/store</filename>). For instance, a particular version of the Subversion package might be stored in a directory <filename>/nix/store/dpmvp969yhdqs7lm2r1a3gng7pyq6vy4-subversion-1.1.3/</filename>, while another version might be stored in <filename>/nix/store/5mq2jcn36ldlmh93yj1n8s9c95pj7c5s-subversion-1.1.2</filename>. The long strings prefixed to the directory names are cryptographic hashes<footnote><para>160-bit truncations of SHA-256 hashes encoded in a base-32 notation, to be precise.</para></footnote> of <emphasis>all</emphasis> inputs involved in building the package — sources, dependencies, compiler flags, and so on. So if two packages differ in any way, they end up in different locations in the file system, so they don’t interfere with each other. <xref linkend='fig-user-environments' /> shows a part of a typical Nix store.</para> <figure xml:id='fig-user-environments'><title>User environments</title> <mediaobject> <imageobject> <imagedata fileref='figures/user-environments.png' format='PNG' /> </imageobject> </mediaobject> </figure> <para>Of course, you wouldn’t want to type <screen> $ /nix/store/dpmvp969yhdq...-subversion-1.1.3/bin/svn</screen> every time you want to run Subversion. Of course we could set up the <envar>PATH</envar> environment variable to include the <filename>bin</filename> directory of every package we want to use, but this is not very convenient since changing <envar>PATH</envar> doesn’t take effect for already existing processes. The solution Nix uses is to create directory trees of symlinks to <emphasis>activated</emphasis> packages. These are called <emphasis>user environments</emphasis> and they are packages themselves (though automatically generated by <command>nix-env</command>), so they too reside in the Nix store. For instance, in <xref linkend='fig-user-environments' /> the user environment <filename>/nix/store/5mq2jcn36ldl...-user-env</filename> contains a symlink to just Subversion 1.1.2 (arrows in the figure indicate symlinks). This would be what we would obtain if we had done <screen> $ nix-env -i subversion</screen> on a set of Nix expressions that contained Subversion 1.1.2.</para> <para>This doesn’t in itself solve the problem, of course; you wouldn’t want to type <filename>/nix/store/0c1p5z4kda11...-user-env/bin/svn</filename> either. That’s why there are symlinks outside of the store that point to the user environments in the store; for instance, the symlinks <filename>default-42-link</filename> and <filename>default-43-link</filename> in the example. These are called <emphasis>generations</emphasis> since every time you perform a <command>nix-env</command> operation, a new user environment is generated based on the current one. For instance, generation 43 was created from generation 42 when we did <screen> $ nix-env -i subversion mozilla</screen> on a set of Nix expressions that contained Mozilla and a new version of Subversion.</para> <para>Generations are grouped together into <emphasis>profiles</emphasis> so that different users don’t interfere with each other if they don’t want to. For example: <screen> $ ls -l /nix/var/nix/profiles/ ... lrwxrwxrwx 1 eelco ... default-42-link -> /nix/store/0c1p5z4kda11...-user-env lrwxrwxrwx 1 eelco ... default-43-link -> /nix/store/3aw2pdyx2jfc...-user-env lrwxrwxrwx 1 eelco ... default -> default-43-link</screen> This shows a profile called <filename>default</filename>. The file <filename>default</filename> itself is actually a symlink that points to the current generation. When we do a <command>nix-env</command> operation, a new user environment and generation link are created based on the current one, and finally the <filename>default</filename> symlink is made to point at the new generation. This last step is atomic on Unix, which explains how we can do atomic upgrades. (Note that the building/installing of new packages doesn’t interfere in any way with old packages, since they are stored in different locations in the Nix store.)</para> <para>If you find that you want to undo a <command>nix-env</command> operation, you can just do <screen> $ nix-env --rollback</screen> which will just make the current generation link point at the previous link. E.g., <filename>default</filename> would be made to point at <filename>default-42-link</filename>. You can also switch to a specific generation: <screen> $ nix-env --switch-generation 43</screen> which in this example would roll forward to generation 43 again. You can also see all available generations: <screen> $ nix-env --list-generations</screen></para> <para>Actually, there is another level of indirection not shown in the figure above. You generally wouldn’t have <filename>/nix/var/nix/profiles/<replaceable>some-profile</replaceable>/bin</filename> in your <envar>PATH</envar>. Rather, there is a symlink <filename>~/.nix-profile</filename> that points to your current profile. This means that you should put <filename>~/.nix-profile/bin</filename> in your <envar>PATH</envar> (and indeed, that’s what the initialisation script <filename>/nix/etc/profile.d/nix.sh</filename> does). This makes it easier to switch to a different profile. You can do that using the command <command>nix-env --switch-profile</command>: <screen> $ nix-env --switch-profile /nix/var/nix/profiles/my-profile $ nix-env --switch-profile /nix/var/nix/profiles/default</screen> These commands switch to the <filename>my-profile</filename> and default profile, respectively. If the profile doesn’t exist, it will be created automatically. You should be careful about storing a profile in another location than the <filename>profiles</filename> directory, since otherwise it might not be used as a root of the garbage collector (see <xref linkend='sec-garbage-collection' />).</para> <para>All <command>nix-env</command> operations work on the profile pointed to by <command>~/.nix-profile</command>, but you can override this using the <option>--profile</option> option (abbreviation <option>-p</option>): <screen> $ nix-env -p /nix/var/nix/profiles/other-profile -i subversion</screen> This will <emphasis>not</emphasis> change the <command>~/.nix-profile</command> symlink.</para> </section> <section xml:id='sec-garbage-collection'><title>Garbage collection</title> <para><command>nix-env</command> operations such as upgrades (<option>-u</option>) and uninstall (<option>-e</option>) never actually delete packages from the system. All they do (as shown above) is to create a new user environment that no longer contains symlinks to the “deleted” packages.</para> <para>Of course, since disk space is not infinite, unused packages should be removed at some point. You can do this by running the Nix garbage collector. It will remove from the Nix store any package not used (directly or indirectly) by any generation of any profile.</para> <para>Note however that as long as old generations reference a package, it will not be deleted. After all, we wouldn’t be able to do a rollback otherwise. So in order for garbage collection to be effective, you should also delete (some) old generations. Of course, this should only be done if you are certain that you will not need to roll back.</para> <para>To delete all old (non-current) generations of your current profile: <screen> $ nix-env --delete-generations old</screen> Instead of <literal>old</literal> you can also specify a list of generations, e.g., <screen> $ nix-env --delete-generations 10 11 14</screen> </para> <para>After removing appropriate old generations you can run the garbage collector as follows: <screen> $ nix-store --gc</screen> If you are feeling uncertain, you can also first view what files would be deleted: <screen> $ nix-store --gc --print-dead</screen> Likewise, the option <option>--print-live</option> will show the paths that <emphasis>won’t</emphasis> be deleted.</para> <para>There is also a convenient little utility <command>nix-collect-garbage</command>, which when invoked with the <option>-d</option> (<option>--delete-old</option>) switch deletes all old generations of all profiles in <filename>/nix/var/nix/profiles</filename>. So <screen> $ nix-collect-garbage -d</screen> is a quick and easy way to clean up your system.</para> <section xml:id="ssec-gc-roots"><title>Garbage collector roots</title> <para>The roots of the garbage collector are all store paths to which there are symlinks in the directory <filename><replaceable>prefix</replaceable>/nix/var/nix/gcroots</filename>. For instance, the following command makes the path <filename>/nix/store/d718ef...-foo</filename> a root of the collector: <screen> $ ln -s /nix/store/d718ef...-foo /nix/var/nix/gcroots/bar</screen> That is, after this command, the garbage collector will not remove <filename>/nix/store/d718ef...-foo</filename> or any of its dependencies.</para> <para>Subdirectories of <filename><replaceable>prefix</replaceable>/nix/var/nix/gcroots</filename> are also searched for symlinks. Symlinks to non-store paths are followed and searched for roots, but symlinks to non-store paths <emphasis>inside</emphasis> the paths reached in that way are not followed to prevent infinite recursion.</para> </section> </section> <section xml:id="sec-channels"><title>Channels</title> <para>If you want to stay up to date with a set of packages, it’s not very convenient to manually download the latest set of Nix expressions for those packages, use <command>nix-pull</command> to register pre-built binaries (if available), and upgrade using <command>nix-env</command>. Fortunately, there’s a better way: <emphasis>Nix channels</emphasis>.</para> <para>A Nix channel is just a URL that points to a place that contains a set of Nix expressions and a manifest. Using the command <link linkend="sec-nix-channel"><command>nix-channel</command></link> you can automatically stay up to date with whatever is available at that URL.</para> <para>You can “subscribe” to a channel using <command>nix-channel --add</command>, e.g., <screen> $ nix-channel --add http://nixos.org/releases/nixpkgs/channels/nixpkgs-unstable</screen> subscribes you to a channel that always contains that latest version of the Nix Packages collection. (Instead of <literal>nixpkgs-unstable</literal> you could also subscribe to <literal>nixpkgs-stable</literal>, which should have a higher level of stability, but right now is just outdated.) Subscribing really just means that the URL is added to the file <filename>~/.nix-channels</filename>. Right now there is no command to “unsubscribe”; you should just edit that file manually and delete the offending URL.</para> <para>To obtain the latest Nix expressions available in a channel, do <screen> $ nix-channel --update</screen> This downloads the Nix expressions in every channel (downloaded from <literal><replaceable>url</replaceable>/nixexprs.tar.bz2</literal>) and registers any available pre-built binaries in every channel (by <command>nix-pull</command>ing <literal><replaceable>url</replaceable>/MANIFEST</literal>). It also makes the union of each channel’s Nix expressions the default for <command>nix-env</command> operations. Consequently, you can then say <screen> $ nix-env -u '*'</screen> to upgrade all packages in your profile to the latest versions available in the subscribed channels.</para> </section> <section xml:id="sec-one-click"><title>One-click installs</title> <para>Often, when you want to install a specific package (e.g., from the <link xlink:href="http://nixos.org/nixpkgs/">Nix Packages collection</link>), subscribing to a channel is a bit cumbersome. And channels don’t help you at all if you want to install an older version of a package than the one provided by the current contents of the channel, or a package that has been removed from the channel. That’s when <emphasis>one-click installs</emphasis> come in handy: you can just go to the web page that contains the package, click on it, and it will be installed with all the necessary dependencies.</para> <para>For instance, you can go to <link xlink:href="http://hydra.nixos.org/jobset/nixpkgs/trunk/channel/latest" /> and click on any link for the individual packages for your platform. The first time you do this, your browser will ask what to do with <literal>application/nix-package</literal> files. You should open them with <filename>/nix/bin/nix-install-package</filename>. This will open a window that asks you to confirm that you want to install the package. When you answer <literal>Y</literal>, the package and all its dependencies will be installed. This is a binary deployment mechanism — you get packages pre-compiled for the selected platform type.</para> <para>You can also install <literal>application/nix-package</literal> files from the command line directly. See <xref linkend='sec-nix-install-package' /> for details.</para> </section> <section xml:id="sec-sharing-packages"><title>Sharing packages between machines</title> <para>Sometimes you want to copy a package from one machine to another. Or, you want to install some packages and you know that another machine already has some or all of those packages or their dependencies. In that case there are mechanisms to quickly copy packages between machines.</para> <para>The command <command linkend="sec-nix-copy-closure">nix-copy-closure</command> copies a Nix store path along with all its dependencies to or from another machine via the SSH protocol. It doesn’t copy store paths that are already present on the target machine. For example, the following command copies Firefox with all its dependencies: <screen> $ nix-copy-closure --to alice@itchy.example.org $(type -p firefox)</screen> See <xref linkend='sec-nix-copy-closure' /> for details.</para> <para>With <command linkend='refsec-nix-store-export'>nix-store --export</command> and <command linkend='refsec-nix-store-import'>nix-store --import</command> you can write the closure of a store path (that is, the path and all its dependencies) to a file, and then unpack that file into another Nix store. For example, <screen> $ nix-store --export $(type -p firefox) > firefox.closure</screen> writes the closure of Firefox to a file. You can then copy this file to another machine and install the closure: <screen> $ nix-store --import < firefox.closure</screen> Any store paths in the closure that are already present in the target store are ignored. It is also possible to pipe the export into another command, e.g. to copy and install a closure directly to/on another machine: <screen> $ nix-store --export $(type -p firefox) | bzip2 | \ ssh alice@itchy.example.org "bunzip2 | nix-store --import"</screen> But note that <command>nix-copy-closure</command> is generally more efficient in this example because it only copies paths that are not already present in the target Nix store.</para> <para>Finally, if you can mount the Nix store of a remote machine in your local filesystem, Nix can copy paths from the remote Nix store to the local Nix store <emphasis>on demand</emphasis>. For instance, suppose that you mount a remote machine containing a Nix store via <command xlink:href="http://fuse.sourceforge.net/sshfs.html">sshfs</command>: <screen> $ sshfs alice@itchy.example.org:/ /mnt</screen> You should then set the <envar>NIX_OTHER_STORES</envar> environment variable to tell Nix about this remote Nix store: <screen> $ export NIX_OTHER_STORES=/mnt/nix</screen> Then if you do any Nix operation, e.g. <screen> $ nix-env -i firefox</screen> and Nix has to build a path that it sees is already present in <filename>/mnt/nix</filename>, then it will just copy from there instead of building it from source.</para> </section> </chapter>