Skip to content

Latest commit

Β 

History

History
855 lines (570 loc) Β· 14.6 KB

slides.md

File metadata and controls

855 lines (570 loc) Β· 14.6 KB
theme highlighter lineNumbers info drawings transition canvasWidth
apple-basic
shiki
false
## Nix
persist
slide-left
700
<style> .slidev-code { line-height: 1 !important; } </style>

Moderator Slide

Preparations

Install nix with flakes and new commands enabled. Add a default repository for repl demos:

nix-channel --add https://channels.nixos.org/nixos-23.05 nixpkgs
nix-channel --update
alacritty -o font.size=20 --working-directory demo -e nix repl

layout: quote

"Yes, Fabian, nix does sounds amazing, but again,

Β Β I'll wait for your nix talk before I get started."

β€” Anonymous 😁


layout: statement

So welcome to the

ultimate
comprehensive
nix talk

ℒ️. Sorry!


layout: statement

Once upon a time in 2006...

The Purely Functional Software Deployment Model

Β 
Eelco Dolstra, PhD Thesis


🎯 My Goals for Today: You...

  • are introduced you to the Nix universe
  • understand how NixOS is built up
  • know how to setup NixOS and nix in your projects
  • know where to look up stuff

🎯 What we'll take a look at today

  • nix (the tool)
  • Nix (the expression language)
  • nixpkgs
  • NixOS
  • Nix Flakes

Β 
πŸ€” What are they?
πŸ€” How on earth are they all connected?


layout: section

With no further ado: nix.


nix is a functional build tool

πŸ“₯ Input:

  • Build instruction (defined in Nix)
  • Source code
  • Build tools / script

πŸ“€ Output:

  • Build results (immutable)

Easy as that!


πŸ€“ The nix manual states that:

Nix is a purely functional package manager.
Β 
This means that it treats packages like values [...] β€”
they are built by functions that don’t have side-effects,
and they never change after they have been built

  • No side effects
  • Results are immutable

Q: So how are build results stored?

A: The Nix Store!

Nix stores packages in [...] the directory /nix/store,
where each package has its own unique subdirectory such as

/nix/store/b6gvzjyb2pg0kjfwrjmg1vfhh54ad73z-firefox-33.1/

where b6gvzjyb2pg0… is a unique identifier for the package that captures all its dependencies.


The next line in the manual states:

Β 

This enables many powerful features.

Β 

⚑Wow!


I demand code! πŸ™Ž

file.nix

{pkgs}: derivation {
  name = "my-very-cool-app";
  system = "x86_64-linux";
  builder = ./build.sh;
  outputs = [ "out" ];
  buildInputs = [ pkgs.bash ];
}

▢️ nix build


layout: statement

Thanks for coming
to my talk! πŸ™

Β 
... ok I lied. It takes more than that to create a working package.


πŸ˜‡ I omitted some stuff

  • pkgs (a.k.a. nixpkgs) bootstrapping.
  • Nobody uses derivation without abstraction.
  • We should use the Nix Flake structure for packages.

And what is this weird derivation thing?... πŸ™€


🎯 What we'll take a look at today

  • nix (the tool) βœ…
  • Nix (the expression language)
  • nixpkgs
  • NixOS
  • Nix Flakes

Nix Expression Language

The Nix language is designed for conveniently creating and composing derivations – precise descriptions of how contents of existing files are used to derive new files.
Β 

It is:

  • domain-specific
  • declarative
  • pure
  • functional
  • lazy
  • dynamically typed

layout: fact

Bad People on the internet claim that

😈
Nix is JSON with functions

Β 
and they are not wholly wrong I'm afraid.

Β 
But in truth: With the exception of curly braces
Β  and beeing slightly annoying to use,
it doesn't have a lot in common.


layout: statement

Nix deserves a talk of it's own.

Here are four slides of the
most important language constructs.


layout: two-cols

Conditionals

a = if
    negate true == false
  then
    "cool bananas 🍌"
  else
    null;

Let Expressions

mynumber = let
    a = 1;
    b = 2;
  in a + b;

# mynumber= 3

::right::

Strings

mySurname = "Hauser";

myName = "Fabian ${mySurname}";

myStory = ''
  Once upon a time,
  there was a person called ${myName}
'';

layout: two-cols

Sets

Other languages call this
dictionary or object.

You will see this a lot.

mySet = {
  keyA = "value";
  "key2" = 13;
};

yourSet.first.second = "Subset";

::right::

Inherit Expression

a = "A";

values = {
  inherit a;
  b = "B";
};

With Expressions

values = { a = "A"; };

myLetterA = with values; a;

Functions: pattern: body

concatStrings = x: y: x + " " + y;

# Usage:
myName = concatStrings "Fabian" "Hauser";

Set-pattern function

mkPackageName = {pname, version}: "${pname}-${version};

pkgName = mkPackageName {
            pname = "hello";
            version: "1.0";
          };

builtins.: Built-in functions

derivation Add stuff to the Nix Store
import Load, parse and return the Nix expression of a file.
map f list Apply the function f to each element in the list list.
... β†’ List of built-in functions in Nix Manual

Β 
πŸ’‘ Often, abstractions from pkgs.lib are used.


layout: statement

Remember our file.nix from the nix part?

Now you should be able to understand some more things.


file.nix

{pkgs}: derivation {
  name = "my-very-cool-app";
  system = "x86_64-linux";
  builder = ./build.sh;
  outputs = [ "out" ];
  buildInputs = [ pkgs.bash ];
}

So again: what happens if we build this thing?



Moderator Slide

Demo with nix repl

pkgs = import <nixpkgs> {}
theApp = import ./file.nix
:t theApp
theApp

theAppDrv = theApp { pkgs = pkgs; }
:t theAppDrv
theAppDrv
# Show derivation and output attributes

# Show string cast
"${theAppDrv}"

# Note: The derivation is not actually buildable due to `build.sh` πŸ™ƒ

So what was that weird string cast?!?

From the nix manual on builtins:

toString e: Convert the expression e to a string. e can be: [...]

  • A set containing { __toString = self: ...; } or { outPath = ...; }.

πŸ‘¨β€πŸ« Of course, a simple reduction:

"${theAppDrv}"
β†’ toString theAppDrv
β†’theAppDrv.outPath
β†’ "/nix/store/[...]-my-very-cool-app"


layout: statement

πŸ§™
Welcome
to nix magic


πŸŸ₯ Don't panic

Having a hard time getting started with nix is normal.

  • Expressions are sometimes hard to read...

  • Lazily evaluated: errors might show up later than expected

  • Eval-Errors are complicated:
    nix is not rustc-helpful I'm afraid πŸ™

  • IDE-Support still not great
    Abstractions can drive you crazy
    (the new nixd LSP is very promising)


πŸ“š Ressources


🎯 What we'll take a look at today

  • nix (the tool) βœ…
  • Nix (the expression language) βœ…
  • nixpkgs
  • NixOS
  • Nix Flakes

layout: fact

🌊
How about a break?


nixpkgs

The mono-repository for:

πŸ—‚οΈ pkgs, pkgs, and more pkgs

πŸ”§ some nix libs

❄️ NixOS

  • modules
  • integration tests
  • utilities/scripts

The CI ("Hydra") pushes binary builds to cache.nixos.org.


πŸ“¦ Packages in nixpkgs

Let's take a look at a package I am the maintainer of: hamster.

http://github.com/NixOS/nixpkgs (β†’ all-packages.nix and default.nix)

So how do I use this package?

nix run nixpkgs#hamster

This builds and executes:
"${nixpkgs.legacyPackages.x86_64-linux.hamster.out}/bin/hamster"


🌌 Welcome to the Nix Universe


πŸ”§ Nixpkgs: Specific Builders

Nixpkgs contains specific builders for:

  • Languages (e.g. haskell, python, node)
  • Frameworks or environments (e.g. gtk, QT, CUDA, teXlive, android)
  • Build tools (e.g. cmake, Xcode)
  • Container / Packaging (e.g. docker/OCI, snap, disk-image)
  • Testing (e.g. nixosTest)

πŸ”§ pkgs.stdenv.mkDerivation

The convenience derivation wrapper.

  • Contains some build essentialsβ„’
  • Default build.sh with custom phases, e.g. buildPhase, installPhase
  • Used by most specific builders β†’ they wrap or hook into mkDerivation

Β 

πŸ“œ For documentation: The Source is your Friend.


🎯 What we'll take a look at today

  • nix (the tool) βœ…
  • Nix (the expression language) βœ…
  • nixpkgs βœ…
  • NixOS
  • Nix Flakes

NixOS is a Linux distribution
based on the purely functional package management system Nix,
that is composed using modules and packages defined in the Nixpkgs project.

-- Nix Manual: Preface


