Compare commits
2 commits
23aa8bdd15
...
701443bf1f
| Author | SHA1 | Date | |
|---|---|---|---|
| 701443bf1f | |||
| a345552e16 |
10 changed files with 184 additions and 65 deletions
53
flake.lock
generated
53
flake.lock
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
@ -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 = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue