1
0
Fork 0
mirror of https://github.com/NixOS/nix-pills synced 2024-09-19 04:00:13 -04:00

Replace \" with ".

This commit is contained in:
Noam Yorav-Raphael 2024-04-04 00:17:57 +03:00 committed by Jan Tojnar
parent cd05ea088e
commit 6f1bbb0d6c
14 changed files with 58 additions and 58 deletions

View file

@ -2,7 +2,7 @@
## Introduction ## Introduction
Welcome to the first post of the \"[Nix](https://nixos.org/nix) in pills\" series. Nix is a purely functional package manager and deployment system for POSIX. Welcome to the first post of the "[Nix](https://nixos.org/nix) in pills" series. Nix is a purely functional package manager and deployment system for POSIX.
There's a lot of documentation that describes what Nix, [NixOS](https://nixos.org/nixos) and related projects are. But the purpose of this post is to convince you to give Nix a try. Installing NixOS is not required, but sometimes I may refer to NixOS as a real world example of Nix usage for building a whole operating system. There's a lot of documentation that describes what Nix, [NixOS](https://nixos.org/nixos) and related projects are. But the purpose of this post is to convince you to give Nix a try. Installing NixOS is not required, but sometimes I may refer to NixOS as a real world example of Nix usage for building a whole operating system.

View file

@ -64,7 +64,7 @@ building path(s) `/nix/store/a7p1w3z2h8pl00ywvw6icr3g5l9vm5r7-<b>user-environmen
created 7 symlinks in user environment created 7 symlinks in user environment
</code></pre> </code></pre>
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. 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.
Generations can be switched and rolled back atomically, which makes them convenient for managing changes to your system. Generations can be switched and rolled back atomically, which makes them convenient for managing changes to your system.
@ -78,7 +78,7 @@ manifest.nix -> /nix/store/q8b5238akq07lj9gfb3qb5ycq4dxxiwm-<b>env-manifest.nix<
share -> /nix/store/ig31y9gfpp8pf3szdd7d4sf29zr7igbr-<b>nix-2.1.3</b>/share share -> /nix/store/ig31y9gfpp8pf3szdd7d4sf29zr7igbr-<b>nix-2.1.3</b>/share
</code></pre> </code></pre>
That nix-2.1.3 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 nix-2.1.3 store derivation in the profile by means of symbolic links. That nix-2.1.3 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 nix-2.1.3 store derivation in the profile by means of symbolic links.
The contents of this profile are special, because only one program has been installed in our profile, therefore e.g. the `bin` directory points to the only program which has been installed (Nix itself). The contents of this profile are special, because only one program has been installed in our profile, therefore e.g. the `bin` directory points to the only program which has been installed (Nix itself).
@ -86,7 +86,7 @@ But that's only the contents of the latest generation of our profile. In fact, `
In turn, that's a symlink to `default-1-link` in the same directory. Yes, that means it's the first generation of the `default` profile. In turn, that's a symlink to `default-1-link` in the same directory. Yes, that means it's the first generation of the `default` profile.
Finally, `default-1-link` is a symlink to the nix store \"user-environment\" derivation that you saw printed during the installation process. Finally, `default-1-link` is a symlink to the nix store "user-environment" derivation that you saw printed during the installation process.
We'll talk about `manifest.nix` more in the next article. We'll talk about `manifest.nix` more in the next article.

View file

@ -171,7 +171,7 @@ So where are we getting packages from? We said something about this already in t
$ nix-channel --list $ nix-channel --list
nixpkgs http://nixos.org/channels/nixpkgs-unstable nixpkgs http://nixos.org/channels/nixpkgs-unstable
If you're using NixOS, you may not see any output from the above command (if you're using the default), or you may see a channel whose name begins with \"nixos-\" instead of \"nixpkgs\". If you're using NixOS, you may not see any output from the above command (if you're using the default), or you may see a channel whose name begins with "nixos-" instead of "nixpkgs".
That's essentially the contents of `~/.nix-channels`. That's essentially the contents of `~/.nix-channels`.

View file

@ -97,7 +97,7 @@ As said previously, you cannot mix integers and strings. You need to explicitly
Using the syntax with two single quotes is useful for writing double quotes inside strings without needing to escape them: Using the syntax with two single quotes is useful for writing double quotes inside strings without needing to escape them:
nix-repl> ''test " test'' nix-repl> ''test " test''
"test \" test" "test " test"
nix-repl> ''${foo}'' nix-repl> ''${foo}''
"strval" "strval"

View file

@ -8,7 +8,7 @@ I remind you how to enter the Nix environment: `source ~/.nix-profile/etc/profil
## Nameless and single parameter ## Nameless and single parameter
Functions are anonymous (lambdas), and only have a single parameter. The syntax is extremely simple. Type the parameter name, then \"`:`\", then the body of the function. Functions are anonymous (lambdas), and only have a single parameter. The syntax is extremely simple. Type the parameter name, then "`:`", then the body of the function.
nix-repl> x: x*2 nix-repl> x: x*2
«lambda» «lambda»
@ -105,7 +105,7 @@ Also you can allow passing more attributes (**variadic**) than the expected ones
nix-repl> mul = { a, b, ... }: a*b nix-repl> mul = { a, b, ... }: a*b
nix-repl> mul { a = 3; b = 4; c = 2; } nix-repl> mul { a = 3; b = 4; c = 2; }
However, in the function body you cannot access the \"c\" attribute. The solution is to give a name to the given set with the **@-pattern**: However, in the function body you cannot access the "c" attribute. The solution is to give a name to the given set with the **@-pattern**:
nix-repl> mul = s@{ a, b, ... }: a*b*s.c nix-repl> mul = s@{ a, b, ... }: a*b*s.c
nix-repl> mul { a = 3; b = 4; c = 2; } nix-repl> mul { a = 3; b = 4; c = 2; }

View file

@ -87,7 +87,7 @@ Important: the hash of the out path is based solely on the input derivations in
Many things are empty in that `.drv`, however I'll write a summary of the [.drv format](http://nixos.org/~eelco/pubs/phd-thesis.pdf) for you: Many things are empty in that `.drv`, however I'll write a summary of the [.drv format](http://nixos.org/~eelco/pubs/phd-thesis.pdf) for you:
1. The output paths (there can be multiple ones). By default nix creates one out path called \"out\". 1. The output paths (there can be multiple ones). By default nix creates one out path called "out".
2. The list of input derivations. It's empty because we are not referring to any other derivation. Otherwise, there would be a list of other .drv files. 2. The list of input derivations. It's empty because we are not referring to any other derivation. Otherwise, there would be a list of other .drv files.
@ -174,7 +174,7 @@ Just like dependencies in other package managers, how do we refer to other packa
nix-repl> builtins.toString d nix-repl> builtins.toString d
"/nix/store/40s0qmrfb45vlh6610rk29ym318dswdr-myname" "/nix/store/40s0qmrfb45vlh6610rk29ym318dswdr-myname"
Nix does the \"set to string conversion\" as long as there is the `outPath` attribute (much like a toString method in other languages): Nix does the "set to string conversion" as long as there is the `outPath` attribute (much like a toString method in other languages):
nix-repl> builtins.toString { outPath = "foo"; } nix-repl> builtins.toString { outPath = "foo"; }
"foo" "foo"
@ -255,7 +255,7 @@ Aha! Nix added a dependency to our myname.drv, it's the coreutils.drv. Before do
## When is the derivation built ## When is the derivation built
Nix does not build derivations **during evaluation** of Nix expressions. In fact, that's why we have to do \":b drv\" in `nix repl`, or use nix-store -r in the first place. Nix does not build derivations **during evaluation** of Nix expressions. In fact, that's why we have to do ":b drv" in `nix repl`, or use nix-store -r in the first place.
An important separation is made in Nix: An important separation is made in Nix:
@ -275,8 +275,8 @@ We're walking through the fundamentals of Nix derivations, to understand how the
With the derivation function we provide a set of information on how to build a package, and we get back the information about where the package was built. Nix converts a set to a string when there's an `outPath`; that's very convenient. With that, it's easy to refer to other derivations. With the derivation function we provide a set of information on how to build a package, and we get back the information about where the package was built. Nix converts a set to a string when there's an `outPath`; that's very convenient. With that, it's easy to refer to other derivations.
When Nix builds a derivation, it first creates a .drv file from a derivation expression, and uses it to build the output. It does so recursively for all the dependencies (inputs). It \"executes\" the .drv files like a machine. Not much magic after all. When Nix builds a derivation, it first creates a .drv file from a derivation expression, and uses it to build the output. It does so recursively for all the dependencies (inputs). It "executes" the .drv files like a machine. Not much magic after all.
## Next pill ## Next pill
\...we will finally write our first **working** derivation. Yes, this post is about \"our first derivation\", but I never said it was a working one ;) \...we will finally write our first **working** derivation. Yes, this post is about "our first derivation", but I never said it was a working one ;)

View file

@ -114,7 +114,7 @@ What do we do here?
6. Once we're set up, compile and install. 6. Once we're set up, compile and install.
As you can see, there's no reference to \"hello\" in the builder anymore. It still makes several assumptions, but it's certainly more generic. As you can see, there's no reference to "hello" in the builder anymore. It still makes several assumptions, but it's certainly more generic.
Now let's rewrite `hello.nix`: Now let's rewrite `hello.nix`:
@ -226,7 +226,7 @@ Then we rewrite `hello.nix` as follows:
Finally! We got a very simple description of a package! Below are a couple of remarks that you may find useful as you're continuing to understand the nix language: Finally! We got a very simple description of a package! Below are a couple of remarks that you may find useful as you're continuing to understand the nix language:
- We assigned to pkgs the import that we did in the previous expressions in the \"with\". Don't be afraid, it's that straightforward. - We assigned to pkgs the import that we did in the previous expressions in the "with". Don't be afraid, it's that straightforward.
- The mkDerivation variable is a nice example of partial application, look at it as (`import ./autotools.nix`) `pkgs`. First we import the expression, then we apply the `pkgs` parameter. That will give us a function that accepts the attribute set `attrs`. - The mkDerivation variable is a nice example of partial application, look at it as (`import ./autotools.nix`) `pkgs`. First we import the expression, then we apply the `pkgs` parameter. That will give us a function that accepts the attribute set `attrs`.
@ -248,4 +248,4 @@ In Nix you create derivations stored in the nix store, and then you compose them
## Next pill ## Next pill
\...we will talk a little about runtime dependencies. Is the GNU hello world package self-contained? What are its runtime dependencies? We only specified build dependencies by means of using other derivations in the \"hello\" derivation. \...we will talk a little about runtime dependencies. Is the GNU hello world package self-contained? What are its runtime dependencies? We only specified build dependencies by means of using other derivations in the "hello" derivation.

View file

@ -30,7 +30,7 @@ Why are we looking at `.drv` files? Because the `hello.drv` file is the represen
## Digression about NAR files ## Digression about NAR files
The `NAR` format is the \"Nix ARchive\". This format was designed due to existing archive formats, such as `tar`, being insufficient. Nix benefits from deterministic build tools, but commonly used archivers lack this property: they add padding, they do not sort files, they add timestamps, and so on. This can result in directories containing bit-identical files turning into non-bit-identical archives, which leads to different hashes. The `NAR` format is the "Nix ARchive". This format was designed due to existing archive formats, such as `tar`, being insufficient. Nix benefits from deterministic build tools, but commonly used archivers lack this property: they add padding, they do not sort files, they add timestamps, and so on. This can result in directories containing bit-identical files turning into non-bit-identical archives, which leads to different hashes.
Thus the `NAR` format was developed as a simple, deterministic archive format. `NAR`s are used extensively within Nix, as we will see below. Thus the `NAR` format was developed as a simple, deterministic archive format. `NAR`s are used extensively within Nix, as we will see below.
@ -76,19 +76,19 @@ Even after reducing the rpath, the `hello` binary would still depend upon `gcc`
We will add a new phase to our autotools builder. The builder has six phases already: We will add a new phase to our autotools builder. The builder has six phases already:
1. The \"environment setup\" phase 1. The "environment setup" phase
2. The \"unpack phase\": we unpack the sources in the current directory (remember, Nix changes to a temporary directory first) 2. The "unpack phase": we unpack the sources in the current directory (remember, Nix changes to a temporary directory first)
3. The \"change directory\" phase, where we change source root to the directory that has been unpacked 3. The "change directory" phase, where we change source root to the directory that has been unpacked
4. The \"configure\" phase: `./configure` 4. The "configure" phase: `./configure`
5. The \"build\" phase: `make` 5. The "build" phase: `make`
6. The \"install\" phase: `make install` 6. The "install" phase: `make install`
Now we will add a new phase after the installation phase, which we call the \"fixup\" phase. At the end of the `builder.sh`, we append: Now we will add a new phase after the installation phase, which we call the "fixup" phase. At the end of the `builder.sh`, we append:
find $out -type f -exec patchelf --shrink-rpath '{}' \; -exec strip '{}' \; 2>/dev/null find $out -type f -exec patchelf --shrink-rpath '{}' \; -exec strip '{}' \; 2>/dev/null

View file

@ -2,11 +2,11 @@
Welcome to the 11th Nix pill. In the previous [10th pill](10-developing-with-nix-shell.md), we drew a parallel between the isolated build environment provided by `nix-build` and the isolated development shell provided by `nix-shell`. Using `nix-shell` allowed us to debug, modify, and manually build software using an environment that is almost identical to the one provided by `nix-build`. Welcome to the 11th Nix pill. In the previous [10th pill](10-developing-with-nix-shell.md), we drew a parallel between the isolated build environment provided by `nix-build` and the isolated development shell provided by `nix-shell`. Using `nix-shell` allowed us to debug, modify, and manually build software using an environment that is almost identical to the one provided by `nix-build`.
Today, we will stop focusing on packaging and instead look at a critical component of Nix: the garbage collector. When we use Nix tools, we are often building derivations. This includes `.drv` files as well as out paths. These artifacts go in the Nix store and take up space in our storage. Eventually we may wish to free up some space by removing derivations we no longer need. This is the focus of the 11th pill. By default, Nix takes a relatively conservative approach when automatically deciding which derivations are \"needed\". In this pill, we will also see a technique to conduct more destructive upgrade and deletion operations. Today, we will stop focusing on packaging and instead look at a critical component of Nix: the garbage collector. When we use Nix tools, we are often building derivations. This includes `.drv` files as well as out paths. These artifacts go in the Nix store and take up space in our storage. Eventually we may wish to free up some space by removing derivations we no longer need. This is the focus of the 11th pill. By default, Nix takes a relatively conservative approach when automatically deciding which derivations are "needed". In this pill, we will also see a technique to conduct more destructive upgrade and deletion operations.
## How does garbage collection work? ## How does garbage collection work?
Programming languages with garbage collectors use the concept of a set of \"garbage collector (or 'GC') roots\" to keep track of \"live\" objects. A GC root is an object that is always considered \"live\" (unless explicitly removed as GC root). The garbage collection process starts from the GC roots and proceeds by recursively marking object references as \"live\". All other objects can be collected and deleted. Programming languages with garbage collectors use the concept of a set of "garbage collector (or 'GC') roots" to keep track of "live" objects. A GC root is an object that is always considered "live" (unless explicitly removed as GC root). The garbage collection process starts from the GC roots and proceeds by recursively marking object references as "live". All other objects can be collected and deleted.
Instead of objects, Nix's garbage collection operates on store paths, [with the GC roots themselves being store paths](https://nixos.org/manual/nix/stable/package-management/garbage-collector-roots.html). . This approach is much more principled than traditional package managers such as `dpkg` or `rpm`, which may leave around unused packages or dangling files. Instead of objects, Nix's garbage collection operates on store paths, [with the GC roots themselves being store paths](https://nixos.org/manual/nix/stable/package-management/garbage-collector-roots.html). . This approach is much more principled than traditional package managers such as `dpkg` or `rpm`, which may leave around unused packages or dangling files.
@ -81,7 +81,7 @@ In fact, `nix-build` automatically adds the `result` symlink as a GC root. Note
The name of the GC root symlink is not important to us at this time. What is important is that such a symlink exists and points to `/home/nix/result`. This is called an **indirect GC root**. A GC root is considered indirect if its specification is outside of `/nix/var/nix/gcroots`. In this case, this means that the target of the `result` symlink will not be garbage collected. The name of the GC root symlink is not important to us at this time. What is important is that such a symlink exists and points to `/home/nix/result`. This is called an **indirect GC root**. A GC root is considered indirect if its specification is outside of `/nix/var/nix/gcroots`. In this case, this means that the target of the `result` symlink will not be garbage collected.
To remove a derivation considered \"live\" by an indirect GC root, there are two possibilities: To remove a derivation considered "live" by an indirect GC root, there are two possibilities:
- Remove the indirect GC root from `/nix/var/nix/gcroots/auto`. - Remove the indirect GC root from `/nix/var/nix/gcroots/auto`.
@ -97,7 +97,7 @@ The main source of software duplication in the nix store comes from GC roots, du
The same holds for profiles. Manipulating the `nix-env` profile will create further generations. Old generations refer to old software, thus increasing duplication in the nix store after an upgrade. The same holds for profiles. Manipulating the `nix-env` profile will create further generations. Old generations refer to old software, thus increasing duplication in the nix store after an upgrade.
Other systems typically \"forget\" everything about their previous state after an upgrade. With Nix, we can perform this type of upgrade (having Nix remove all old derivations, including old generations), but we do so manually. There are four steps to doing this: Other systems typically "forget" everything about their previous state after an upgrade. With Nix, we can perform this type of upgrade (having Nix remove all old derivations, including old generations), but we do so manually. There are four steps to doing this:
- First, we download a new version of the nixpkgs channel, which holds the description of all the software. This is done via `nix-channel --update`. - First, we download a new version of the nixpkgs channel, which holds the description of all the software. This is done via `nix-channel --update`.
@ -120,4 +120,4 @@ Garbage collection in Nix is a powerful mechanism to clean up your system. The `
## Next pill ## Next pill
In the next pill, we will package another project and introduce the \"inputs\" design pattern. We've only played with a single derivation until now; however we'd like to start organizing a small repository of software. The \"inputs\" pattern is widely used in nixpkgs; it allows us to decouple derivations from the repository itself and increase customization opportunities. In the next pill, we will package another project and introduce the "inputs" design pattern. We've only played with a single derivation until now; however we'd like to start organizing a small repository of software. The "inputs" pattern is widely used in nixpkgs; it allows us to decouple derivations from the repository itself and increase customization opportunities.

View file

@ -14,7 +14,7 @@ Over time, the `nixpkgs` repository evolved a particular structure. This structu
Different operating system distributions have different opinions about how package repositories should be organized. Systems like Debian scatter packages in several small repositories (which tends to make tracking interdependent changes more difficult, and hinders contributions to the repositories), while systems like Gentoo put all package descriptions in a single repository. Different operating system distributions have different opinions about how package repositories should be organized. Systems like Debian scatter packages in several small repositories (which tends to make tracking interdependent changes more difficult, and hinders contributions to the repositories), while systems like Gentoo put all package descriptions in a single repository.
Nix follows the \"single repository\" pattern by placing all descriptions of all packages into [nixpkgs](https://github.com/NixOS/nixpkgs). This approach has proven natural and attractive for new contributions. Nix follows the "single repository" pattern by placing all descriptions of all packages into [nixpkgs](https://github.com/NixOS/nixpkgs). This approach has proven natural and attractive for new contributions.
For the rest of this pill, we will adopt the single repository pattern. The natural implementation in Nix is to create a top-level Nix expression, followed by one expression for each package. The top-level expression imports and combines all package expressions in an attribute set mapping names to packages. For the rest of this pill, we will adopt the single repository pattern. The natural implementation in Nix is to create a top-level Nix expression, followed by one expression for each package. The top-level expression imports and combines all package expressions in an attribute set mapping names to packages.
@ -129,7 +129,7 @@ Taking a closer look at the above command, we see the following options:
- The -f option is used to specify the expression to use. In this case, the expression is the `./default.nix` of the current directory. - The -f option is used to specify the expression to use. In this case, the expression is the `./default.nix` of the current directory.
- The -i option stands for \"installation\". - The -i option stands for "installation".
- The -A is the same as above for `nix-build`. - The -A is the same as above for `nix-build`.
@ -147,7 +147,7 @@ The approach we've taken so far has a few problems:
Until now, our approach to addressing the above problems has been inadequate and required changing the nix expression to match our needs. With the `inputs` pattern, we provide another answer: let the user change the `inputs` of the expression. Until now, our approach to addressing the above problems has been inadequate and required changing the nix expression to match our needs. With the `inputs` pattern, we provide another answer: let the user change the `inputs` of the expression.
When we talk about \"the inputs of an expression\", we are referring to the set of derivations needed to build that expression. In this case: When we talk about "the inputs of an expression", we are referring to the set of derivations needed to build that expression. In this case:
- `mkDerivation` from `autotools`. Recall that `mkDerivation` has an implicit dependency on the toolchain. - `mkDerivation` from `autotools`. Recall that `mkDerivation` has an implicit dependency on the toolchain.
@ -172,7 +172,7 @@ Our goal is to make package expressions independent of the repository. To achiev
else []; else [];
} }
Recall that \"`{...}: ...`\" is the syntax for defining functions accepting an attribute set as argument; the above snippet just defines a function. Recall that "`{...}: ...`" is the syntax for defining functions accepting an attribute set as argument; the above snippet just defines a function.
We made `gd` and its dependencies optional. If `gdSupport` is true (which it is by default), we will fill `buildInputs` and `graphviz` will be built with `gd` support. Otherwise, if an attribute set is passed with `gdSupport = false;`, the build will be completed without `gd` support. We made `gd` and its dependencies optional. If `gdSupport` is true (which it is by default), we will fill `buildInputs` and `graphviz` will be built with `gd` support. Otherwise, if an attribute set is passed with `gdSupport = false;`, the build will be completed without `gd` support.
@ -214,22 +214,22 @@ Let's talk a closer look at the snippet and dissect the syntax:
- The entire expression in `default.nix` returns an attribute set with the keys `hello`, `graphviz`, and `graphvizCore`. - The entire expression in `default.nix` returns an attribute set with the keys `hello`, `graphviz`, and `graphvizCore`.
- With \"`let`\", we define some local variables. - With "`let`", we define some local variables.
- We bring `pkgs` into the scope when defining the package set. This saves us from having to type `pkgs`\" repeatedly. - We bring `pkgs` into the scope when defining the package set. This saves us from having to type `pkgs`" repeatedly.
- We import `hello.nix` and `graphviz.nix`, which each return a function. We call the functions with a set of inputs to get back the derivation. - We import `hello.nix` and `graphviz.nix`, which each return a function. We call the functions with a set of inputs to get back the derivation.
- The \"`inherit x`\" syntax is equivalent to \"`x = x`\". This means that the \"`inherit gd`\" here, combined with the above \"`with pkgs;`\", is equivalent to \"`gd = pkgs.gd`\". - The "`inherit x`" syntax is equivalent to "`x = x`". This means that the "`inherit gd`" here, combined with the above "`with pkgs;`", is equivalent to "`gd = pkgs.gd`".
The entire repository of this can be found at the [pill 12](https://gist.github.com/tfc/ca800a444b029e85a14e530c25f8e872) gist. The entire repository of this can be found at the [pill 12](https://gist.github.com/tfc/ca800a444b029e85a14e530c25f8e872) gist.
## Conclusion ## Conclusion
The \"`inputs`\" pattern allows our expressions to be easily customizable through a set of arguments. These arguments could be flags, derivations, or any other customizations enabled by the nix language. Our package expressions are simply functions: there is no extra magic present. The "`inputs`" pattern allows our expressions to be easily customizable through a set of arguments. These arguments could be flags, derivations, or any other customizations enabled by the nix language. Our package expressions are simply functions: there is no extra magic present.
The \"`inputs`\" pattern also makes the expressions independent of the repository. Given that we pass all needed information through arguments, it is possible to use these expressions in any other context. The "`inputs`" pattern also makes the expressions independent of the repository. Given that we pass all needed information through arguments, it is possible to use these expressions in any other context.
## Next pill ## Next pill
In the next pill, we will talk about the \"`callPackage`\" design pattern. This removes the tedium of specifying the names of the inputs twice: once in the top-level `default.nix`, and once in the package expression. With `callPackage`, we will implicitly pass the necessary inputs from the top-level expression. In the next pill, we will talk about the "`callPackage`" design pattern. This removes the tedium of specifying the names of the inputs twice: once in the top-level `default.nix`, and once in the package expression. With `callPackage`, we will implicitly pass the necessary inputs from the top-level expression.

View file

@ -41,7 +41,7 @@ We want `callPackage` to be a function of two arguments, with the following beha
## Implementing `callPackage` ## Implementing `callPackage`
In this section, we will build up the `callPackages` pattern from scratch. To start, we need a way to obtain the argument names of a function (in this case, the function that takes \"inputs\" and produces a package derivation) at runtime. This is because we want to automatically pass such arguments. In this section, we will build up the `callPackages` pattern from scratch. To start, we need a way to obtain the argument names of a function (in this case, the function that takes "inputs" and produces a package derivation) at runtime. This is because we want to automatically pass such arguments.
Nix provides a builtin function to do this: Nix provides a builtin function to do this:
@ -81,9 +81,9 @@ Let's dissect the above snippet:
- We define a `callPackage` variable which is a function. - We define a `callPackage` variable which is a function.
- The first parameter to the `callPackage` function is a set of name-value pairs that may appear in the argument set of the function we wish to \"autocall\". - The first parameter to the `callPackage` function is a set of name-value pairs that may appear in the argument set of the function we wish to "autocall".
- The second parameter is the function to \"autocall\" - The second parameter is the function to "autocall"
- We take the argument names of the function and intersect with the set of all values. - We take the argument names of the function and intersect with the set of all values.
@ -145,7 +145,7 @@ The reader should notice a magic thing happening. We're defining `pkgs` in terms
## Conclusion ## Conclusion
The \"`callPackage`\" pattern has simplified our repository considerably. We were able to import packages that require named arguments and call them automatically, given the set of all packages sourced from `nixpkgs`. The "`callPackage`" pattern has simplified our repository considerably. We were able to import packages that require named arguments and call them automatically, given the set of all packages sourced from `nixpkgs`.
We've also introduced some useful builtin functions that allows us to introspect Nix functions and manipulate attributes. These builtin functions are not usually used when packaging software, but rather act as tools for packaging. They are documented in the [Nix manual](https://nixos.org/manual/nix/stable/expressions/builtins.html). We've also introduced some useful builtin functions that allows us to introspect Nix functions and manipulate attributes. These builtin functions are not usually used when packaging software, but rather act as tools for packaging. They are documented in the [Nix manual](https://nixos.org/manual/nix/stable/expressions/builtins.html).
@ -153,4 +153,4 @@ Writing a repository in Nix is an evolution of writing convenient functions for
## Next pill ## Next pill
In the next pill, we will talk about the \"`override`\" design pattern. The `graphvizCore` seems straightforward. It starts from `graphviz.nix` and builds it without gd. In the next pill, we will consider another point of view: starting from `pkgs.graphviz` and disabling gd? In the next pill, we will talk about the "`override`" design pattern. The `graphvizCore` seems straightforward. It starts from `graphviz.nix` and builds it without gd. In the next pill, we will consider another point of view: starting from `pkgs.graphviz` and disabling gd?

View file

@ -52,13 +52,13 @@ We would like to avoid specifying the nix expression again. Instead, we would li
The difference is obvious, as well as the advantages of this approach. The difference is obvious, as well as the advantages of this approach.
Note: that `.override` is not a \"method\" in the OO sense as you may think. Nix is a functional language. The`.override` is simply an attribute of a set. Note: that `.override` is not a "method" in the OO sense as you may think. Nix is a functional language. The`.override` is simply an attribute of a set.
## The override implementation ## The override implementation
Recall that the graphviz attribute in the repository is the derivation returned by the function imported from `graphviz.nix`. We would like to add a further attribute named \"`override`\" to the returned set. Recall that the graphviz attribute in the repository is the derivation returned by the function imported from `graphviz.nix`. We would like to add a further attribute named "`override`" to the returned set.
Let's start by first creating a function \"`makeOverridable`\". This function will take two arguments: a function (that must return a set) and the set of original arguments to be passed to the function. Let's start by first creating a function "`makeOverridable`". This function will take two arguments: a function (that must return a set) and the set of original arguments to be passed to the function.
We will put this function in a `lib.nix`: We will put this function in a `lib.nix`:
@ -128,7 +128,7 @@ Now it would be nice if `callPackage` made our derivations overridable. This is
## Conclusion ## Conclusion
The \"`override`\" pattern simplifies the way we customize packages starting from an existing set of packages. This opens a world of possibilities for using a central repository like `nixpkgs` and defining overrides on our local machine without modifying the original package. The "`override`" pattern simplifies the way we customize packages starting from an existing set of packages. This opens a world of possibilities for using a central repository like `nixpkgs` and defining overrides on our local machine without modifying the original package.
We can dream of a custom, isolated `nix-shell` environment for testing graphviz with a custom gd: We can dream of a custom, isolated `nix-shell` environment for testing graphviz with a custom gd:
@ -140,4 +140,4 @@ The key in Nix is to find powerful yet simple abstractions in order to let the u
## Next pill ## Next pill
In the next pill, we will talk about Nix search paths. By \"search path\", we mean a place in the file system where Nix looks for expressions. This answers the question of where `<nixpkgs>` comes from. In the next pill, we will talk about Nix search paths. By "search path", we mean a place in the file system where Nix looks for expressions. This answers the question of where `<nixpkgs>` comes from.

View file

@ -1,6 +1,6 @@
# Nix Search Paths # Nix Search Paths
Welcome to the 15th Nix pill. In the previous [14th](14-override-design-pattern.md) pill we have introduced the \"override\" pattern, useful for writing variants of derivations by passing different inputs. Welcome to the 15th Nix pill. In the previous [14th](14-override-design-pattern.md) pill we have introduced the "override" pattern, useful for writing variants of derivations by passing different inputs.
Assuming you followed the previous posts, I hope you are now ready to understand `nixpkgs`. But we have to find `nixpkgs` in our system first! So this is the step: introducing some options and environment variables used by nix tools. Assuming you followed the previous posts, I hope you are now ready to understand `nixpkgs`. But we have to find `nixpkgs` in our system first! So this is the step: introducing some options and environment variables used by nix tools.
@ -14,7 +14,7 @@ In the shell for example, when you execute the command `ping`, it's being search
In nix it's exactly the same, however the syntax is different. Instead of just typing `ping` you have to type `<ping>`. Yes, I know\... you are already thinking of `<nixpkgs>`. However, don't stop reading here, let's keep going. In nix it's exactly the same, however the syntax is different. Instead of just typing `ping` you have to type `<ping>`. Yes, I know\... you are already thinking of `<nixpkgs>`. However, don't stop reading here, let's keep going.
What's `NIX_PATH` good for? Nix expressions may refer to an \"abstract\" path such as `<nixpkgs>`, and it's possible to override it from the command line. What's `NIX_PATH` good for? Nix expressions may refer to an "abstract" path such as `<nixpkgs>`, and it's possible to override it from the command line.
For ease we will use `nix-instantiate --eval` to do our tests. I remind you, [nix-instantiate](https://nixos.org/manual/nix/stable/command-ref/nix-instantiate.html) is used to evaluate nix expressions and generate the .drv files. Here we are not interested in building derivations, so evaluation is enough. It can be used for one-shot expressions. For ease we will use `nix-instantiate --eval` to do our tests. I remind you, [nix-instantiate](https://nixos.org/manual/nix/stable/command-ref/nix-instantiate.html) is used to evaluate nix expressions and generate the .drv files. Here we are not interested in building derivations, so evaluation is enough. It can be used for one-shot expressions.
@ -31,7 +31,7 @@ It's useless from a nix view point, but I think it's useful for your own underst
Great. At first attempt nix obviously said could not be found anywhere in the search path. Note that the -I option accepts a single directory. Paths added with -I take precedence over `NIX_PATH`. Great. At first attempt nix obviously said could not be found anywhere in the search path. Note that the -I option accepts a single directory. Paths added with -I take precedence over `NIX_PATH`.
The `NIX_PATH` also accepts a different yet very handy syntax: \"`somename=somepath`\". That is, instead of searching inside a directory for a name, we specify exactly the value of that name. The `NIX_PATH` also accepts a different yet very handy syntax: "`somename=somepath`". That is, instead of searching inside a directory for a name, we specify exactly the value of that name.
$ NIX_PATH="ping=/bin/ping" nix-instantiate --eval -E '<ping>' $ NIX_PATH="ping=/bin/ping" nix-instantiate --eval -E '<ping>'
/bin/ping /bin/ping
@ -82,14 +82,14 @@ In order to specify an alternative to `~/.nix-defexpr` it's possible to use the
replacing old `graphviz' replacing old `graphviz'
installing `graphviz' installing `graphviz'
Oh why did it say there's another derivation named graphviz? Because both `graphviz` and `graphvizCore` attributes in our repository have the name \"graphviz\" for the derivation: Oh why did it say there's another derivation named graphviz? Because both `graphviz` and `graphvizCore` attributes in our repository have the name "graphviz" for the derivation:
$ nix-env -f '<mypkgs>' -qaP $ nix-env -f '<mypkgs>' -qaP
graphviz graphviz graphviz graphviz
graphvizCore graphviz graphvizCore graphviz
hello hello hello hello
By default `nix-env` parses all derivations and uses the derivation names to interpret the command line. So in this case \"graphviz\" matched two derivations. Alternatively, like for `nix-build`, one can use -A to specify an attribute name instead of a derivation name: By default `nix-env` parses all derivations and uses the derivation names to interpret the command line. So in this case "graphviz" matched two derivations. Alternatively, like for `nix-build`, one can use -A to specify an attribute name instead of a derivation name:
$ nix-env -f '<mypkgs>' -i -A graphviz $ nix-env -f '<mypkgs>' -i -A graphviz
replacing old `graphviz' replacing old `graphviz'
@ -113,7 +113,7 @@ It may or may not make sense for you, or it's like that for historical reasons,
## Conclusion ## Conclusion
The `NIX_PATH` variable is the search path used by nix when using the angular brackets syntax. It's possible to refer to \"abstract\" paths inside nix expressions and define the \"concrete\" path by means of `NIX_PATH`, or the usual -I flag in nix tools. The `NIX_PATH` variable is the search path used by nix when using the angular brackets syntax. It's possible to refer to "abstract" paths inside nix expressions and define the "concrete" path by means of `NIX_PATH`, or the usual -I flag in nix tools.
We've also explained some of the uncommon `nix-env` behaviors for newcomers. The `nix-env` tool does not use `NIX_PATH` to search for packages, but rather for `~/.nix-defexpr`. Beware of that! We've also explained some of the uncommon `nix-env` behaviors for newcomers. The `nix-env` tool does not use `NIX_PATH` to search for packages, but rather for `~/.nix-defexpr`. Beware of that!

View file

@ -192,9 +192,9 @@ This demonstrates an important point. For the *current* package alone, it doesn'
## Setup Hooks ## Setup Hooks
As we mentioned above, sometimes dependencies need to influence the packages that use them in ways other than just *being* a dependency. [^1] `propagatedBuildInputs` can actually be seen as an example of this: packages using that are effectively \"injecting\" those dependencies as extra `buildInputs` in their downstream dependents. But in general, a dependency might affect the packages it depends on in arbitrary ways. *Arbitrary* is the key word here. We could teach `setup.sh` things about upstream packages like `pkg/nix-support/propagated-build-inputs`, but not arbitrary interactions. As we mentioned above, sometimes dependencies need to influence the packages that use them in ways other than just *being* a dependency. [^1] `propagatedBuildInputs` can actually be seen as an example of this: packages using that are effectively "injecting" those dependencies as extra `buildInputs` in their downstream dependents. But in general, a dependency might affect the packages it depends on in arbitrary ways. *Arbitrary* is the key word here. We could teach `setup.sh` things about upstream packages like `pkg/nix-support/propagated-build-inputs`, but not arbitrary interactions.
Setup hooks are the basic building block we have for this. In nixpkgs, a \"hook\" is basically a bash callback, and a setup hook is no exception. Let's look at the last part of `findInputs` we haven't covered: Setup hooks are the basic building block we have for this. In nixpkgs, a "hook" is basically a bash callback, and a setup hook is no exception. Let's look at the last part of `findInputs` we haven't covered:
findInputs() { findInputs() {
local pkg=$1 local pkg=$1
@ -237,7 +237,7 @@ Functions listed in `envHooks` are applied to every package passed to `addToEnv`
anEnvHook() { anEnvHook() {
local pkg=$1 local pkg=$1
echo "I'm depending on \"$pkg\"" echo "I'm depending on "$pkg""
} }
envHooks+=(anEnvHook) envHooks+=(anEnvHook)