mirror of
https://github.com/NixOS/nix.dev.git
synced 2024-10-18 14:32:43 -04:00
Update sharing deps tutorial
This commit is contained in:
parent
bc863f7f85
commit
b038f6e117
|
@ -6,7 +6,7 @@
|
|||
|
||||
### What will you learn?
|
||||
|
||||
In this tutorial you'll learn how not to repeat yourself by sharing dependencies between 'default.nix`, which is responsible for building the project, and `shell.nix`, which is responsible for providing you with an environment to work in.
|
||||
In this tutorial you'll learn how not to repeat yourself by sharing dependencies between `default.nix`, which is responsible for building the project, and `shell.nix`, which is responsible for providing you with an environment to work in.
|
||||
|
||||
### How long will it take?
|
||||
|
||||
|
@ -14,25 +14,26 @@ This tutorial will take approximately 1 hour.
|
|||
|
||||
### What will you need?
|
||||
|
||||
This tutorial assumes you've seen a derivation (`mkDerivation`, `buildPythonApplication`, etc) before, and that you've seen `nix-shell` used to create shell environments.
|
||||
This tutorial assumes you're familiar with Nixpkgs build helpers (`mkDerivation`, `buildPythonApplication`, etc) and know how to create environments for `nix-shell`.
|
||||
While this tutorial uses Python as the language for the example project, no actual Python knowledge is requried.
|
||||
|
||||
## Setting the stage
|
||||
|
||||
Suppose you have a working build for your project in a `default.nix` file so that when you run `nix-build` it builds your project.
|
||||
It includes all of the dependencies needed to build it, but nothing more.
|
||||
Now suppose you wanted to bring in some tools during development, such as a linter, a code formatter, [git commit hooks][git_hooks], etc.
|
||||
Now suppose you wanted to bring in some tools during development, such as a linter, a code formatter, [git commit hooks], etc.
|
||||
|
||||
[git_hooks]: https://github.com/cachix/pre-commit-hooks.nix
|
||||
[git commit hooks]: https://github.com/cachix/pre-commit-hooks.nix
|
||||
|
||||
One solution could be to add those packages to your build.
|
||||
This would certainly work in a pinch, but now your build depends on packages that aren't necessary for it to actually build.
|
||||
This would certainly work in a pinch, but now your build depends on packages that aren't actually required.
|
||||
A better solution is to add those development packages to a shell environment so that the build dependencies stay as lean as possible.
|
||||
|
||||
However, now you need to define a `shell.nix` that not only provides your development packages, but can also build your project.
|
||||
In other words, you need a `shell.nix` that brings in all of the packages that your build depends on.
|
||||
You could certainly copy the build dependencies from `default.nix` and copy them into `shell.nix`, but this is less than ideal:
|
||||
your build dependencies are defined in multiple places, and aside from repeating yourself there's now the possiblity that the dependencies in `default.nix` and `shell.nix` may fall out of sync.
|
||||
your build dependencies would be defined in two places.
|
||||
Maintaining duplicate declarations in `default.nix` and `shell.nix` opens the possibility for them to diverge, producing surprising results.
|
||||
|
||||
There is a better way!
|
||||
|
||||
|
@ -86,10 +87,10 @@ app = "app:main"
|
|||
|
||||
This file tells Python how to build the project and what will execute when you run the executable called `app`.
|
||||
|
||||
For the Nix part of the project you'll create two files: `build.nix` and `default.nix`.
|
||||
The actual build recipe will be in `build.nix` and `default.nix` will import this file to perform the build.
|
||||
For the Nix part of the project you'll create two files: `package.nix` and `default.nix`.
|
||||
The actual build recipe will be in `package.nix` and `default.nix` will import this file to perform the build.
|
||||
|
||||
First create a `build.nix` file like this:
|
||||
First create a `package.nix` file like this:
|
||||
|
||||
```nix
|
||||
{
|
||||
|
@ -112,10 +113,12 @@ buildPythonApplication {
|
|||
|
||||
The Nix expression in this file is a _function_ that produces a derivation.
|
||||
This method of defining builds is a common design pattern in the Nix community, and is the format used throughout the `nixpkgs` repository.
|
||||
This particular derivation builds your Python application and ensures that `flask`, the library used to create the web application, is available at runtime for the application.
|
||||
This particular derivation builds your Python application and ensures that `flask`, the library used to create the web application, is available at runtime.
|
||||
|
||||
Note that on line 11 of the `build.nix` file the `src` attribute is set using `builtins.path`.
|
||||
This is a good habit to form because it will give your build a fixed name rather than simply inheriting the name of the parent directory.
|
||||
Note that on line 11 of the `package.nix` file the `src` attribute is set using `builtins.path`.
|
||||
This creates a [reproducible source path], and is a good habit to form.
|
||||
|
||||
[reproducible source path]: https://nix.dev/recipes/best-practices#reproducible-source-paths
|
||||
|
||||
Finally, create a `default.nix` that looks like this:
|
||||
|
||||
|
@ -124,14 +127,15 @@ let
|
|||
pkgs = import <nixpkgs> {};
|
||||
in
|
||||
{
|
||||
build = pkgs.python3Packages.callPackage ./build.nix {};
|
||||
build = pkgs.python3Packages.callPackage ./package.nix {};
|
||||
}
|
||||
```
|
||||
|
||||
The `callPackage` function reads the expression in `build.nix` to determine which inputs it needs (in this case, `buildPythonApplication`, `setuptools-scm`, and `flask`), then calls the expression with the inputs that were requested.
|
||||
You can read more about `callPackage` in the [Nix Pills][nix_pills_callpackage].
|
||||
The `python3Packages.callPackage` function determines which arguments the function in `package.nix` takes (in this case, `buildPythonApplication`, `setuptools-scm`, and `flask`) then calls the function in `package.nix` with the corresponding attributes from `python3Packages`.
|
||||
You can read more about the `callPackage` pattern in the [Nix Pills][nix_pills_callpackage].
|
||||
|
||||
Also note that this `default.nix` returns an attribute set with a single attribute called `build`.
|
||||
This allows adding more attributes later without breaking existing consumers.
|
||||
Try to build this project by running `nix-build -A build`
|
||||
|
||||
[nix_pills_callpackage]: https://nixos.org/guides/nix-pills/callpackage-design-pattern.html
|
||||
|
@ -144,12 +148,12 @@ Edit `default.nix` to look like this:
|
|||
```nix
|
||||
let
|
||||
pkgs = import <nixpkgs> {};
|
||||
build = pkgs.python3Packages.callPackage ./build.nix {};
|
||||
build = pkgs.python3Packages.callPackage ./package.nix {};
|
||||
in
|
||||
{
|
||||
inherit build;
|
||||
shell = pkgs.mkShell {
|
||||
inputsFrom = [build];
|
||||
inputsFrom = [ build ];
|
||||
packages = with pkgs.python3Packages; [
|
||||
black
|
||||
flake8
|
||||
|
@ -163,7 +167,7 @@ Let's break this all down.
|
|||
The `pkgs.mkShell` function produces a shell environment, and it's common to put the expression that calls this function in a `shell.nix` file by itself.
|
||||
However, doing so means that you to declare `pkgs = ...` a second time (first in `default.nix`, then again in `shell.nix`) and if you're pinning `nixpkgs` to a particular revision you may forget to update one of the declarations.
|
||||
|
||||
By putting the `build` declaration on line 3 you're able to use it throughout the attribute set that spans lines 5-14.
|
||||
By putting the `build` declaration in the `let` binding on line 3 you're able to use it throughout the attribute set that spans lines 5-14.
|
||||
Line 6 includes the `build` attribute in the attribute set.
|
||||
Lines 7-13 produce the shell environment for working on the project.
|
||||
|
||||
|
@ -198,7 +202,7 @@ $ which black
|
|||
These are the Nix store paths on the author's machine at the time of writing.
|
||||
You will likely see different store paths and versions depending on when you execute these commands and the architecture of the machine that the commands are executed on.
|
||||
|
||||
## Where to next?
|
||||
## Next steps
|
||||
- [Nixpkgs Manual - `mkShell`](https://nixos.org/manual/nixpkgs/stable/#sec-pkgs-mkShell)
|
||||
- [Nix Pills - callPackage Design Pattern][nix_pills_callpackage]
|
||||
- [Creating shell environments](https://nix.dev/tutorials/learning-journey/shell-dot-nix.html)
|
||||
|
|
Loading…
Reference in a new issue