feat: add first blog post
This commit is contained in:
parent
23aa8bdd15
commit
a345552e16
7 changed files with 172 additions and 3 deletions
|
|
@ -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];
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
themes/
|
||||
public/
|
||||
|
|
|
|||
|
|
@ -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/"},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
+++
|
||||
title="Blog Posts"
|
||||
template="custom/blog/section.html"
|
||||
+++
|
||||
|
|
@ -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 %}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
{% extends "blog/section.html" %}
|
||||
<meta name="fediverse:creator" content="@moritz@functional.cafe">
|
||||
Loading…
Add table
Add a link
Reference in a new issue