πŸš€ NixOS: Features

  • Build whole system from a Nix file
  • Configuration with NixOS Module abstractions
  • Manage system with nixos-* scripts

Properties:

  • The system is immutable
  • Setup changes result in a "whole new system"

<style> ol { list-style: decimal !important; } </style>

πŸ—οΈ NixOS Setup

In a nutshell:

  1. πŸ’Ύ Boot live Image
  2. Partitioning (/ root-FS, /boot/efi boot partition, the usual)
  3. nixos-generate-config: Generate a basic configuration.nix
  4. nixos-install: Install the system to the Disk
  5. Reboot and enjoy

layout: section

Let's take a look at a minimal NixOS desktop setup with gnome and networking.


{ config, pkgs, ... }: {
  system.stateVersion = "23.11";

  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  networking.hostName = "nixos";

  services.xserver.enable = true;
  services.xserver.desktopManager.gnome.enable = true;

  users.users.alice = {
    isNormalUser = true;
    password = "bob"; # TODO: Insecure
    extraGroups = [ "wheel" ];
  };
}

🧨 Demo time!

# Preparations:
cd demo
rm -f nixos.qcow2
export NIXOS_CONFIG=`pwd`/configuration.nix

nixos-rebuild build-vm --no-flake
./result/bin/run-nixos-vm

πŸ“ Applying config changes

Let's add hamster to the system's packages:

πŸ“ƒ /etc/nixos/configuration.nix

{ config, pkgs, ... }: {
  ...
  environment.systemPackages = [ pkgs.hamster ];
}

▢️ Apply

nixos-rebuild switch

NixOS Modules

Pretty cool abstractions, e.g.:

services.nextcloud = {
  enable = true;
  host = "nextcloud.coredump.ch";
};

Due to time constraint, no more Modules tonight, sorry 😞


🎯 What we'll take a look at today

  • nix (the tool) βœ…
  • Nix (the expression language) βœ…
  • nixpkgs βœ…
  • NixOS βœ…
  • Nix Flakes

❄️ Flakes

What Cargo.toml is to cargo, just on steroids πŸ”₯

πŸ“₯ inputs

Other nix flakes (or git repos) that we want to use in our flake
(plus self: the folder our flake.nix lives in)

πŸ“€ outputs

Standardized nix-tree with derivations


❄️ Output tree

{
  packages.<system>.<name> = derivation ...;
  devShells.<system>.<name> = derivation ...;
  nixosConfigurations.<host> = ...;
  nixosModules.<name> = ...;
  apps = ...;
  checks = ...;
  formatter = ...;
  templates = ...;
  ...
}

<system> is the arch (e.g. x86_64-linux)
<name> is a custom name or default


❄️ Example: NixOS Installation

▢️ nixos-rebuild switch

{
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05";

  outputs = { self, nixpkgs }: {
    nixosConfigurations.fabian-desktop = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [ ./configuration.nix ];
    };
  };
}

β†’ /etc/nixos/flake.nix


❄️ Example: Dev Shell

▢️ nix develop

{
  inputs.nixpkgs.url = "github:NixOS/nixpkgs";

  outputs = { self, nixpkgs }: let
   system = "x86_64-linux";
   pkgs = import nixpkgs { inherit system; };
  in {
    devShells.${system}.default = pkgs.mkShell {
      name = "my-node-application";
      buildInputs = [ pkgs.nodejs_20 ];
    };
  };
}

❄️ Example: Simple Package

▢️ nix build

{ 
  outputs = { self, nixpkgs }: let
   system = "x86_64-linux";
   pkgs = import nixpkgs { inherit system; };
  in {
    packages.${system}.default = pkgs.mkDerivation {
      name = "hello";
      src = self;
      buildPhase = "gcc -o hello ./hello.c";
      installPhase = "mkdir -p $out/bin; install -t $out/bin hello";
    };
  };
}

flake.lock

What Cargo.lock is to cargo, just on steroids πŸ”₯

  • pin inputs to an exact version (=git hash)
  • Automatically initialised on first flake run
  • Update with nix flake update

Tracking this file makes your builds (mostly) reproducible.


πŸ“š On the Topic of Documentation

Nix Flakes are still considered unstable. However...
Flakes are also the de-facto-standard way to use nix nowadays.

The documentation is still a work in progress I'm afraid.

A good starting point:

πŸ’‘ https://nixos.wiki/wiki/Flakes


layout: section

You made it πŸ’ͺ

Welcome to the Universe of nix!