Compare commits

...

2 commits

Author SHA1 Message Date
701443bf1f
Revert "feat: switch back to lix"
This reverts commit 679f12e6a8.
2025-05-19 12:26:12 +02:00
a345552e16
feat: add first blog post 2025-05-19 12:23:32 +02:00
10 changed files with 184 additions and 65 deletions

53
flake.lock generated
View file

@ -373,21 +373,6 @@
"type": "github"
}
},
"flakey-profile": {
"locked": {
"lastModified": 1712898590,
"narHash": "sha256-FhGIEU93VHAChKEXx905TSiPZKga69bWl1VB37FK//I=",
"owner": "lf-",
"repo": "flakey-profile",
"rev": "243c903fd8eadc0f63d205665a92d4df91d42d9d",
"type": "github"
},
"original": {
"owner": "lf-",
"repo": "flakey-profile",
"type": "github"
}
},
"fromYaml": {
"flake": false,
"locked": {
@ -572,43 +557,6 @@
"type": "github"
}
},
"lix": {
"flake": false,
"locked": {
"lastModified": 1746827285,
"narHash": "sha256-hsFe4Tsqqg4l+FfQWphDtjC79WzNCZbEFhHI8j2KJzw=",
"rev": "47aad376c87e2e65967f17099277428e4b3f8e5a",
"type": "tarball",
"url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/47aad376c87e2e65967f17099277428e4b3f8e5a.tar.gz?rev=47aad376c87e2e65967f17099277428e4b3f8e5a"
},
"original": {
"type": "tarball",
"url": "https://git.lix.systems/lix-project/lix/archive/2.93.0.tar.gz"
}
},
"lix-module": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"flakey-profile": "flakey-profile",
"lix": "lix",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1746838955,
"narHash": "sha256-11R4K3iAx4tLXjUs+hQ5K90JwDABD/XHhsM9nkeS5N8=",
"rev": "cd2a9c028df820a83ca2807dc6c6e7abc3dfa7fc",
"type": "tarball",
"url": "https://git.lix.systems/api/v1/repos/lix-project/nixos-module/archive/cd2a9c028df820a83ca2807dc6c6e7abc3dfa7fc.tar.gz?rev=cd2a9c028df820a83ca2807dc6c6e7abc3dfa7fc"
},
"original": {
"type": "tarball",
"url": "https://git.lix.systems/lix-project/nixos-module/archive/2.93.0.tar.gz"
}
},
"master": {
"locked": {
"lastModified": 1747575265,
@ -1045,7 +993,6 @@
"home-manager": "home-manager",
"impermanence": "impermanence",
"jovian": "jovian",
"lix-module": "lix-module",
"master": "master",
"neovim-nightly-overlay": "neovim-nightly-overlay",
"niri": "niri",

View file

@ -35,8 +35,7 @@
| .key as $parent_key
| .value.inputs | keys[]
| select(IN($root_input_keys[]))
| {"key": $parent_key, "value": .}
| .key + ".inputs." + .value + ".follows = \"" + .value + "\";"'
| $parent_key + ".inputs." + . + ".follows = \"" + . + "\";"'
'';
runtimeInputs = [pkgs.jq];
})
@ -113,7 +112,6 @@
home-manager.url = "github:nix-community/home-manager";
impermanence.url = "github:nix-community/impermanence";
jovian.url = "github:Jovian-Experiments/Jovian-NixOS";
lix-module.url = "https://git.lix.systems/lix-project/nixos-module/archive/2.93.0.tar.gz";
nix-index-database.url = "github:Mic92/nix-index-database";
nix-monitored.url = "github:ners/nix-monitored";
nixos-mailserver.url = "gitlab:simple-nixos-mailserver/nixos-mailserver";
@ -154,8 +152,6 @@
git-hooks.inputs.nixpkgs.follows = "nixpkgs";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
jovian.inputs.nixpkgs.follows = "nixpkgs";
lix-module.inputs.flake-utils.follows = "flake-utils";
lix-module.inputs.nixpkgs.follows = "nixpkgs";
neovim-nightly-overlay.inputs.flake-compat.follows = "flake-compat";
neovim-nightly-overlay.inputs.flake-parts.follows = "flake-parts";
neovim-nightly-overlay.inputs.git-hooks.follows = "git-hooks";

View file

@ -1,4 +1,4 @@
{inputs, ...}: {
{
imports = [
../../modules/zfs_unencrypted.nix
../../modules/shared.nix
@ -7,7 +7,6 @@
./ddns.nix
./mail-server.nix
./website/root
inputs.lix-module.nixosModules.default
];
time.timeZone = "Europe/Berlin";

View file

@ -1 +1,2 @@
themes/
public/

View file

@ -28,5 +28,5 @@ header_nav = [
{ url = "/", name_en = "/home/"},
# { url = "/about", name_en = "/about/"},
# { url = "/journal", name_en = "/journal/"},
# { url = "/blog", name_en = "/blog/"}
{ url = "/blog", name_en = "/blog/"},
]

View file

@ -0,0 +1,158 @@
+++
title="Generate Nix Flake \"follows\""
template="custom/blog/page.html"
+++
Like many [Nix](https://nixos.org) users I am using the "experimental" flakes feature[^1].
Flakes are a way of defining inputs and outputs:
```nix
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
# other inputs
};
outputs = inputs @ {nixpkgs, ...}: {
# imagine some output here
};
}
```
The outputs are used (as the name implies) for some kind of output, such as: packages, NixOS configuration, development shells, ...\
But as this blog post exclusively revolves around the inputs part you can already forget about outputs again.
The inputs are a reference to a source, like a git repo, which are used by the flake.
Most often you want to have one input for _nixpkgs_, where most of the package definitions for Nix are found.
Additionally you will likely use some Nix libraries which are also inputs to your flake.
You can also track source code of projects which do not use Nix at all, which allows for the equivalent of "-git" packages in the AUR.
To make flakes reproducible the specific version of each input is recorded in the "flake.lock" file.
## Inputs all the way down
The example flake above is so simple that you will hardly see something alike in the wild.
As a real world example we will look at the flake I use to define the configurations of all my machines.
In it I use many libraries and NixOS modules[^2] which leads to an inputs section like this:
```nix
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
flake-parts.url = "github:hercules-ci/flake-parts";
clan-core.url = "git+https://git.clan.lol/clan/clan-core";
clan-core.inputs.nixpkgs.follows = "nixpkgs"; # Needed if your configuration uses nixpkgs unstable.
flake-utils.url = "github:numtide/flake-utils";
git-hooks.url = "github:cachix/git-hooks.nix";
home-manager.url = "github:nix-community/home-manager";
impermanence.url = "github:nix-community/impermanence";
jovian.url = "github:Jovian-Experiments/Jovian-NixOS";
lix-module.url = "https://git.lix.systems/lix-project/nixos-module/archive/2.93.0.tar.gz";
nixos-mailserver.url = "gitlab:simple-nixos-mailserver/nixos-mailserver";
nur.url = "github:nix-community/NUR";
niri.url = "github:sodiboo/niri-flake";
};
outputs = _: {};
}
```
In reality I use even more inputs, but you get the point.
And to complicate things further all of these inputs seen above are also flakes.
This means they can define inputs, which could in turn be flakes, which could define inputs, and so on.
As eluded to earlier we need to keep track of each inputs version to ensure reproducibility.
But with so many inputs which also define inputs we inevitably end up with duplicates.
In some cases this can be exactly what we want to ensure we build the same thing as the person who defined the input we use.
However often we do not want 10 different versions of _nixpkgs_ and in turn 10 versions of bash or other packages.
The evaluation time also increases with the number of distinct inputs.
## I will follow you
To solve this problem we can use the follows feature.
I already used this in the second example to make the _nixpkgs_ of _clan-core_ follow our _nixpkgs_ defined above.
This causes nix to override the _nixpkgs_ version of _clan-core_ to the same one as the _nixpkgs_ input.
For a handful of inputs this can be easily written by hand, but at some point becomes tiring.
The flake defined in the previous section uses a staggering 49 inputs[^3].
I definitely do not want to figure out and write all the follow statements for this by hand!
## Just One Line
To get an overview for inputs which are redundant I wrote a [jq](https://jqlang.org/) one-liner[^4]:
```sh
nix flake metadata --json | jq -r \
'.locks.nodes
| map(select(has("inputs"))
| .inputs[])
| flatten
| map(select(test(".*_[0-9]+")))[]'
```
Resulting in the following candidates for duplicate inputs:
```text
systems_2
systems_3
gitignore_2
nixpkgs_2
nixpkgs_3
flake-utils_2
nixpkgs_4
nixpkgs_5
flake-compat_2
git-hooks_2
nixpkgs_6
nixpkgs-24_11
flake-parts_3
nixpkgs_8
treefmt-nix_2
flake-parts_2
nixpkgs_7
```
In this list `nixpkgs-24_11` is a false positive, but the rest are duplicates.
To avoid these duplicate inputs I wrote another one-liner.
```sh
nix flake metadata --json | jq -r \
'(.locks.nodes.root.inputs | keys) as $root_input_keys
| .locks.nodes | to_entries[]
| select(.key | IN($root_input_keys[]))
| select((.value | has("flake") | not) or (.value.flake == true))
| select(.value | has("inputs"))
| .key as $parent_key
| .value.inputs | keys[]
| select(IN($root_input_keys[]))
| $parent_key + ".inputs." + . + ".follows = \"" + . + "\";"'
```
It generates a follow statement for every non top-level input with the same name as a top-level input.
Looking at our example we already have a top-level input called _nixpkgs_.
This means the script will create a follow statement for every other input called _nixpkgs_ to follow this top-level _nixpkgs_.
Running this script produces a list of follow statements:
```text
clan-core.inputs.flake-parts.follows = "flake-parts";
clan-core.inputs.nixpkgs.follows = "nixpkgs";
git-hooks.inputs.nixpkgs.follows = "nixpkgs";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
jovian.inputs.nixpkgs.follows = "nixpkgs";
lix-module.inputs.flake-utils.follows = "flake-utils";
lix-module.inputs.nixpkgs.follows = "nixpkgs";
niri.inputs.nixpkgs.follows = "nixpkgs";
nixos-mailserver.inputs.git-hooks.follows = "git-hooks";
nixos-mailserver.inputs.nixpkgs.follows = "nixpkgs";
nur.inputs.flake-parts.follows = "flake-parts";
nur.inputs.nixpkgs.follows = "nixpkgs";
```
By adding these to our flake we reduce the number of inputs to 36.
We can reduce this further by adding new _top-level_ inputs which are used often by the libraries we use.
To do so we can again identify duplicates, add them as top-level imports and run the script again.
## Conclusion
We were able to reduce our number of inputs from 49 inputs to 36 (which could be reduced even further).
This should speed up evaluation and avoid some duplicate packages for our flake.
There exist a similar tool [nix-auto-follow](https://github.com/fzakaria/nix-auto-follow) which rewrites the "flake.lock" file directly to remove duplicates.
However by rewriting the lock file it is harder to edit/change what inputs follows which.
There is an [open issue](https://github.com/fzakaria/nix-auto-follow/issues/19) to make it more configurable.
So maybe this problem could be solved in the future.
For now tough I will just use my trusty one-liner!
---
[^1]: by now I doubt they will ever get stable
[^2]: also libraries I guess
[^3]: run `nix flake metadata | grep -v "follows input" | grep "Last modified" -c` and subtract 1 for the flake itself
[^4]: if you ignore line breaks added for readability

View file

@ -0,0 +1,4 @@
+++
title="Blog Posts"
template="custom/blog/section.html"
+++

View file

@ -0,0 +1,5 @@
{% extends "blog/page.html" %}
{% block content %} <!-- TODO: use head instead if supported by theme -->
{{ super() }}
<meta name="fediverse:creator" content="@moritz@functional.cafe">
{% endblock %}

View file

@ -0,0 +1,2 @@
{% extends "blog/section.html" %}
<meta name="fediverse:creator" content="@moritz@functional.cafe">

View file

@ -2,16 +2,14 @@
config,
lib,
inputs,
self,
pkgs,
...
}: let
inherit (lib) mkEnableOption mkOption types;
cfg = config.my.programs.nix;
in {
imports = [
inputs.lix-module.nixosModules.default
];
options.my.programs.nix = {
gc = {
enable = mkEnableOption "nix-gc";
@ -25,9 +23,15 @@ in {
};
config = {
home-manager.users.moritz.programs.direnv.nix-direnv.package = pkgs.nix-direnv.override {
nix = config.nix.package;
};
nix = {
nixPath = ["nixpkgs=${inputs.nixpkgs}"];
package = pkgs.nix; # TODO: change this back
extraOptions = ''
experimental-features = nix-command flakes
'';
@ -52,6 +56,9 @@ in {
master.flake = inputs.master;
nixpkgs.flake = inputs.nixpkgs;
stable.flake = inputs.stable;
dotfiles.flake = self;
default.flake = self;
d.flake = self;
};
settings = {