dot

vizie's NixOS desktop: Hyprland, CachyOS kernel and gaming tweaks

1415676

The CachyOS kernel, updated and built every night by git.granstrm.com

By Gustaf Granström

dot's flake has a `ci` for gt now. Every night at 02:00, tools/update-kernel
moves nix-cachyos-kernel to its latest commit if the kernel changed, and gt
fast-forwards main to it; CI on main builds the kernel, its modules and the
NVIDIA driver into the public binary cache, cache.git.granstrm.com, which
the desktop substitutes from.

The input follows master: release only moves once upstream's Hydra has
built it, and it has been at 7.2.8 for weeks; this is 7.3.0. The Desktop
update and the update alias take git.granstrm.com's commits and update every
input but the kernel's, warn before compiling a kernel the cache doesn't
have, and don't reboot when nothing changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

9 files changed +214 −37

modifiedREADME.md
@@ -43,6 +43,11 @@
4343 nix flake update --flake ~/git/dot # newer packages; then rebuild (alias: update)
4444 ```
4545
46+The alias, like the control centre's Desktop update (`tools/nixos-update`), leaves
47+the kernel alone: git.granstrm.com moves it to the latest CachyOS kernel every
48+night and builds it into its binary cache (the `ci` output in `flake.nix`), so
49+the update pulls that commit and downloads the kernel instead of compiling it.
50+
4651 Every rebuild is a boot menu entry, so a bad one is undone by picking the one
4752 before it.
4853
@@ -96,6 +101,8 @@
96101 - Kernel: `linux-cachyos-latest-lto-zen4` from
97102 [xddxdd/nix-cachyos-kernel]https://github.com/xddxdd/nix-cachyos-kernel, the
98103 same build as CachyOS's znver4 `linux-cachyos` (EEVDF, 1000 Hz, ThinLTO, Zen 4).
104+ Built every night it changes by git.granstrm.com, and downloaded from
105+ `https://cache.git.granstrm.com`.
99106 - cachyos-settings: sysctl, I/O schedulers, THP, ntsync, limits, oomd, PCI latency,
100107 ananicy-cpp with CachyOS's rules, bpftune; see `modules/nixos/cachyos.nix`.
101108 - `proton-cachyos` is installed for Steam under CachyOS's own internal name
modifiedflake.lock
@@ -42,11 +42,11 @@
4242 "nixpkgs-lib": "nixpkgs-lib"
4343 },
4444 "locked": {
45- "lastModified": 1788450739,
46- "narHash": "sha256-glZLQlzIn1fXH6PazR2iUmTo7kzzyYSshrWhLS9TqCU=",
45+ "lastModified": 1790898470,
46+ "narHash": "sha256-zTwuwezD0w3hpga6a6P8emidzAZFyWqlNeRBlpWOOl8=",
4747 "owner": "hercules-ci",
4848 "repo": "flake-parts",
49- "rev": "31729ca8cbdb4fa927b34e5f4353e6a83f39e993",
49+ "rev": "024633cd702b10285db5cb19b40ad48d2399ba60",
5050 "type": "github"
5151 },
5252 "original": {
@@ -102,27 +102,26 @@
102102 "nixpkgs": "nixpkgs"
103103 },
104104 "locked": {
105- "lastModified": 1790564970,
106- "narHash": "sha256-ANcKKTLB5oitjAYPp+iWts5clpbowVbDPVvt03P7Hes=",
105+ "lastModified": 1792702169,
106+ "narHash": "sha256-7SmndCoLigN20I9i7tAK0JDQb1XZR/3i7HIhGVcr/ag=",
107107 "owner": "xddxdd",
108108 "repo": "nix-cachyos-kernel",
109- "rev": "b1332396df6e880d7e3b6b451c6a74132ce8cf66",
109+ "rev": "02ba4db52e62e1fbece80402d369127ae77cbbeb",
110110 "type": "github"
111111 },
112112 "original": {
113113 "owner": "xddxdd",
114- "ref": "release",
115114 "repo": "nix-cachyos-kernel",
116115 "type": "github"
117116 }
118117 },
119118 "nixpkgs": {
120119 "locked": {
121- "lastModified": 1790505892,
122- "narHash": "sha256-/pAz2XfqHS//WRn2xRjoqes7Z92qZ0Q1gufZZ3PtuwA=",
120+ "lastModified": 1792617723,
121+ "narHash": "sha256-IyFA94SfEEqeru/RZyRRbmk8gtBejDTiojSReKzUOc8=",
123122 "owner": "NixOS",
124123 "repo": "nixpkgs",
125- "rev": "545c226a9af7f59fba5c3873f7c6a65e014c8f5f",
124+ "rev": "dce1caf58d1a943af38b376e824a0d036ec3eea7",
126125 "type": "github"
127126 },
128127 "original": {
@@ -134,11 +133,11 @@
134133 },
135134 "nixpkgs-lib": {
136135 "locked": {
137- "lastModified": 1788057806,
138- "narHash": "sha256-DTQSMxzDWmT0zhguthvegnVkn7CFqGCv4IHCzk5ZUpM=",
136+ "lastModified": 1790477367,
137+ "narHash": "sha256-oujbxmVKDhci2E4EM3KyAbRUgp5/IsCoiA/LfEF7OOk=",
139138 "owner": "nix-community",
140139 "repo": "nixpkgs.lib",
141- "rev": "596e2e3940e09b2abbeb03f75fa1828c57fcd72c",
140+ "rev": "f7cd230690d9fc982d06129f9189b101fddcfa3b",
142141 "type": "github"
143142 },
144143 "original": {
modifiedflake.nix
@@ -20,10 +20,13 @@
2020 inputs.nixpkgs.follows = "nixpkgs";
2121 };
2222
23- # CachyOS kernels. Its nixpkgs input is left alone on purpose: the kernel
24- # stays the exact build upstream tests (it compiles locally, as its binary
25- # cache isn't used).
26- nix-cachyos-kernel.url = "github:xddxdd/nix-cachyos-kernel/release";
23+ # CachyOS kernels, from master: upstream updates it every day with what
24+ # CachyOS releases (its release branch only moves once upstream's own CI
25+ # has built it, which can lag for weeks). Its nixpkgs input is left alone
26+ # on purpose, so the kernel is the build upstream defines. git.granstrm.com
27+ # updates it every night and builds the kernel into its binary cache (`ci`
28+ # below); the Desktop update leaves it alone (tools/nixos-update).
29+ nix-cachyos-kernel.url = "github:xddxdd/nix-cachyos-kernel";
2730
2831 imsh-clients = {
2932 url = "github:echozio/imsh-clients";
@@ -90,5 +93,71 @@
9093 );
9194
9295 formatter.${system} = pkgs.nixfmt;
96+
97+ # CI on git.granstrm.com (gt, set up in ~/git/srv: modules/nixos/gt). On
98+ # main, every night: tools/update-kernel commits the latest CachyOS kernel,
99+ # gt fast-forwards main to it, and CI on that commit builds the kernel, its
100+ # modules (nvidia-open among them) and the NVIDIA driver into the public
101+ # binary cache, https://cache.git.granstrm.com, which cachyos.nix
102+ # substitutes from.
103+ ci =
104+ { ref, ... }:
105+ let
106+ desktop = self.nixosConfigurations.desktop.config;
107+ nvidia = desktop.hardware.nvidia.package;
108+ in
109+ nixpkgs.lib.optionalAttrs (ref == "refs/heads/main") {
110+ caches = {
111+ kernel = {
112+ path = desktop.boot.kernelPackages.kernel;
113+ label = "CachyOS kernel";
114+ public = true;
115+ };
116+ kernel-modules = {
117+ path = desktop.system.modulesTree;
118+ label = "Kernel modules";
119+ public = true;
120+ };
121+ # Built against the kernel, so new with it too. Unfree, but NVIDIA
122+ # lets it be redistributed.
123+ nvidia = {
124+ path = pkgs.linkFarm "nvidia-driver" (
125+ map (output: {
126+ name = output;
127+ path = nvidia.${output};
128+ }) nvidia.outputs
129+ ++ [
130+ {
131+ name = "settings";
132+ path = nvidia.settings;
133+ }
134+ ]
135+ );
136+ label = "NVIDIA driver";
137+ public = true;
138+ };
139+ };
140+
141+ effects.update-kernel = {
142+ drv = pkgs.writeShellApplication {
143+ name = "update-kernel";
144+ runtimeInputs = with pkgs; [
145+ nix
146+ git
147+ jq
148+ coreutils
149+ ];
150+ text = builtins.readFile ./tools/update-kernel;
151+ };
152+ description = "Commits the latest CachyOS kernel";
153+ fastForward = true;
154+ on.schedule = [
155+ {
156+ cron = "0 2 * * *";
157+ tz = "Europe/Oslo";
158+ }
159+ ];
160+ };
161+ };
93162 };
94163 }
@@ -13,6 +13,7 @@
1313 name = "nixos-update";
1414 runtimeInputs = with pkgs; [
1515 git
16+ jq
1617 nvd
1718 ];
1819 runtimeEnv.DOT_REPO = config.dot.repoPath;
@@ -57,8 +57,9 @@
5757
5858 # The pacman ones, for NixOS. Built as you, with sudo only for the switch:
5959 # Nix won't read a git checkout owned by someone else, so a root build
60- # of this one fails.
61- update = "nix flake update --flake ${config.dot.repoPath} && nixos-rebuild switch --sudo --flake ${config.dot.repoPath}";
60+ # of this one fails. update, like the control centre's (tools/nixos-update),
61+ # takes the kernel git.granstrm.com built (git pull) and updates the rest.
62+ update = "git -C ${config.dot.repoPath} pull --ff-only && nix flake update --flake ${config.dot.repoPath} $(${lib.getExe pkgs.jq} -r '.nodes.root.inputs | keys[] | select(. != \"nix-cachyos-kernel\")' ${config.dot.repoPath}/flake.lock) && nixos-rebuild switch --sudo --flake ${config.dot.repoPath}";
6263 rebuild = "nixos-rebuild switch --sudo --flake ${config.dot.repoPath}";
6364 cleanup = "sudo nix-collect-garbage --delete-older-than 14d";
6465 };
@@ -49,10 +49,18 @@
4949 {
5050 # --- Kernel ----------------------------------------------------------------
5151
52- # The overlay pins the kernel to the nixpkgs it was built with. Its binary
53- # cache isn't used, so the kernel compiles locally.
52+ # The overlay pins the kernel to the nixpkgs it was built with, so the build
53+ # doesn't change with this system's nixpkgs.
5454 nixpkgs.overlays = [ inputs.nix-cachyos-kernel.overlays.pinned ];
5555
56+ # git.granstrm.com builds the kernel, its modules and the NVIDIA driver every
57+ # night the kernel changes (flake.nix's `ci`), and serves them from its
58+ # binary cache.
59+ nix.settings = {
60+ substituters = [ "https://cache.git.granstrm.com" ];
61+ trusted-public-keys = [ "cache.git.granstrm.com-1:Y6BjEJMQZ02kt2oOJ/99RU+NTDZDsBY8tqIiypq1ong=" ];
62+ };
63+
5664 # Same build as linux-cachyos on CachyOS's znver4 repo: EEVDF scheduler,
5765 # 1000 Hz, full preemption, Clang ThinLTO, tuned for Zen 4 (also right for
5866 # this Zen 5 CPU, as on CachyOS).
@@ -4,8 +4,10 @@
44 # control centre's update tile in a kitty window (installed as `nixos-update`,
55 # modules/home/packages.nix, which sets DOT_REPO).
66 #
7-# 1. a temporary worktree of main
8-# 2. nix flake update, committed there
7+# 1. a temporary worktree of main, with the commits git.granstrm.com made since
8+# (the nightly CachyOS kernel, flake.nix's `ci`)
9+# 2. nix flake update of every input but the kernel's, committed there: the kernel
10+# is the one git.granstrm.com built, and comes from its binary cache
911 # 3. nixos-rebuild build, then nvd's list of what changed against the running system
1012 # 4. asks before going on; then pushes the commit, installs it as the next boot
1113 # entry (nixos-rebuild boot), brings your checkout's main up to date and reboots
@@ -42,35 +44,59 @@
4244 step "Fetching $repo"
4345 git -C "$repo" worktree prune
4446 git -C "$repo" fetch origin main
45-git -C "$repo" merge-base --is-ancestor origin/main main ||
46- die "main in $repo is behind origin/main (or has diverged); pull first."
47-base=$(git -C "$repo" rev-parse main)
47+main=$(git -C "$repo" rev-parse main)
48+# git.granstrm.com's own commits (the kernel) are taken as they are; your own on
49+# main that it doesn't have yet are pushed with the update.
50+if git -C "$repo" merge-base --is-ancestor main origin/main; then
51+ base=$(git -C "$repo" rev-parse origin/main)
52+elif git -C "$repo" merge-base --is-ancestor origin/main main; then
53+ base=$main
54+else
55+ die "main in $repo and origin/main have diverged; rebase main first."
56+fi
4857 ahead=$(git -C "$repo" rev-list --count origin/main..main)
4958 dirty=$(git -C "$repo" status --porcelain)
5059
5160 tmp=$(mktemp -d -t dot-update.XXXXXX)
5261 step "Creating a worktree of main in $tmp"
53-git -C "$repo" worktree add --detach "$tmp" main
62+git -C "$repo" worktree add --detach "$tmp" "$base"
5463 cd "$tmp" || die "Could not enter $tmp."
5564
56-step "Updating flake inputs"
57-nix flake update --commit-lock-file
58-if [ "$(git rev-parse HEAD)" = "$base" ]; then
65+step "Updating flake inputs (all but the kernel's)"
66+mapfile -t inputs < <(jq -r '.nodes.root.inputs | keys[] | select(. != "nix-cachyos-kernel")' flake.lock)
67+nix flake update --commit-lock-file "${inputs[@]}"
68+
69+kernel=$(nix eval --raw "$tmp#nixosConfigurations.desktop.config.boot.kernelPackages.kernel")
70+if ! nix path-info "$kernel" >/dev/null 2>&1 &&
71+ ! nix path-info --store https://cache.git.granstrm.com "$kernel" >/dev/null 2>&1; then
72+ note "The kernel isn't in git.granstrm.com's cache: its CI hasn't built it yet, or failed"
73+ note "(https://git.granstrm.com/dot). It would compile here, which takes a while."
74+ read -rp "Compile it here? [y/N] " answer || answer=""
75+ case $answer in
76+ [yY]*) ;;
77+ *)
78+ echo "Nothing was changed."
79+ sleep 1
80+ exit 0
81+ ;;
82+ esac
83+fi
84+
85+step "Building"
86+nixos-rebuild build --flake "$tmp"
87+if [ "$(readlink -f "$tmp/result")" = "$(readlink -f /run/current-system)" ]; then
5988 printf '\nEverything is already up to date.\n'
6089 wait_close
6190 exit 0
6291 fi
63-
64-step "Building"
65-nixos-rebuild build --flake "$tmp"
6692
6793 step "What changes"
68-git --no-pager log -1 --format=%b
94+git --no-pager log --format='%s%n%n%b' "$main..HEAD"
6995 nvd diff /run/current-system "$tmp/result"
7096
7197 echo
7298 [ -z "$dirty" ] || note "Uncommitted changes in $repo are not part of this update."
73-[ "$ahead" -eq 0 ] || note "main has $ahead commit(s) not on GitHub yet; they are pushed too."
99+[ "$ahead" -eq 0 ] || note "main has $ahead commit(s) not on git.granstrm.com yet; they are pushed too."
74100 read -rp "Commit, push, install and reboot? [y/N] " answer || answer=""
75101 case $answer in
76102 [yY]*) ;;
@@ -92,7 +118,7 @@
92118 if [ "$(git -C "$repo" symbolic-ref --quiet --short HEAD)" = main ]; then
93119 git -C "$repo" merge --ff-only "$commit"
94120 else
95- git -C "$repo" update-ref refs/heads/main "$commit" "$base"
121+ git -C "$repo" update-ref refs/heads/main "$commit" "$main"
96122 fi
97123 cd "$repo"
98124 cleanup
@@ -84,7 +84,7 @@
8484
8585 echo
8686 [ -z "$dirty" ] || note "Uncommitted changes in $repo are not part of this update."
87-[ "$ahead" -eq 0 ] || note "main has $ahead commit(s) not on GitHub yet; they are pushed and deployed too."
87+[ "$ahead" -eq 0 ] || note "main has $ahead commit(s) not on git.granstrm.com yet; they are pushed and deployed too."
8888 read -rp "Commit, push and switch the server? [y/N] " answer || answer=""
8989 case $answer in
9090 [yY]*) ;;
@@ -1,0 +1,66 @@
1+#!/usr/bin/env bash
2+# The nightly CachyOS kernel update on git.granstrm.com (the update-kernel effect,
3+# flake.nix): moves the nix-cachyos-kernel input to the latest commit of its master
4+# branch and commits flake.lock, if the kernel changed (its version, config,
5+# patches or how it's built: the input's kernel-cachyos directory). Upstream's own
6+# daily nixpkgs updates alone don't count, or the kernel would be rebuilt every
7+# night. gt then fast-forwards main to the commit, and CI on it builds the kernel
8+# into the binary cache (cache.git.granstrm.com), so the Desktop update
9+# (tools/nixos-update) downloads it instead of compiling.
10+#
11+# It runs in gt's effect sandbox: a clone of main, the internet, and no Nix daemon,
12+# so the input is fetched into a store of its own under /tmp.
13+set -euo pipefail
14+
15+input=nix-cachyos-kernel
16+store=/tmp/store
17+
18+nix() { command nix --extra-experimental-features 'nix-command flakes' --store "$store" "$@"; }
19+
20+# The input's lock entry, by its name in the root's inputs.
21+locked() { jq -r --arg i "$input" '.nodes[.nodes.root.inputs[$i]].locked' flake.lock; }
22+
23+# Where a lock entry's source is, on disk.
24+source_of() {
25+ local path
26+ path=$(nix flake prefetch --json "$(jq -r '"github:\(.owner)/\(.repo)/\(.rev)"' <<<"$1")" | jq -r .storePath)
27+ echo "$store$path"
28+}
29+
30+# The kernel cachyos.nix uses, linuxPackages-cachyos-latest-lto-zen4, is
31+# linux-cachyos's version.
32+version() { jq -r '."linux-cachyos".version' "$1/kernel-cachyos/version.json"; }
33+
34+old=$(locked)
35+nix flake update "$input"
36+new=$(locked)
37+old_rev=$(jq -r .rev <<<"$old")
38+new_rev=$(jq -r .rev <<<"$new")
39+
40+if [ "$old_rev" = "$new_rev" ]; then
41+ echo "No new commit on $input." | tee /run/gt/skip
42+ exit 0
43+fi
44+
45+old_src=$(source_of "$old")
46+new_src=$(source_of "$new")
47+if [ "$(nix hash path "$old_src/kernel-cachyos")" = "$(nix hash path "$new_src/kernel-cachyos")" ]; then
48+ echo "$input ${new_rev:0:7}: the kernel is the same, so it stays at ${old_rev:0:7}." | tee /run/gt/skip
49+ exit 0
50+fi
51+
52+old_version=$(version "$old_src")
53+new_version=$(version "$new_src")
54+if [ "$old_version" = "$new_version" ]; then
55+ subject="CachyOS kernel $new_version, rebuilt"
56+else
57+ subject="CachyOS kernel $new_version"
58+fi
59+
60+git add flake.lock
61+git -c user.name=git.granstrm.com -c user.email=gt@git.granstrm.com commit -q -F - <<EOF
62+$subject
63+
64+$input ${old_rev:0:7} -> ${new_rev:0:7}, kernel $old_version -> $new_version.
65+EOF
66+git --no-pager log -1 --format='%s%n%n%b'