theme | highlighter | lineNumbers | info | drawings | transition | canvasWidth | |
---|---|---|---|---|---|---|---|
apple-basic |
shiki |
false |
## Nix
|
|
slide-left |
700 |
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
β Anonymous π
So welcome to the
β’οΈ. Sorry!
Once upon a time in 2006...
- 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
nix
(the tool)- Nix (the expression language)
- nixpkgs
- NixOS
- Nix Flakes
Β
π€ What are they?
π€ How on earth are they all connected?
π₯ 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
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:
Β
Β
{pkgs}: derivation {
name = "my-very-cool-app";
system = "x86_64-linux";
builder = ./build.sh;
outputs = [ "out" ];
buildInputs = [ pkgs.bash ];
}
nix build
Β
... ok I lied. It takes more than that to create a working package.
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?... π
nix
(the tool) β- Nix (the expression language)
- nixpkgs
- NixOS
- Nix Flakes
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
Β
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.
a = if
negate true == false
then
"cool bananas π"
else
null;
mynumber = let
a = 1;
b = 2;
in a + b;
# mynumber= 3
::right::
mySurname = "Hauser";
myName = "Fabian ${mySurname}";
myStory = ''
Once upon a time,
there was a person called ${myName}
'';
Other languages call this
dictionary or object.
You will see this a lot.
mySet = {
keyA = "value";
"key2" = 13;
};
yourSet.first.second = "Subset";
::right::
a = "A";
values = {
inherit a;
b = "B";
};
values = { a = "A"; };
myLetterA = with values; a;
concatStrings = x: y: x + " " + y;
# Usage:
myName = concatStrings "Fabian" "Hauser";
mkPackageName = {pname, version}: "${pname}-${version};
pkgName = mkPackageName {
pname = "hello";
version: "1.0";
};
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.
Now you should be able to understand some more things.
{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?
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` π
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"
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 notrustc
-helpful I'm afraid π -
IDE-Support still not great
Abstractions can drive you crazy
(the newnixd
LSP is very promising)
- https://nix.dev/
- https://zero-to-nix.com/
- Nix Manual: https://nixos.org/manual/nix/
- NixOS Wiki: https://nixos.wiki/wiki/Overview_of_the_Nix_Language
nix
(the tool) β- Nix (the expression language) β
- nixpkgs
- NixOS
- Nix Flakes
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.
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)
nix run nixpkgs#hamster
This builds and executes:
"${nixpkgs.legacyPackages.x86_64-linux.hamster.out}/bin/hamster"
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
)
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.
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.
- 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>
In a nutshell:
- πΎ Boot live Image
- Partitioning (
/
root-FS,/boot/efi
boot partition, the usual) nixos-generate-config
: Generate a basicconfiguration.nix
nixos-install
: Install the system to the Disk- Reboot and enjoy
{ 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" ];
};
}
# Preparations:
cd demo
rm -f nixos.qcow2
export NIXOS_CONFIG=`pwd`/configuration.nix
nixos-rebuild build-vm --no-flake
./result/bin/run-nixos-vm
Let's add hamster
to the system's packages:
π /etc/nixos/configuration.nix
{ config, pkgs, ... }: {
...
environment.systemPackages = [ pkgs.hamster ];
}
nixos-rebuild switch
- Configuration options come from NixOS Modules
- Option search: https://search.nixos.org/
- Additional docs: https://nixos.org/manual/nixos/
Pretty cool abstractions, e.g.:
services.nextcloud = {
enable = true;
host = "nextcloud.coredump.ch";
};
Due to time constraint, no more Modules tonight, sorry π
nix
(the tool) β- Nix (the expression language) β
- nixpkgs β
- NixOS β
- Nix Flakes
What Cargo.toml
is to cargo
, just on steroids π₯
Other nix flakes (or git repos) that we want to use in our flake
(plus self
: the folder our flake.nix
lives in)
Standardized nix-tree with derivations
{
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
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
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 ];
};
};
}
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";
};
};
}
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.
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
You made it πͺ