# services/prebuild.nix — nightly pre-build of the other hosts' system closures. # # Both laptops/desktops offload builds to this host (nix.buildMachines in # common.nix), and the Macbook can't build at all (max-jobs = 0). Realising # their toplevels here ahead of time turns `update` on those machines into a # pure copy: the client's `update` alias re-runs this exact nix build over SSH # (so eval happens here too, against a warm eval cache), finds the path already # realised, and only copies the closure back. # # --out-link doubles as the gc root, so `clean` doesn't reap the closures # before the other machines ever ask for them. { config, lib, pkgs, ... }: let loupeCredential = pkgs.writeShellScript "forgejo-loupe-credential" '' [ "''${1:-}" = get ] || exit 0 protocol= host= path= while IFS='=' read -r key value; do case "$key" in protocol) protocol=$value ;; host) host=$value ;; path) path=$value ;; esac done [ "$protocol" = https ] && [ "$host" = forg.gregersen.it ] || exit 0 case "$path" in lazzexus/Loupe|lazzexus/Loupe.git) ;; *) exit 0 ;; esac # Prefer a dedicated token. The router token can work too when it has # read access to the private Loupe repository. Neither enters the store. secret=/var/secrets/forgejo-loupe-token [ -f "$secret" ] || secret=/var/secrets/forgejo-router-token [ -f "$secret" ] || exit 0 if [ -r "$secret" ]; then token=$(${pkgs.coreutils}/bin/cat "$secret") else token=$(/run/wrappers/bin/sudo -n ${pkgs.coreutils}/bin/cat "$secret") || exit 0 fi [ -n "$token" ] || exit 0 printf 'username=rope\npassword=%s\n' "$token" ''; mkService = host: { description = "Pre-build the ${host} system closure"; after = [ "network-online.target" ]; wants = [ "network-online.target" ]; path = [ pkgs.git ]; environment.HOME = "/root"; serviceConfig = { Type = "oneshot"; StateDirectory = "prebuild"; }; # Gaming's kernel comes from lantian's attic (see hosts/hardware/ # FredOS-Gaming.nix). That substituter isn't configured on this host, so # without it the cachyos kernel gets built from source here instead of # fetched — hours, not minutes. Harmless for the Macbook. script = '' ${config.nix.package}/bin/nix build --refresh \ --option extra-substituters https://attic.xuyh0120.win/lantian \ --option extra-trusted-public-keys lantian:EeAUQ+W+6r7EtwnmYjeVwx5kOGEBpjlBfPlzGlTNvHc= \ --out-link /var/lib/prebuild/${host} \ 'git+https://forg.gregersen.it/rope/nixos#nixosConfigurations.${host}.config.system.build.toplevel' ''; }; # Staggered so the two builds don't fight over cores and bandwidth. mkTimer = startAt: { wantedBy = [ "timers.target" ]; timerConfig = { OnCalendar = startAt; Persistent = true; RandomizedDelaySec = "20m"; }; }; in { config = lib.mkIf (config.networking.hostName == "FredOS-Mediaserver") { # Nix's git+https input fetch uses Git outside the build sandbox. Both the # root prebuild timer and fred's SSH-triggered rebuilds read credentials at # fetch time, without putting a private token in flake.lock or /nix/store. programs.git = { enable = true; config.credential = { useHttpPath = true; "https://forg.gregersen.it".helper = "${loupeCredential}"; }; }; systemd.services = { prebuild-macbook = mkService "FredOS-Macbook"; prebuild-gaming = mkService "FredOS-Gaming"; }; systemd.timers = { prebuild-macbook = mkTimer "04:00"; prebuild-gaming = mkTimer "05:00"; }; }; }