├── .binder ├── default.nix └── shell.nix ├── .github ├── CODEOWNERS └── workflows │ ├── pr.yml │ └── push.yml ├── .gitignore ├── README.md ├── default.nix ├── doc ├── Makefile ├── _config.yml ├── _static │ └── empty ├── conf.py ├── index.rst └── tutorials └── tutorials ├── 00-intro └── 01-getting-started.ipynb ├── 01-nix ├── 01-using-nix.ipynb └── 02-using-experimental-nix-command.ipynb ├── 02-python └── 01-using-and-creating-python-packages.ipynb └── 03-images └── 01-creating-a-docker-image.ipynb /.binder/default.nix: -------------------------------------------------------------------------------- 1 | # Binder uses the following environment. 2 | 3 | let 4 | tutorials = import ./..; 5 | in tutorials.runEnv 6 | -------------------------------------------------------------------------------- /.binder/shell.nix: -------------------------------------------------------------------------------- 1 | # Binder uses the following environment. 2 | 3 | let 4 | tutorials = import ./..; 5 | in tutorials.runEnv 6 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # CODEOWNERS file 2 | # 3 | # This file describes who owns what in this repository. 4 | # 5 | # New tutorials should have a code owner. 6 | # 7 | 8 | / @FRidh 9 | 10 | # Tutorials 11 | 12 | /tutorials/00-intro/01-getting-started @FRidh 13 | /tutorials/01-nix/using-nix.ipynb @FRidh 14 | /tutorials/01-nix/02-using-experimental-nix-command.ipynb 15 | /tutorials/02-python/01-using-and-creating-python-packages.ipynb.ipynb @FRidh 16 | /tutorials/03-images/01-creating-a-docker-image.ipynb @FRidh 17 | -------------------------------------------------------------------------------- /.github/workflows/pr.yml: -------------------------------------------------------------------------------- 1 | name: "PR tests" 2 | on: 3 | pull_request: 4 | jobs: 5 | tests: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Checkout 9 | uses: actions/checkout@v2 10 | - name: Install Nix 11 | uses: cachix/install-nix-action@v8 12 | - name: Build run-time and build-time deps 13 | run: nix-build -A runDeps -A devDeps 14 | - name: Compose documentation 15 | # Execute notebooks and join them into Sphinx docs 16 | run: nix-shell -A devEnv --run "make -C doc html" -------------------------------------------------------------------------------- /.github/workflows/push.yml: -------------------------------------------------------------------------------- 1 | name: "Tests" 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | tests: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v2 12 | - name: Install Nix 13 | uses: cachix/install-nix-action@v8 14 | - name: Build run-time and build-time deps 15 | run: nix-build -A runDeps -A devDeps 16 | - name: Compose documentation 17 | # Execute notebooks and join them into Sphinx docs 18 | run: nix-shell -A devEnv --run "make -C doc html" 19 | - name: Install SSH Client 20 | uses: webfactory/ssh-agent@v0.2.0 21 | with: 22 | ssh-private-key: ${{ secrets.DEPLOY_KEY }} 23 | - name: Deploy 24 | uses: JamesIves/github-pages-deploy-action@releases/v3 25 | with: 26 | SSH: true 27 | BRANCH: gh-pages # The branch the action should deploy to. 28 | FOLDER: doc/_build/html # The folder the action should deploy. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | doc/_build 2 | result* 3 | 4 | # TODO: ignore everything but notebooks of interest 5 | tutorials/*/.ipynb_checkpoints* 6 | tutorials/*/*.nix 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nix tutorials 2 | 3 | ![Tests](https://github.com/FRidh/nix-tutorials/workflows/Tests/badge.svg?branch=master) [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/FRidh/nix-tutorials/master) 4 | 5 | This repository contains tutorials for using Nix and Nixpkgs written as Jupyter notebooks. The tutorials 6 | 7 | - can be [read online](https://fridh.github.io/nix-tutorials) 8 | - or [used interactively](https://mybinder.org/v2/gh/FRidh/nix-tutorials/master) using Binder. 9 | 10 | ## Developing 11 | 12 | Warning: When working on these tutorials, please keep in mind that the notebooks are executed outside of a Nix build. Don't blindly evaluate them. 13 | 14 | To open the development environment shell 15 | 16 | nix-shell -A devEnv 17 | 18 | To open Jupyterlab for writing tutorials 19 | 20 | nix-shell -A devEnv --run "jupyter-lab" 21 | 22 | To build the the run-time dependencies used by Binder 23 | 24 | nix-build -A runDeps 25 | 26 | To compose the documentation 27 | 28 | nix-shell -A devEnv --run "make -C doc html" 29 | 30 | ## Contributing tutorials 31 | 32 | When contributing a new tutorial 33 | - add the tutorial add the correct place 34 | - add a reference in `doc/reference.rst` 35 | - add a code owner in `.github/CODEOWNERS` 36 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | # The environment that it used to execute the notebooks. 2 | let 3 | fetchTarballFromGitHub = {repo, owner, rev, sha256}: fetchTarball { 4 | url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; 5 | inherit sha256; 6 | }; 7 | 8 | nixpkgs = fetchTarballFromGitHub { 9 | owner = "NixOS"; 10 | repo = "nixpkgs"; 11 | rev = "64565f9d8ffe5bc3737ebd5f6b97756fac16d23b"; 12 | sha256 = "1n31xffqi1lfaf44k38z6bx7g4scj5nibx9zcnf06mqn4fzakgd6"; 13 | }; 14 | 15 | pkgs = import nixpkgs {}; 16 | 17 | python = pkgs.python3; 18 | 19 | pandoc = (import (fetchTarballFromGitHub { 20 | owner = "Mic92"; 21 | repo = "nur-packages"; 22 | rev = "0c3d7e8545a8f01e72fb79d3f17137267e9c20dc"; 23 | sha256 = "0c0dg4177kwmgfnpv15sbgd2x1l04bgddw9qnr8qsj4b8dpp945i"; 24 | }) {inherit pkgs;}).pandoc-bin; # Much smaller, faster CI 25 | 26 | # Binder runs Nix inside Docker. Sandboxing is not possible. 27 | nixConf = (pkgs.runCommand "nix.conf" {} '' 28 | mkdir -p $out/etc 29 | cat << EOF > $out/etc/nix.conf 30 | sandbox = false 31 | EOF 32 | ''); 33 | 34 | runDeps = [ 35 | (python.withPackages(ps: with ps; [ 36 | notebook # Needed for Binder 37 | ])) 38 | pkgs.nix 39 | nixConf 40 | ]; 41 | 42 | devDeps = [ 43 | (python.withPackages(ps: with ps; [ 44 | notebook # Needed for Binder 45 | jupyterlab # For development 46 | sphinx # For generating docs 47 | nbsphinx # For including the notebooks in docs 48 | ])) 49 | pkgs.nix 50 | pkgs.gitMinimal 51 | pandoc # Required by nbsphinx...sigh 52 | pkgs.gnumake 53 | ]; 54 | 55 | devEnv = pkgs.mkShell { 56 | name = "nix-tutorials-dev-env"; 57 | buildInputs = devDeps; 58 | }; 59 | 60 | runEnv = let 61 | env = pkgs.buildEnv { 62 | name = "nix-tutorials-run-env"; 63 | paths = runDeps; 64 | }; 65 | in pkgs.mkShell { 66 | # Make runEnv available for binder. 67 | # Do not include devEnv here because of closure size. 68 | # 69 | # We use mkShell, not because it runs hooks (we do not want that) 70 | # but because we simply need to be able to export an environment variable 71 | # which buildEnv doesn't allow. 72 | inherit (env) name; 73 | buildInputs = [ env ]; 74 | 75 | # Use a nix.conf file with binder 76 | NIX_CONF_DIR="${env}/etc"; 77 | }; 78 | 79 | in { 80 | inherit devDeps runDeps devEnv runEnv pkgs; 81 | } 82 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= -W 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /doc/_config.yml: -------------------------------------------------------------------------------- 1 | # Jekyll configuration. 2 | # By default Jekyll excludes folders prefixed with underscore. 3 | include: 4 | - _static 5 | - _sources -------------------------------------------------------------------------------- /doc/_static/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FRidh/nix-tutorials/3c61dbf20d2ac71ce3545dfc79daf93115bd7307/doc/_static/empty -------------------------------------------------------------------------------- /doc/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | # import os 14 | # import sys 15 | # sys.path.insert(0, os.path.abspath('.')) 16 | 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = 'nix-tutorials' 21 | copyright = '2020, Frederik Rietdijk' 22 | author = 'Frederik Rietdijk' 23 | 24 | # -- General configuration --------------------------------------------------- 25 | 26 | # Add any Sphinx extension module names here, as strings. They can be 27 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 28 | # ones. 29 | extensions = [ 30 | 'nbsphinx', 31 | ] 32 | 33 | master_doc = 'index' 34 | 35 | # Add any paths that contain templates here, relative to this directory. 36 | templates_path = ['_templates'] 37 | 38 | # List of patterns, relative to source directory, that match files and 39 | # directories to ignore when looking for source files. 40 | # This pattern also affects html_static_path and html_extra_path. 41 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '**.ipynb_checkpoints'] 42 | 43 | 44 | # -- Options for HTML output ------------------------------------------------- 45 | 46 | # The theme to use for HTML and HTML Help pages. See the documentation for 47 | # a list of builtin themes. 48 | # 49 | html_theme = 'nature' 50 | 51 | # Add any paths that contain custom static files (such as style sheets) here, 52 | # relative to this directory. They are copied after the builtin static files, 53 | # so a file named "default.css" will overwrite the builtin "default.css". 54 | html_static_path = ['_static'] 55 | html_extra_path = ['_config.yml'] 56 | 57 | # -- Get version information and date from Git ---------------------------- 58 | 59 | # Ugly, but because we're running outside of a `nix-build` it is OK-ish... 60 | try: 61 | from subprocess import check_output 62 | release = check_output(['git', 'describe', '--tags', '--always']) 63 | release = release.decode().strip() 64 | today = check_output(['git', 'show', '-s', '--format=%ad', '--date=short']) 65 | today = today.decode().strip() 66 | except Exception: 67 | release = '' 68 | today = '' 69 | 70 | 71 | # Amount of time per cell 72 | nbsphinx_timeout = 120 73 | 74 | # This is processed by Jinja2 and inserted before each notebook 75 | nbsphinx_prolog = r""" 76 | {% set docname = '' + env.doc2path(env.docname, base=None) %} 77 | .. raw:: html 78 | 79 |
80 |

81 | Interactive online version Binder badge. Generated from {{ docname|e }}. 82 |

83 |
84 | 85 | .. raw:: latex 86 | 87 | \nbsphinxstartnotebook{\scriptsize\noindent\strut 88 | \textcolor{gray}{The following section was generated from 89 | \sphinxcode{\sphinxupquote{\strut {{ docname | escape_latex }}}} \dotfill}} 90 | """ -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | .. nix-tutorials documentation master file, created by 2 | sphinx-quickstart on Sun Mar 15 19:42:59 2020. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Nix tutorials 7 | ============= 8 | 9 | This page links to various Nix tutorials. Each tutorial has a button at the top, allowing you to interactively run the tutorial. This also allows you to try out Nix if you haven't done so already! 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | :caption: Contents: 14 | 15 | tutorials/00-intro/01-getting-started 16 | tutorials/01-nix/01-using-nix 17 | tutorials/01-nix/02-using-experimental-nix-command 18 | tutorials/02-python/01-using-and-creating-python-packages 19 | tutorials/03-images/01-creating-a-docker-image 20 | -------------------------------------------------------------------------------- /doc/tutorials: -------------------------------------------------------------------------------- 1 | ../tutorials -------------------------------------------------------------------------------- /tutorials/00-intro/01-getting-started.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Getting started\n", 8 | "\n", 9 | "This page contains tutorials showing how to use Nix and Nixpkgs. The tutorials were written as [Jupyter Notebooks](https://jupyter-notebook-beginner-guide.readthedocs.io/en/latest/what_is_jupyter.html) so they can be used interactively. \n", 10 | "\n", 11 | "If you just want to read the tutorials instead of interactively use them, or you are already familiar with Jupyter Notebooks, then you can skip this tutorial and proceed with the actual tutorials regarding Nix and Nixpkgs.\n", 12 | "\n", 13 | "## What is a Jupyter Notebook?\n", 14 | "A Jupyter Notebook is a document that, aside from text and figures can also contain interactive content and code. \n", 15 | "A notebook consists of cells and each cell has a type, e.g. code or markup. \n", 16 | "Code cells, when executed, can generate output. The output is recorded in the notebook.\n", 17 | "\n", 18 | "## How about the static website?\n", 19 | "Now, the static website is generated by simply evaluating the notebooks and converting input and output to html. \n", 20 | "The interactive tutorials on the other hand are actual notebooks that are provisioned using Binder. \n", 21 | "\n", 22 | "## How do I use these tutorials interactively?\n", 23 | "Every tutorial on this page, including this one, has a \"launch binder\" button at the top. \n", 24 | "Press it, and after some time (it typically takes 10 seconds or more) a notebook is opened and you see the tutorial, minus output.\n", 25 | "\n", 26 | "To evaluate a cell, select a cell and press the \"Run\" button at the top. We can test this with the following cell" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": null, 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "! echo \"hello!\"" 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "metadata": {}, 41 | "source": [ 42 | "To evaluate more than one cell, e.g. all the cells, see the \"Cell\" menu at the top." 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": null, 48 | "metadata": {}, 49 | "outputs": [], 50 | "source": [ 51 | "! echo \"One\"" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": null, 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "! echo \"cell\"" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": null, 66 | "metadata": {}, 67 | "outputs": [], 68 | "source": [ 69 | "! echo \"of\"" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": null, 75 | "metadata": {}, 76 | "outputs": [], 77 | "source": [ 78 | "! echo \"many\"" 79 | ] 80 | }, 81 | { 82 | "cell_type": "markdown", 83 | "metadata": {}, 84 | "source": [ 85 | "## My notebook hangs, what now?\n", 86 | "\n", 87 | "It may happen the notebook hangs, there is no output or something weird is going on. If that's the case, open the \"Kernel\" menu and restart the kernel." 88 | ] 89 | }, 90 | { 91 | "cell_type": "markdown", 92 | "metadata": {}, 93 | "source": [ 94 | "## That's it!\n", 95 | "\n", 96 | "Now you know all there is to know about using the tutorials interactively. Good luck!" 97 | ] 98 | } 99 | ], 100 | "metadata": { 101 | "kernelspec": { 102 | "display_name": "Python 3", 103 | "language": "python", 104 | "name": "python3" 105 | }, 106 | "language_info": { 107 | "codemirror_mode": { 108 | "name": "ipython", 109 | "version": 3 110 | }, 111 | "file_extension": ".py", 112 | "mimetype": "text/x-python", 113 | "name": "python", 114 | "nbconvert_exporter": "python", 115 | "pygments_lexer": "ipython3", 116 | "version": "3.7.5" 117 | } 118 | }, 119 | "nbformat": 4, 120 | "nbformat_minor": 2 121 | } 122 | -------------------------------------------------------------------------------- /tutorials/01-nix/01-using-nix.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Using Nix\n", 8 | "\n", 9 | "This tutorial given an introduction to the basic `nix-*` commands." 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "## Building with `nix-build`\n", 17 | "\n", 18 | "The `nix-build` command is used for building recipes, also known as derivations. The resulting build artifacts are packages that can be installed or copied elsewhere.\n", 19 | "\n", 20 | "In the following example we create a `recipe.nix` file. In this case,\n", 21 | "our recipe is simple: we fetch the latest version of NixOS 19.09 and build\n", 22 | "a package from it, `hello`." 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": null, 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "%%file recipe.nix\n", 32 | "with import (fetchTarball \"channel:nixos-19.09\") {};\n", 33 | "hello" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": null, 39 | "metadata": {}, 40 | "outputs": [], 41 | "source": [ 42 | "! nix-build recipe.nix" 43 | ] 44 | }, 45 | { 46 | "cell_type": "markdown", 47 | "metadata": {}, 48 | "source": [ 49 | "The store path shows where the build is cached. A symbolic link to that path is also created" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": null, 55 | "metadata": {}, 56 | "outputs": [], 57 | "source": [ 58 | "! ls -l result" 59 | ] 60 | }, 61 | { 62 | "cell_type": "markdown", 63 | "metadata": {}, 64 | "source": [ 65 | "We can run the `hello` command that is provided by it" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": null, 71 | "metadata": {}, 72 | "outputs": [], 73 | "source": [ 74 | "! result/bin/hello" 75 | ] 76 | }, 77 | { 78 | "cell_type": "markdown", 79 | "metadata": {}, 80 | "source": [ 81 | "## Managing channels with `nix-channel`\n", 82 | "\n", 83 | "Nix has the concept of channels. A channel is essentially a location providing Nix expressions. The Nixpkgs project offers various channels.\n", 84 | "\n", 85 | "The following lists the currently configured channels" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": null, 91 | "metadata": {}, 92 | "outputs": [], 93 | "source": [ 94 | "! nix-channel --list" 95 | ] 96 | }, 97 | { 98 | "cell_type": "markdown", 99 | "metadata": {}, 100 | "source": [ 101 | "We will now install a channel" 102 | ] 103 | }, 104 | { 105 | "cell_type": "code", 106 | "execution_count": null, 107 | "metadata": {}, 108 | "outputs": [], 109 | "source": [ 110 | "! nix-channel --add https://github.com/NixOS/nixpkgs-channels/archive/nixos-19.09.tar.gz nixos" 111 | ] 112 | }, 113 | { 114 | "cell_type": "markdown", 115 | "metadata": {}, 116 | "source": [ 117 | "and can check it is configured" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": null, 123 | "metadata": {}, 124 | "outputs": [], 125 | "source": [ 126 | "! nix-channel --list" 127 | ] 128 | }, 129 | { 130 | "cell_type": "markdown", 131 | "metadata": {}, 132 | "source": [ 133 | "To use the channel, don't forget to update it. This will fetch the latest Nix expression on the location the channel points to." 134 | ] 135 | }, 136 | { 137 | "cell_type": "code", 138 | "execution_count": null, 139 | "metadata": {}, 140 | "outputs": [], 141 | "source": [ 142 | "! nix-channel --update" 143 | ] 144 | }, 145 | { 146 | "cell_type": "markdown", 147 | "metadata": {}, 148 | "source": [ 149 | "## Installing with `nix-env`\n", 150 | "\n", 151 | "Nix has the concept of profiles where users can install packages in. The `nix-env` command is used for installing packages. Users have a default profile, let's see if anything is installed for the current user" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": null, 157 | "metadata": {}, 158 | "outputs": [], 159 | "source": [ 160 | "! nix-env --query" 161 | ] 162 | }, 163 | { 164 | "cell_type": "markdown", 165 | "metadata": {}, 166 | "source": [ 167 | "We can now install `hello` in our profile. That way, the application will remain available. Let's install it from our `recipe.nix` file." 168 | ] 169 | }, 170 | { 171 | "cell_type": "code", 172 | "execution_count": null, 173 | "metadata": {}, 174 | "outputs": [], 175 | "source": [ 176 | "! nix-env -i -f recipe.nix" 177 | ] 178 | }, 179 | { 180 | "cell_type": "markdown", 181 | "metadata": {}, 182 | "source": [ 183 | "We can now see it is installed" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": null, 189 | "metadata": {}, 190 | "outputs": [], 191 | "source": [ 192 | "! nix-env --query" 193 | ] 194 | }, 195 | { 196 | "cell_type": "markdown", 197 | "metadata": {}, 198 | "source": [ 199 | "and that we can execute it" 200 | ] 201 | }, 202 | { 203 | "cell_type": "code", 204 | "execution_count": null, 205 | "metadata": {}, 206 | "outputs": [], 207 | "source": [ 208 | "! hello" 209 | ] 210 | }, 211 | { 212 | "cell_type": "markdown", 213 | "metadata": {}, 214 | "source": [ 215 | "We can install the same package but from the channel we configured. Note the package of interest, `hello`, is an attribute of the Nix expression that the channel `nixos` corresponds to" 216 | ] 217 | }, 218 | { 219 | "cell_type": "code", 220 | "execution_count": null, 221 | "metadata": {}, 222 | "outputs": [], 223 | "source": [ 224 | "! nix-env -iA nixos.hello" 225 | ] 226 | }, 227 | { 228 | "cell_type": "markdown", 229 | "metadata": {}, 230 | "source": [ 231 | "Instead of installing from a local file, we can also fetch an expression. It's possible to point to any Nix expression or archive containing Nix expressions." 232 | ] 233 | }, 234 | { 235 | "cell_type": "code", 236 | "execution_count": null, 237 | "metadata": {}, 238 | "outputs": [], 239 | "source": [ 240 | "! nix-env -iA hello -f https://github.com/NixOS/nixpkgs-channels/archive/nixos-19.09.tar.gz" 241 | ] 242 | }, 243 | { 244 | "cell_type": "markdown", 245 | "metadata": {}, 246 | "source": [ 247 | "In the example we actually fetched a channel, for which a short-hand notation exists" 248 | ] 249 | }, 250 | { 251 | "cell_type": "code", 252 | "execution_count": null, 253 | "metadata": {}, 254 | "outputs": [], 255 | "source": [ 256 | "! nix-env -iA hello -f \"channel:nixos-19.09\"" 257 | ] 258 | } 259 | ], 260 | "metadata": { 261 | "kernelspec": { 262 | "display_name": "Python 3", 263 | "language": "python", 264 | "name": "python3" 265 | }, 266 | "language_info": { 267 | "codemirror_mode": { 268 | "name": "ipython", 269 | "version": 3 270 | }, 271 | "file_extension": ".py", 272 | "mimetype": "text/x-python", 273 | "name": "python", 274 | "nbconvert_exporter": "python", 275 | "pygments_lexer": "ipython3", 276 | "version": "3.7.5" 277 | } 278 | }, 279 | "nbformat": 4, 280 | "nbformat_minor": 2 281 | } 282 | -------------------------------------------------------------------------------- /tutorials/01-nix/02-using-experimental-nix-command.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Using the experimental `nix` command\n", 8 | "\n", 9 | "The previous tutorial showed how to use Nix commands such as `nix-build` and `nix-env`. In this tutorial we'll use the new but still experimental `nix` command." 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "## Building a package with `nix build`\n", 17 | "\n", 18 | "Instead of `nix-build` it is now possible to build using `nix build`. Note that, contrary to `nix-build`, no out-link is created by default.\n", 19 | "\n", 20 | "In the following example we create a `recipe.nix` file. In this case, our recipe is simple: we fetch the latest version of NixOS 19.09 and build a package from it, `hello`." 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": 1, 26 | "metadata": {}, 27 | "outputs": [ 28 | { 29 | "name": "stdout", 30 | "output_type": "stream", 31 | "text": [ 32 | "Writing recipe.nix\n" 33 | ] 34 | } 35 | ], 36 | "source": [ 37 | "%%file recipe.nix\n", 38 | "with import (fetchTarball \"channel:nixos-19.09\") {};\n", 39 | "hello" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": 2, 45 | "metadata": {}, 46 | "outputs": [ 47 | { 48 | "name": "stdout", 49 | "output_type": "stream", 50 | "text": [ 51 | "\u001b[K[\u001b[32;1m13.3\u001b[0m MiB DL]\n" 52 | ] 53 | } 54 | ], 55 | "source": [ 56 | "! nix build -f recipe.nix" 57 | ] 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "metadata": {}, 62 | "source": [ 63 | "To obtain the path we can explicitly create a out-link" 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": 3, 69 | "metadata": {}, 70 | "outputs": [ 71 | { 72 | "name": "stdout", 73 | "output_type": "stream", 74 | "text": [ 75 | "\u001b[Klrwxrwxrwx 1 freddy users 54 Mar 28 11:34 result -> /nix/store/4w99qz14nsahk0s798a5rw5l7qk1zwwf-hello-2.10\n" 76 | ] 77 | } 78 | ], 79 | "source": [ 80 | "! nix build -f recipe.nix -o result\n", 81 | "! ls -l result" 82 | ] 83 | }, 84 | { 85 | "cell_type": "markdown", 86 | "metadata": {}, 87 | "source": [ 88 | "We can run the `hello` command that is provided by it" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 4, 94 | "metadata": {}, 95 | "outputs": [ 96 | { 97 | "name": "stdout", 98 | "output_type": "stream", 99 | "text": [ 100 | "Hello, world!\n" 101 | ] 102 | } 103 | ], 104 | "source": [ 105 | "! result/bin/hello" 106 | ] 107 | }, 108 | { 109 | "cell_type": "markdown", 110 | "metadata": {}, 111 | "source": [ 112 | "## Shell with specified packages with `nix run`\n", 113 | "\n", 114 | "The `nix run` command allows you to use a program temporarily; after closing the shell the program is \"gone\". Well, not really, it is still in the store but it can be garbage-collected again.\n", 115 | "\n", 116 | "The following one-liner calls `nix run`, tells it to use the Nix expressions found at `channel-nixos-20.03`, and then open a shell that has the Python 3 package. We also directly invoke `python3` using `--command` and tell `python3` to print `hello`." 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": 5, 122 | "metadata": {}, 123 | "outputs": [ 124 | { 125 | "name": "stdout", 126 | "output_type": "stream", 127 | "text": [ 128 | "\u001b[K[\u001b[32;1m13\u001b[0m copied (\u001b[32;1m99.4\u001b[0m MiB), \u001b[32;1m33.2\u001b[0m MiB DL]\n", 129 | "hello!\n" 130 | ] 131 | } 132 | ], 133 | "source": [ 134 | "! nix run --file channel:nixos-20.03 python3 --command python3 -c 'print(\"hello!\")'" 135 | ] 136 | } 137 | ], 138 | "metadata": { 139 | "kernelspec": { 140 | "display_name": "Python 3", 141 | "language": "python", 142 | "name": "python3" 143 | }, 144 | "language_info": { 145 | "codemirror_mode": { 146 | "name": "ipython", 147 | "version": 3 148 | }, 149 | "file_extension": ".py", 150 | "mimetype": "text/x-python", 151 | "name": "python", 152 | "nbconvert_exporter": "python", 153 | "pygments_lexer": "ipython3", 154 | "version": "3.7.5" 155 | } 156 | }, 157 | "nbformat": 4, 158 | "nbformat_minor": 2 159 | } 160 | -------------------------------------------------------------------------------- /tutorials/02-python/01-using-and-creating-python-packages.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Using and creating Python packages\n", 8 | "\n", 9 | "This tutorial will show how to use Python packages from Nixpkgs and create new ones. For reference material on Python in Nixpkgs, see the [Python section in the Nixpkgs manual](https://nixos.org/nixpkgs/manual#python)" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "## Python interpreters\n", 17 | "\n", 18 | "Nixpkgs contains recipes for various Python interpreters. Multiple versions are available of the official reference implementation also known as CPython. Interpreters can be installed into a profile, used as part of a build or used temporary in a `nix-shell` or `nix run` session. " 19 | ] 20 | }, 21 | { 22 | "cell_type": "markdown", 23 | "metadata": {}, 24 | "source": [ 25 | "## Python applications, libraries and environments\n", 26 | "\n", 27 | "In Nixpkgs a distinction is made between applications, libraries and environments. \n", 28 | "- Applications are programs for end-users such as Calibre the e-book manager. \n", 29 | "- Libraries are packages providing importable modules. Additionally, tools used for development of libraries are also considered libraries.\n", 30 | "- Environments are a Python interpreter along with libraries, typically used for development or as dependency for other programs.\n" 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "metadata": {}, 36 | "source": [ 37 | "## Python application\n", 38 | "\n", 39 | "Let's consider first a Python application, the version control system Mercurial. The following recipe shows how to build it. For build and run-time dependencies we use the recipes provided by Nixpkgs. We then create a builder function for building our package. Finally, we call it." 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": null, 45 | "metadata": {}, 46 | "outputs": [], 47 | "source": [ 48 | "%%file default.nix\n", 49 | "\n", 50 | "let\n", 51 | " nixpkgs = fetchTarball \"channel:nixos-20.03\";\n", 52 | " pkgs = import nixpkgs {};\n", 53 | "\n", 54 | " recipe = { python3, fetchurl }: \n", 55 | " with python3.pkgs;\n", 56 | " \n", 57 | " buildPythonApplication rec {\n", 58 | " pname = \"mercurial\";\n", 59 | " version = \"5.2.2\";\n", 60 | "\n", 61 | " src = fetchurl {\n", 62 | " url = \"https://mercurial-scm.org/release/mercurial-${version}.tar.gz\";\n", 63 | " sha256 = \"0fy00q0k4f0q64jjlnb7cl6m0sglivq9jgdddsp5sywc913zzigz\";\n", 64 | " };\n", 65 | " \n", 66 | " # By default tests are executed, but they need to be invoked differently for this package\n", 67 | " dontUseSetuptoolsCheck = true;\n", 68 | " };\n", 69 | "\n", 70 | "in pkgs.callPackage recipe {}\n" 71 | ] 72 | }, 73 | { 74 | "cell_type": "markdown", 75 | "metadata": {}, 76 | "source": [ 77 | "Let's build it. Note we suppress the build-output because of the amount." 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": null, 83 | "metadata": {}, 84 | "outputs": [], 85 | "source": [ 86 | "! nix-build --no-build-output" 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "metadata": {}, 92 | "source": [ 93 | "We can now execute `hg` directly from the store path" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": null, 99 | "metadata": {}, 100 | "outputs": [], 101 | "source": [ 102 | "! result/bin/hg --version" 103 | ] 104 | }, 105 | { 106 | "cell_type": "markdown", 107 | "metadata": {}, 108 | "source": [ 109 | "or install it in our profile" 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": null, 115 | "metadata": {}, 116 | "outputs": [], 117 | "source": [ 118 | "! nix-env -if ." 119 | ] 120 | }, 121 | { 122 | "cell_type": "markdown", 123 | "metadata": {}, 124 | "source": [ 125 | "bringing the executable onto `$PATH`." 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": null, 131 | "metadata": {}, 132 | "outputs": [], 133 | "source": [ 134 | "! hg --version" 135 | ] 136 | }, 137 | { 138 | "cell_type": "markdown", 139 | "metadata": {}, 140 | "source": [ 141 | "Creating a basic recipe for Mercurial was easy. The recipe used in Nixpkgs is however more elaborate." 142 | ] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "execution_count": null, 147 | "metadata": {}, 148 | "outputs": [], 149 | "source": [ 150 | "! nix run -f channel:nixos-20.03 curl --command curl --silent https://raw.githubusercontent.com/NixOS/nixpkgs/nixos-20.03/pkgs/applications/version-management/mercurial/default.nix | pygmentize" 151 | ] 152 | }, 153 | { 154 | "cell_type": "markdown", 155 | "metadata": {}, 156 | "source": [ 157 | "## Python library\n", 158 | "\n", 159 | "Python uses packages to distribute libraries called modules that are importable. In Nixpkgs all Python 3 libraries are in the attribute set `python3.pkgs`. The following example shows a recipe for the Python package `toolz`" 160 | ] 161 | }, 162 | { 163 | "cell_type": "code", 164 | "execution_count": null, 165 | "metadata": {}, 166 | "outputs": [], 167 | "source": [ 168 | "%%file toolz.nix\n", 169 | "\n", 170 | "{ lib, buildPythonPackage, fetchPypi }:\n", 171 | "\n", 172 | "buildPythonPackage rec {\n", 173 | " pname = \"toolz\";\n", 174 | " version = \"0.10.0\";\n", 175 | "\n", 176 | " src = fetchPypi {\n", 177 | " inherit pname version;\n", 178 | " sha256 = \"08fdd5ef7c96480ad11c12d472de21acd32359996f69a5259299b540feba4560\";\n", 179 | " };\n", 180 | "\n", 181 | " doCheck = false;\n", 182 | "\n", 183 | " meta = with lib; {\n", 184 | " homepage = https://github.com/pytoolz/toolz;\n", 185 | " description = \"List processing tools and functional utilities\";\n", 186 | " license = licenses.bsd3;\n", 187 | " maintainers = with maintainers; [ fridh ];\n", 188 | " };\n", 189 | "}" 190 | ] 191 | }, 192 | { 193 | "cell_type": "markdown", 194 | "metadata": {}, 195 | "source": [ 196 | "Applications or other libraries may want to use this package. In order to make that possible, we need to update the Python packages set to include this package" 197 | ] 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": null, 202 | "metadata": {}, 203 | "outputs": [], 204 | "source": [ 205 | "%%file mypython.nix\n", 206 | "\n", 207 | "let\n", 208 | " nixpkgs = fetchTarball \"channel:nixos-20.03\";\n", 209 | " pkgs = import nixpkgs {};\n", 210 | "\n", 211 | " mypython = pkgs.python3.override {\n", 212 | " self = mypython;\n", 213 | " packageOverrides = pself: psuper: {\n", 214 | " toolz = pself.callPackage ./toolz.nix {};\n", 215 | " };\n", 216 | " };\n", 217 | "in {\n", 218 | " inherit mypython;\n", 219 | "}" 220 | ] 221 | }, 222 | { 223 | "cell_type": "markdown", 224 | "metadata": {}, 225 | "source": [ 226 | "We now have a Python interpreter that has a package set that includes our package. Using this type of overriding we can also inject modifications to existing packages that will then be used by all dependents in the set.\n", 227 | "\n", 228 | "Let's build the package. " 229 | ] 230 | }, 231 | { 232 | "cell_type": "code", 233 | "execution_count": null, 234 | "metadata": {}, 235 | "outputs": [], 236 | "source": [ 237 | "! nix-build -A mypython.pkgs.toolz mypython.nix" 238 | ] 239 | }, 240 | { 241 | "cell_type": "markdown", 242 | "metadata": {}, 243 | "source": [ 244 | "The log shows the execution of several hooks that are responsible for building, installing and testing the package." 245 | ] 246 | }, 247 | { 248 | "cell_type": "markdown", 249 | "metadata": {}, 250 | "source": [ 251 | "## Environments\n", 252 | "\n", 253 | "Now that we know how to build a Python library, we want to use it in an environment, for example a development environment." 254 | ] 255 | }, 256 | { 257 | "cell_type": "markdown", 258 | "metadata": {}, 259 | "source": [ 260 | "The following expression creates a Python environment, quite similar to a `virtualenv` or `venv` that includes the interpreter, our package and another package, the test runner `pytest`" 261 | ] 262 | }, 263 | { 264 | "cell_type": "code", 265 | "execution_count": null, 266 | "metadata": {}, 267 | "outputs": [], 268 | "source": [ 269 | "%%file myenv.nix\n", 270 | "\n", 271 | "(import ./mypython.nix).mypython.withPackages(ps: with ps; [ toolz pytest ])" 272 | ] 273 | }, 274 | { 275 | "cell_type": "code", 276 | "execution_count": null, 277 | "metadata": {}, 278 | "outputs": [], 279 | "source": [ 280 | "! nix run -f myenv.nix --command python3 -c 'import toolz; print(toolz); import pytest; print(pytest)'" 281 | ] 282 | }, 283 | { 284 | "cell_type": "markdown", 285 | "metadata": {}, 286 | "source": [ 287 | "The `toolz` module, just like the `pytest` module can now be imported." 288 | ] 289 | }, 290 | { 291 | "cell_type": "markdown", 292 | "metadata": {}, 293 | "source": [ 294 | "How does an environment like this look like? If we build the expression we get the link to the store path" 295 | ] 296 | }, 297 | { 298 | "cell_type": "code", 299 | "execution_count": null, 300 | "metadata": {}, 301 | "outputs": [], 302 | "source": [ 303 | "! find $(nix-build myenv.nix) | tail" 304 | ] 305 | }, 306 | { 307 | "cell_type": "markdown", 308 | "metadata": {}, 309 | "source": [ 310 | "The environment is essentially a bunch of symbolic links to the packages we've included, as well as the interpreter. Executables are also wrapped so that all tools can find each other." 311 | ] 312 | } 313 | ], 314 | "metadata": { 315 | "kernelspec": { 316 | "display_name": "Python 3", 317 | "language": "python", 318 | "name": "python3" 319 | }, 320 | "language_info": { 321 | "codemirror_mode": { 322 | "name": "ipython", 323 | "version": 3 324 | }, 325 | "file_extension": ".py", 326 | "mimetype": "text/x-python", 327 | "name": "python", 328 | "nbconvert_exporter": "python", 329 | "pygments_lexer": "ipython3", 330 | "version": "3.7.5" 331 | } 332 | }, 333 | "nbformat": 4, 334 | "nbformat_minor": 2 335 | } 336 | -------------------------------------------------------------------------------- /tutorials/03-images/01-creating-a-docker-image.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Creating a Docker image\n", 8 | "\n", 9 | "In this tutorial we will create Docker images using Nix and the `dockerTools` functions in Nixpkgs." 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "## Create a simple image\n", 17 | "\n", 18 | "In the following example we create a Docker image that contains only Python." 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": null, 24 | "metadata": {}, 25 | "outputs": [], 26 | "source": [ 27 | "%%file default.nix\n", 28 | "\n", 29 | "with import (fetchTarball \"channel:nixos-20.03\") {};\n", 30 | "\n", 31 | "dockerTools.buildImage {\n", 32 | " name = \"python\";\n", 33 | " config = {\n", 34 | " Cmd = [\n", 35 | " \"${python3}/bin/python3 -c 'print(\\\"hello\\\")'\"\n", 36 | " ];\n", 37 | " };\n", 38 | "}" 39 | ] 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "metadata": {}, 44 | "source": [ 45 | "Let's build the image." 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": null, 51 | "metadata": {}, 52 | "outputs": [], 53 | "source": [ 54 | "! nix-build" 55 | ] 56 | }, 57 | { 58 | "cell_type": "markdown", 59 | "metadata": {}, 60 | "source": [ 61 | "Now we have our Docker image in the store. Note how small it is" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": null, 67 | "metadata": {}, 68 | "outputs": [], 69 | "source": [ 70 | "! du -h $(nix-build)" 71 | ] 72 | }, 73 | { 74 | "cell_type": "markdown", 75 | "metadata": {}, 76 | "source": [ 77 | "To run the image as a container, just load it with `docker load`\n", 78 | "```sh\n", 79 | "docker load < $(nix-build)\n", 80 | "```\n", 81 | "It's not shown here because the Docker daemon is not available." 82 | ] 83 | } 84 | ], 85 | "metadata": { 86 | "kernelspec": { 87 | "display_name": "Python 3", 88 | "language": "python", 89 | "name": "python3" 90 | }, 91 | "language_info": { 92 | "codemirror_mode": { 93 | "name": "ipython", 94 | "version": 3 95 | }, 96 | "file_extension": ".py", 97 | "mimetype": "text/x-python", 98 | "name": "python", 99 | "nbconvert_exporter": "python", 100 | "pygments_lexer": "ipython3", 101 | "version": "3.7.5" 102 | } 103 | }, 104 | "nbformat": 4, 105 | "nbformat_minor": 2 106 | } 107 | --------------------------------------------------------------------------------