Nixとはなにか、パッケージマネージャとしての使い方の紹介

# Nixってなに？

Nixの説明と簡単な使いかたを紹介したいと思います。

NixというとパッケージマネージャやOSとしてのNixOSの意味がありますが、ここでは[パッケージマネージャとしてのNix](https://nixos.org/manual/nix/stable/)を説明します。

公式のマニュアルはこちらです。

* [Nix: パッケージマネージャの使い方](https://nixos.org/manual/nix/stable/)
* [NixOS: NixOSの使い方](https://nixos.org/manual/nixos/stable/)
* [NixPills: パッケージを作るときのノウハウ集](https://nixos.org/guides/nix-pills/)

Nixをパッケージマネージャとして使う場合は手元のWindows, Mac, LinuxでOSのインストールなしに利用することができます。

パッケージマネージャだけでなく、開発環境を含めた開発フローについてpythonを使った例を示します。

NixではパッケージのことをDerivationと呼びますので注意してください。Nixでは独特の用語が多いので[用語集](https://qiita.com/junjihashimoto@github/items/54f8e25071b2800ee2ee#%E7%94%A8%E8%AA%9E%E9%9B%86)をつけました。参考にしてください。


#### OSのバージョンを気にしないソフトのインストール

あるソフトを使う場合にOSのバージョンを気にしたり、関連するソフトをインストールするかと思います。
MacのユーザーとLinuxのユーザーの開発環境が違っていてつらいという状況もあるでしょう。
同じソフトだけどバージョン違いのものをいれて試したいこともあるでしょう。
Nixをつかうとシステムを汚さずに使いたいソフトをどこででもインストールできます。

例えば、[gccをインストールしたい場合はMacやLinuxにかかわらず、次のコマンドでインストールできます。](https://nixos.org/manual/nix/stable/#examples)

```nix
nix-env -i gcc
```

#### どこにインストールするのか？

プログラムをインストールケースは次のようなものがサポートされています。

* システムのユーザー全員
    * [/etc/nixos/configuration.nix](https://nixos.org/manual/nixos/stable/index.html#sec-configuration-syntax)に設定を書く。
* システムのあるユーザー
    * nix-envコマンドで直接インストールする。
    * [~/.config/nixpkgs/config.nix](https://nixos.org/manual/nixpkgs/stable/#sec-modify-via-packageOverrides)に設定を書く。
* あるユーザーのある開発環境だけ
    * [nix-shell](https://nixos.org/manual/nix/unstable/command-ref/nix-shell.html)コマンドを使う。例えばpythonが欲しいときは`nix-shell -p python`とすればpythonがあるshellの環境ができます。exitをするとそのpythonへの参照が消えます。
   


#### ハッシュによるバージョン管理

Nixはパッケージの依存関係をハッシュで管理しています。
パッケージを作るのに必要なパッケージのリストとパッケージのソースコードのアーカイブのハッシュをつくってそれをもとに出力先を決めます。詳しくは[こちら](https://nixos.org/guides/nix-pills/nix-store-paths.html
)を参照してください。ハッシュによって再現性を担保します。

ハッシュでつくられたパッケージを中央のレポジトリ（https://cache.nixos.org） でキャッシュすることでバイナリのパッケージを配布しています。個人的なパッケージのキャッシュにはローカルのストレージ、AWSのS3、[cachix](https://cachix.org/)が使えます。

#### パッケージ作成が簡単

Nixはもっとも簡単にパッケージが作れものじゃないかなと思っています。 単にシェルの結果だけを生成するパッケージは次のようなものです。

```nix
runCommand "hello" {} ''
  mkdir $out
  echo hello > $out/hello.txt
'';
```

#### まとめ

Nixの利点をまとめると以下のようになります。

* 再現性
* バイナリキャッシュ
* 独自パッケージの提供が簡単(中央のリポジトリがなくてもパッケージを提供できる。)
* MacでもLinuxでも同じパッケージを利用可能

いいことばかりだけではなく、Nixではなにがつらいのか以下に紹介しておきます。

* 使いたいパッケージが公式サイトで提供がない。
* コミュニティーが小さい。
* 既存のパッケージのコードがよくわからないが、読めないと生きていけない。
* nix expressionのデバッグが難しい。
* ストレージを多く使う傾向がある。
* セキュリティパッチを当てられない。セキュリティの対応にはソフトの再インストールが必要。
* 成熟してない。次から次に新しいパッケージの管理ツールがでてくるので学習コストが高め。

# Dockerとの違いは？

再現性というとDockerを思い浮かべるでしょう。Nixも同じような用途で使うことができますが、Nixはパッケージ管理ソフトです。時にはHomebrewのように時にはDockerのように使えます。
細かいDockerとの違いは[こちらの記事](https://discourse.nixos.org/t/is-there-much-difference-between-using-nix-shell-and-docker-for-local-development/807/13)や下記の表が参考になるでしょう。

| | Nix | Docker |
|-|-|-|
|実行環境|通常のユーザー環境|コンテナ|
|実行権限|ユーザーと同じ権限|ルート権限|
|MacOSでの利用|MacOSのネイティブ(homebrew的な立ち位置で使える。)|コンテナ内のLinux|
|再現性の担保方法|依存するファイルのハッシュで担保（実行したときによらず同じ結果になるはず）|ビルドしたときのスナップショットで担保|
|ビルドの再現性|いつ実行しても同じものができる。|実行したときの最新のファイルがインストールされる。ダウンロードするファイルが違う可能性がある。|
|ビルドプロセス|Nix言語で記述：aptやyumは使えない。|Dockerfileで記述：aptやyumが使える。|
|キャッシュする単位|パッケージごと|スナップショット全体(各ビルドのステップごとにキャッシュができますが、一部を変更するとそれ以降はすべてやり直しになります。)|



# Bazelとの違いは？

Bazelはgoogleが開発したビルドツールですね。
Googleでは非常によく使われているようで、例えばGoogle ChromeのビルドにBazelは使われています。

Bazelはビルドに必要とするファイルをすべて洗い出してサンドボックス環境でビルドを行います。
そのため、再現性が高く、効率よくビルドした結果をキャッシュするビルドツールです。この考えはnixのビルド方法に近いです。

こちらの記事にあるようにBazelを使って再現性が高い機械学習のパイプラインを作った例があります。
https://www.spotdraft.com/engineering-blog/how-we-used-bazel-to-streamline-our-ai-development

Bazelはビルドツールとして設計されていますが、Nixはパッケージマネージャとして設計されています。
使うターゲットの違いがあります。

# どんな用途使うといいと思っているか？

以下のようなケースでnixを使うといいと考えています。
nixではカスタマイズしたツールをインストールするのが簡単です。
nixでは開発環境の構築はnix-shellを実行するだけです。
環境構築が複雑になってきたらnixをつかうことを検討してもいいかもしれません。
コンテナのほうが向いている場合は無理に使う必要はないです。

* エディタなどのツールの設定ファイルの管理(.vimrcや.emacs)
* セットアップが複雑なプロジェクト(まずaptでなにかインストールして、それから言語特有のプログラムを実行してとか。)
* 複数の言語やライブラリを利用するプロジェクト(rustで作られたライブラリをpythonから利用するとか)

# インストール方法

下記を実行するだけです。LinuxでもMacでも同様です。Windowsの場合はWSL2上で実行しましょう。

```shell
$ curl -L https://nixos.org/nix/install | sh
```

# アンインストール方法

https://github.com/NixOS/nix/issues/1402#issuecomment-312496360

1. ~/.profile や ~/.bash_profile の`. "$HOME/.nix-profile/etc/profile.d/nix.sh"`の行を消す。 
1. `rm -rf $HOME/{.nix-channels,.nix-defexpr,.nix-profile,.config/nixpkgs}
sudo`
1. `rm -rf /nix`
1. マルチユーザー用にインストールしているならnixbld[0-9]のユーザーを削除

# パッケージの管理の仕組み

パッケージは次のフローで作成されます。
通常はnix-buildコマンドで次の手順が一度に実行されます。

1. nix言語で書かれたものをdrvファイルにコンパイルします。その結果/nix/store/*.drvファイルができます。この時点では実際のビルドはなにも始まりません。
1. drvファイルをつかってパッケージの中身を作成します。bashとかpythonとかいろいろなコマンドを使って実際のビルドが行われます。その結果、/nix/store/*(drvがついてないディレクトリ)ができあがります。



![](https://i.stack.imgur.com/NqxsO.png)


# パッケージマネージャの使い方

パッケージマネージャとしてのコマンドを紹介します。
こちらのコマンドはユーザーの環境内でグローバルに設定するために使います。
開発環境で使うツールはshell.nixファイルを作りnix-shellコマンドを起動して利用します。

パッケージのインストールにこれまでnix-envを使ってきましたが、nix profileというコマンドが試験的に導入されています。二つの使い方を紹介しますが、互いに互換性がないので初めてつかうかたはnix profileから始めてもいいかもしません。

* nix-envをつかう場合
    * インストール
        * nix-env -i "パッケージ名"
    * 特定のチャネルのパッケージをインストール
        * nix-env -f https://github.com/NixOS/nixpkgs/archive/nixos-14.12.tar.gz -iA firefox
    * アンインストール
        * nix-env -e "パッケージ名"
    * インストール済みのパッケージの一覧
        * nix-env -q
    * インストール可能なパッケージの一覧
        * nix-env -qa
* nix profileを使う場合
    * インストール
        * nix profile install nixpkgs# "パッケージ名"
    * 特定のチャネルのパッケージをインストール
        * nix profile install nixpkgs/release-20.09#firefox
    * アンインストール
        * nix profile listで削除したいパッケージのpositionを調べて下記を実行
        * nix profile remove "position"
    * インストール済みのパッケージの一覧
        * nix profile list

ディスクがなくなってきたときは`nix-collect-garbage`を実行してGCをします。

# パッケージの構成



# パッケージの作り方

### Nix Expression Language（Nix言語）

パッケージを作る前にパッケージを書くためのNixに慣れる必要があります。
詳細は[こちらのwiki](https://nixos.wiki/wiki/Nix_Expression_Language
)にありますが、特徴は次のようなものです。

* 関数型言語
* 遅延評価
* 動的型付け
* ファイル全体が一つの式
* 式の型は次がすべて
    * 文字列型
    * 整数型
    * 浮動小数点型
    * パス
    * ブーリアン
    * null
    * リスト
    * 辞書型
    * 関数（ラムダ）
    * derivation

例えば次のようなdefault.nixファイルがある場合を考えます。
ファイルですが、一つの関数になっていて引数は`{}`がついているので辞書型で
その辞書の要素（キー）にpkgsというのがあります。
pkgsというパッケージの辞書の中でstdenvのキーのところにmkDerivationというパッケージ(derivation)をつくる関数があって、引数として辞書をとります。
この場合はnameという要素（キー）に`package1`という文字列をいれて、パッケージ(derivation)の名前を`package1`として宣言しています。


```nix
{pkgs}:
pkgs.stdenv.mkDerivation {
  name = "package1";
##以下省略
}
```


### Derivation

### Sandbox

### ファイル構成


https://nixos.org/manual/nix/stable/

# 再現性の高いパッケージの作り方(NivとFlakes)

Nixによるパッケージは再現性が高いですが、nixpkgsなど関連するパッケージを固定しておかないと環境によってはインストールされるものが違ってきます。

固定する方法は二通りあって、nivとflakesです。

* [niv](https://github.com/nmattia/niv)
    * gitで管理されたレポジトリをまとめてくれて、nix上で使えるようにするツール。
* [flakes](https://www.tweag.io/blog/2020-05-25-flakes/
)
    * nixコマンドに統合された次世代型パッケージ管理ツール。
    * 従来のdefault.nixと互換性がない。

# ユーザー環境の管理方法

https://github.com/nix-community/home-manager

# 開発環境の作り方

開発環境の作り方はいくつかあります。

* `nix-shell -p "パッケージをスペース区切りで列挙"`
    * 例、`nix-shell -p sqlite gcc`
* shell.nixまたはdefault.nixファイルを置き、derivationを出力するようにする。
    * 例として次のshell.nixを作りnix-shellコマンドを実行します。

```
{pkgs ? import <nixpkgs> {}}: # nix-shellへの引数（?は引数がない場合のデフォルトで今回はnixpkgsのパッケージ(システムのデフォルトが使われる。)）
pkgs.mkShell { # mkShellはソースの無いderivationを作るために使う便利関数
  buildInputs = [ pkgs.sqlite pkgs.gcc ]; # 開発環境で使うパッケージのリスト
}
```
* flake.nixファイルを置き、devShellをターゲットにderivationを出力するようにする。
    * 例として次のflake.nixを作りnix developコマンドを実行します。


```
{ # ソース: https://nixos.wiki/wiki/Flakes
  description = "my project description";

  inputs.flake-utils.url = "github:numtide/flake-utils";

  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem
      (system:
        let pkgs = nixpkgs.legacyPackages.${system}; in
        {
          devShell = import ./shell.nix { inherit pkgs; };
        }
      );
}
```

   
# Pythonの使い方
* [nixpkgsから直接使う](https://github.com/NixOS/nixpkgs/blob/master/doc/languages-frameworks/python.section.md)
    * 公式の標準の方法
    * pros
        * 使い方が簡単
            * 単にパッケージを並べるだけでパッケージをインストールずみのpythonが使えます。
            * サンプル：`nix-shell -p 'python38.withPackages(ps: with ps; [ numpy toolz requests ])' --run python3`
        * インストールそのもので失敗しにくい。
        * wheelも扱える。
            * [pytorchの場合のサンプル]( https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/python-modules/pytorch/bin.nix)

    * cons
        * cache.nixos.orgに機械学習系のパッケージがキャッシュされてないのでフルスクラッチからビルドが走りインストールに時間がかかかる。たとえば、transformersとpandasを使うプロジェクトで12時間くらいかかる。(どういう条件でキャッシュされるのかはよくわかっていません。)
* [mach-nix](https://github.com/DavHau/mach-nix)
    * requirements.txtを使うプロジェクトの場合
* [poetry2nix](https://github.com/nix-community/poetry2nix)
    * pyproject.tomlを使うプロジェクトの場合
    * pros
        * cache.nixos.orgにキャッシュがなくてもwhlなどを利用でき、インストールが他より速い。（nixをつかわない場合と同じくらい？）
    * cons
        * poetryそのものでパッケージのインストールができないとできない。



# カスタマイズしたツールの使い方（Sixel対応のScreenのインストール）

nixpkgsが提供していないソフトのパッケージの仕方を見ていきます。
その例としてsixelに対応したgnu screenのパッケージを行います。

1. nixpkgsに類似のパッケージがないか探す。　
    * 今回はnixpkgsのscreen
 https://github.com/NixOS/nixpkgs/blob/9d3d02f9c1272f1845bcd3295a22f4a3acb6326a/pkgs/tools/misc/screen/default.nix をつかいます。
1. flake.nixの雛形の生成をするために`nix flake init`を実行
1. flake.nixのinputsのところにインストールしたいソフトのURLをはる
    * https://github.com/junjihashimoto/screen-nix/blob/main/flake.nix#L5-L8
1. flake.nixの`defaultPackage.x86_64-linux` にnixpkgsのmkDerivationのところを貼り付け、srcのところinputsのものに変更する。
    * https://github.com/junjihashimoto/screen-nix/blob/main/flake.nix#L11-L102
1. `nix profile install github:<ユーザーID>/<レポジトリ名>`でインストール
    * `nix profile install github:junjihashimoto/screen-nix`

# CUDAの使い方

CUDAのためのドライバのセットアップ方法はNixOSとそれ以外では違います。
Ubuntu上でNixを使っている場合はドライバの設定は不要ですが、次のライブラリのセットアップを行ってください。

### NixOS以外の場合

nixではnvidiaのライブラリ(libcuda.soなど)を/run/opengl-driver/libは以下に置くことになっています。
CUDAを使う前に下記のコマンドを実行しましょう。systemdで起動時に設定したい場合は[こちら](https://discourse.nixos.org/t/building-with-cuda-on-nixpkgs/4462/14
)を参照してください。

```shell
sudo mkdir -p /run/opengl-driver/lib
sudo ln -s /usr/lib/x86_64-linux-gnu/libcuda* /run/opengl-driver/lib/
sudo ln -s /usr/lib/x86_64-linux-gnu/libnvidia-* /run/opengl-driver/lib/
```

WSL2の場合は次のようになります。

```shell
sudo mkdir -p /run/opengl-driver/lib
sudo ln -s /usr/lib/wsl/lib/lib*.* /run/opengl-driver/lib/
```

### NixOSの場合


# OpenGLの使い方

### NixOS以外の場合

OpenGLを動かす場合も/run/opengl-driver/libは以下に置くことになっているのですが、上記のCUDAのやりかたではうまく動かないので[nixGL](https://github.com/guibou/nixGL)を使いましょう。

### NixOSの場合

# OpenGLの使い方


# デバッグの仕方

### nix-buildに関すること

* 修正してないのにビルドが走る場合
  * 修正前後のdrvファイルを/nix/store/*から見つけてきてnix-diffコマンドで差分を確認する
* 特定のdrvファイルのビルドに失敗する場合
  * nix-shell "drv ファイル"を実行し、(source $stdenv/setup ; genericBuild)コマンドを実行する。
     * https://nixos.org/guides/nix-pills/fundamentals-of-stdenv.html
     * こちらも参照：https://nixos.org/guides/nix-pills/developing-with-nix-shell.html
* ビルドの失敗したところのシェルに入りたい。
    * breakpointHookを使う。
    * https://discourse.nixos.org/t/debug-a-failed-derivation-with-breakpointhook-and-cntr/8669
* ビルドのログを見たい。
    * nix log *.drvファイル
    * nix log "/nix/store/以下の成功したビルドのディレクトリ"
    * nix log `readlink -f result` # nix buildで生成されたresultディレクトリをつくったログを見る場合。
* *.nixファイルのnix expression自体をデバッグしたい。特に途中の式になにが入っているのかわからない。
    * nix replを使う。
        * 起動後、`:l <nixpkgs>`や`src = import ./default.nix {}`などしてファイルを読みんで式を評価して確認
        * flakesの場合
            * `:lf . `を実行後に`pkgs = import inputs.nixpkgs {}`を実行して読み込む。
            * https://github.com/NixOS/nix/pull/5027
    * traceを使って途中の式を評価して表示する。
        * https://medium.com/@MrJamesFisher/nix-by-example-a0063a1a4c55
* derivationの設定を書き換えたい
    * overlays
        * https://nixos.wiki/wiki/Overlays
    * override
        * https://nixos.org/guides/nix-pills/nixpkgs-overriding-packages.html
        * https://nixos.org/guides/nix-pills/override-design-pattern.html
* drvの生成でどんなコマンドが動くのか確認する
    * nix show-derivation "drvファイル" | jq '.[] | .["env"]'
* nixのbuildの中でネットワークにアクセスしたい。
    * `--option sandbox false`のオプションをつける.
        * デフォルトはsandbox環境でderivationのビルドが行われるがsandboxをオフにしてビルドすることでネットワークにビルド中にアクセスできる。
        * このオプションをつけてもアクセスできない場合は、nix.confにtrusted-users=<ユーザー名>を追加する。
            * https://discourse.nixos.org/t/how-to-run-nix-build-with-sandbox-false/17693
            * https://nixos.org/manual/nix/stable/command-ref/conf-file.html
    * gitからネットワークにアクセスしているならgitのラッパーを書く。
        * sandbox環境でないとビルドの再現性が落ちるため、あまりsandboxをオフにするのは好まれない。
        * gitのようにネットワークにアクセスするコマンドをビルド中に使う場合はコマンド自体のラッパーを書いてネットワークアクセスを回避するパターンがある。下記はその一例。
        * サンプル
            * https://github.com/NixOS/nixpkgs/blob/1922e8792421a31f4d4ca962ee2d35cd1b72bd18/pkgs/tools/audio/kaldi/default.nix#L40-L62
    * `__impure = true;`をderivationにつける。
        * nix 2.8の新機能
        * `--option sandbox false`をつけてビルドするとすべてのderivationのビルドがsandbox環境でないところでビルドされるが、nix 2.8の新機能で特定のderivationだけsandboxを外すことができるようになった。
        * https://discourse.nixos.org/t/nix-2-8-0-released/18714

# キャッシュ

### 別のディレクトリにキャッシュを保存する方法

### キャッシュの参照先の追加方法

### NFSで/nix/storeを共有する方法（シングルユーザーモード）

https://nixos.wiki/wiki/NFS
こちらにあるようにシングルユーザーモードのときは/nixのディレクトリをNFS上に置くことができます。
これにより、すべてのサーバーでパッケージが共有できます。

fstabに次のような設定をいれるといいようです。

```
<host_or_ip>/nix /nix nfs nofail,x-systemd.device-timeout=4,local_lock=all 0 0
```

<del>
しかし、`local_lock=flock`のオプションをつけるようにありますが、これは同一サーバー内でのロックに限定する話のように見えます。（https://linux.die.net/man/5/nfs）
複数のサーバーで使う場合は`local_lock=none`もしくはこれを付けないほうがいいかもしれません。
また、[こちらのしくじりの話](https://techblog.raccoon.ne.jp/archives/1635140633.html)からするとロックのときにキャッシュをうまく破棄させるために`noac`のオプションが必要なようです。
</del>

### NFSで/nix/storeを共有する方法（マルチユーザーモード）

マルチーユーザーモードで単純にNFSで/nixをマウントすると、nix-daemonというデーモンと通信するための/nix/var/nix/daemon-socket/socketのファイルが作られるため、マシンごとにこのソケットのファイルがつくれなくなり、nix-daemonが起動できなくなります。
なので、次のようにbindの設定をいれるとローカルの/var/run/nix-daemon-socketのディレクトリにソケットのファイルができるので、nix-daemonが起動できるようになります。

```
<host_or_ip>/nix /nix nfs nofail,x-systemd.device-timeout=4,local_lock=all 0 0
/var/run/nix-daemon-socket    /nix/var/nix/daemon-socket          none    bind        0       0
```

# 分散ビルド

複数のマシンをつかってビルドを高速にする場合には、https://nixos.org/manual/nix/stable/advanced-topics/distributed-builds.html を参照ください。
わかりにくい気がしますが、次の手順でセットアップします。

1. sshできるnixをインストールしたサーバーを用意。
1. /etc/nix/machinesに分散ビルド用のサーバーを列挙

/etc/nix/machinesのフォーマット

```
#sshのユーザー名@ホスト マシンのタイプ sshの鍵 並列化の数 優先度 (kvmをつかうかどうかのフラグ)
nix@scratchy.labs.cs.uu.nl  i686-linux      /home/nix/.ssh/id_scratchy_auto        8 1 kvm
nix@itchy.labs.cs.uu.nl     i686-linux      /home/nix/.ssh/id_scratchy_auto        8 2
nix@poochie.labs.cs.uu.nl   i686-linux      /home/nix/.ssh/id_scratchy_auto        1 2 kvm benchmark
```

ビルドは一台のホストにビルド結果を集約しつつ、必要に応じてリモートのサーバーにファイルをコピーしてリモートのサーバーでビルドし、それをまたホストにコピーするという手順で行うようです。


# セキュリティ

* パッケージの信頼性を担保するか？
    * おそらく議論中
    * https://discourse.nixos.org/t/trust-model-for-nixpkgs/9450/29
* キャッシュのセキュリティ
    * バイナリキャッシュを秘密鍵で暗号化して、ユーザーは公開鍵で利用するモデル。
    * https://www.tweag.io/blog/2019-11-21-untrusted-ci/

# 用語集

* nix : パッケージマネージャのコマンド
* nixpkgs : nixのパッケージ一覧をまとめたもの。 https://github.com/nixos/nixpkgs で提供しています。
* derivation : パッケージのこと、debianであればdebファイルのこと。
* NixOS : nixをパッケージマネージャとしてつかうlinuxのディストリビューション
* Nix言語 : パッケージを記述する言語、nix expressionともいう。
* チャンネル:パッケージ一覧のセットorバージョン、ubuntuだったら18.04とか20.04とか。
* Nixストア: パッケージをインストールしているディレクトリ（`/nix/store`）
* drvファイル
    * *.nixファイルから生成したderivationをつくるためのファイル。
    * https://nixos.org/guides/nix-pills/our-first-derivation.html


# 参考文献

* https://serokell.io/blog/what-is-nix
* https://nixos.wiki/wiki/Flakes
* https://github.com/Tokyo-NixOS/Tokyo-NixOS-Meetup-Wiki/wiki/terminology
* https://nixos.org/manual/nixos/stable/
* https://nixos.org/guides/nix-pills/
* https://nixos.org/manual/nix/unstable/
* https://discourse.nixos.org/t/is-there-much-difference-between-using-nix-shell-and-docker-for-local-development/807/4
* https://github.com/nmattia/niv
* https://www.tweag.io/blog/2020-05-25-flakes/
* https://nixos.wiki/wiki/Flakes
* https://serokell.io/blog/practical-nix-flakes
* https://discourse.nixos.org/t/debug-a-failed-derivation-with-breakpointhook-and-cntr/8669