diff --git a/source/tutorials/ad-hoc-developer-environments.md b/source/tutorials/ad-hoc-developer-environments.md index b9a20b411..3d9a5ceef 100644 --- a/source/tutorials/ad-hoc-developer-environments.md +++ b/source/tutorials/ad-hoc-developer-environments.md @@ -128,27 +128,6 @@ There are two things going on here: 1. The `--pure` flag makes sure that the bash environment from your system is not inherited. That means only the `git` that Nix installed is available inside the shell. This is useful for one-liners and scripts that run, for example, within a CI environment. While developing, however, we'd like to have our editor around and a bunch of other things. Therefore we might skip the flag for development environments but use it in build ones. 2. The `-I` flag pins the Nixpkgs revision to an **exact Git revision**, leaving no doubt about which exact version of Nix packages will be used. -## Reproducible executables - -Finally, we can wrap scripts with Nix to provide a reproducible shell environment that we can commit to a Git repository and share with strangers online. As long as they have Nix installed, they'll be able to execute the script without worrying about manually installing (and later uninstalling) dependencies at all. - -```python -#! /usr/bin/env nix-shell -#! nix-shell --pure -i python -p "python38.withPackages (ps: [ ps.django ])" -#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/2a601aafdc5605a5133a2ca506a34a3a73377247.tar.gz - -import django - -print(django) -``` - -This is essentially the same example as in the previous section, but this time declaratively source controlled! All of the required Nix commands are included as `#!` shebang headers in the script itself. - -:::{note} -The multiline shebang format is a feature of [nix-shell](https://nixos.org/manual/nix/stable/command-ref/nix-shell.html#use-as-a--interpreter). -All the subsequent `#! nix-shell` lines are used to build up the shell's configuration before building the shell and executing the body of the script. -::: - ## Next steps We've only covered the bare essentials of Nix here. Once you're comfortable with these examples, take a look at: @@ -160,3 +139,4 @@ We've only covered the bare essentials of Nix here. Once you're comfortable with - See `man nix-shell` for all of the options. - To quickly setup a Nix project read through [Getting started Nix template](https://github.com/nix-dot-dev/getting-started-nix-template). +- {ref}`reproducible-scripts` to see how to use `nix-shell` as a shebang. diff --git a/source/tutorials/index.md b/source/tutorials/index.md index 0004ce33f..7e346274e 100644 --- a/source/tutorials/index.md +++ b/source/tutorials/index.md @@ -5,6 +5,7 @@ install-nix.md ad-hoc-developer-environments.md +reproducible-scripts.md nix-language.md towards-reproducibility-pinning-nixpkgs.md declarative-and-reproducible-developer-environments.md diff --git a/source/tutorials/nix-language.md b/source/tutorials/nix-language.md index ef25812de..c50879216 100644 --- a/source/tutorials/nix-language.md +++ b/source/tutorials/nix-language.md @@ -75,7 +75,7 @@ Read detailed explanations if you want to make sure you fully understand the exa - Familiarity with software development - Familiarity with Unix shell, to read command line examples -- A [Nix installation](./install-nix) to run the examples +- A {ref}`Nix installation ` to run the examples ### How to run the examples? diff --git a/source/tutorials/reproducible-scripts.md b/source/tutorials/reproducible-scripts.md new file mode 100644 index 000000000..b40c78af4 --- /dev/null +++ b/source/tutorials/reproducible-scripts.md @@ -0,0 +1,79 @@ +(reproducible-scripts)= + +# Reproducible interpreted scripts + +In this tutorial, you will learn how to use Nix to create and run reproducible interpreted scripts. + +## Requirements + +- A working {ref}`Nix installation ` +- Familiarity with [Bash] + +## A trivial script with non-trivial dependencies + +Take the following script, which fetches the content XML of a URL, converts it to JSON, and formats it for better readability: + +```bash +#! /bin/bash + +curl https://github.com/NixOS/nixpkgs/releases.atom | xml2json | jq . +``` + +It requires the programs `curl`, `xml2json`, and `jq`. +It also requires the `bash` interpreter. +If any of these dependencies are not present on the system running the script, it will fail partially or altogether. + +With Nix, we can declare all dependencies explicitly, and produce a script that will always run on any machine that supports Nix and the required packages taken from Nixpkgs. + +## The script + +A [shebang] is the first line of a script starting with `#!`. +It determines which program to use for running the script. + +[Bash]: https://www.gnu.org/software/bash/ +[shebang]: https://en.m.wikipedia.org/wiki/Shebang_(Unix) + +We will use the shebang line `#! /usr/bin/env nix-shell`. + +`/usr/bin/env` is a program available on most modern Unix-like operating systems. +It takes a command name as argument and will run the first executable by that name it finds in the directories listed in the environment variable `$PATH`. + +We use [`nix-shell` as a shebang interpreter]. +It takes the following parameters relevant for our use case: + +- `-i` tells which program to use for interpreting the rest of the file +- `-p` lists packages that should be present in the interpreter's environment +- `-I` explicitly sets [the search path] for packages + +[`nix-shell` as a shebang interpreter]: https://nixos.org/manual/nix/stable/command-ref/nix-shell.html#use-as-a--interpreter +[the search path]: https://nixos.org/manual/nix/unstable/command-ref/opt-common.html#opt-I + +Create a file named `nixpkgs-releases.sh` with the following content: + +```shell +#!/usr/bin/env nix-shell +#! nix-shell -i bash +#! nix-shell -p curl jq python3Packages.xmljson +#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/2a601aafdc5605a5133a2ca506a34a3a73377247.tar.gz + +curl https://github.com/NixOS/nixpkgs/releases.atom | xml2json | jq . +``` + +We specify `bash` as the interpreter. + +The command `xml2json` is provided by the package `python3Packages.xmljson`, while the commands `jq` and `curl` are provided by packages of the same name. + +The parameter of `-I` refers to a specific Git commit of the Nixpkgs repository. +This ensures that the script will always run with the exact same packages versions, everywhere. + +Make the script executable: + + ```console + chmod +x nixpkgs-releases.sh + ``` + +Run the script: + +```console +./nixpkgs-releases.sh +```