All checks were successful
Check / eval (push) Successful in 3m4s
Re-diagnosis of the "btrfs-assistant 2.2 segfaults on launch" bug, and the fix is not the planned nixpkgs override: 1. gdb: the crash is btrfs_util_subvolume_iterator_next() — libbtrfsutil's UNPRIVILEGED subvolume-iteration path in btrfs-progs 6.17.1 (upstream-fixed after 6.17.1, kdave/btrfs-progs 886571653). Symbol versions were checked and match: not ABI/link drift. 2. VM A/B on real btrfs: as root it works (exit 0); as a user it segfaults (139). The pkexec launcher runs it as root — so the GUI path was fine all along, except… 3. …the distro shipped NO polkit authentication agent: every pkexec prompt in the session failed silently. That is the actual root cause of "the GUI doesn't open". Shipped: hyprpolkitagent (Hyprland's Qt agent — the prompt is Stylix-themed) via exec-once in hyprland.nix; `nomarchy-menu snapshot` prefers btrfs-assistant-launcher again, with the nomarchy-snapshots fzf flow kept as fallback (and for SSH); checks.snapshot-gui guards the root path + offscreen GUI event loop on a real btrfs volume so a lock bump can't silently regress it. No btrfs-progs patch: all our flows are root-side; the unprivileged fix arrives with a lock bump. Verified: V0 (flake check) + V2 (snapshot-gui check, executed green) + V1 (HM generation builds; hyprland.conf carries the agent exec-once; generated menu passes bash -n with the launcher wiring). Remaining V3 queued: first on-hardware themed polkit prompt. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
563 lines
28 KiB
Nix
563 lines
28 KiB
Nix
{
|
|
description = "Nomarchy — the rock-solid reproducibility of NixOS, the polish of an opinionated desktop";
|
|
|
|
inputs = {
|
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
|
|
|
|
home-manager = {
|
|
url = "github:nix-community/home-manager/release-26.05";
|
|
inputs.nixpkgs.follows = "nixpkgs";
|
|
};
|
|
|
|
stylix = {
|
|
# Track the release branch matching nixpkgs/HM — master is built
|
|
# against unstable and warns about the version skew on every
|
|
# activation. (No home-manager input to follow anymore: stylix
|
|
# vendors its HM integration.)
|
|
url = "github:nix-community/stylix/release-26.05";
|
|
inputs.nixpkgs.follows = "nixpkgs";
|
|
};
|
|
|
|
# Pinned by Nomarchy so distro + hardware quirks are tested together
|
|
# (consumed by lib.mkFlake's hardwareProfile). Its nixpkgs input is
|
|
# only used by its own CI — follow ours to keep locks/ISO lean.
|
|
nixos-hardware = {
|
|
url = "github:NixOS/nixos-hardware/master";
|
|
inputs.nixpkgs.follows = "nixpkgs";
|
|
};
|
|
};
|
|
|
|
outputs = { self, nixpkgs, home-manager, stylix, nixos-hardware, ... }:
|
|
let
|
|
system = "x86_64-linux";
|
|
username = "nomarchy"; # reference host only; downstream picks its own
|
|
|
|
pkgs = import nixpkgs {
|
|
inherit system;
|
|
overlays = [ self.overlays.default ];
|
|
# Matches nixpkgs.config.allowUnfree in modules/nixos — the
|
|
# standalone HM generation must come from like-configured pkgs.
|
|
config.allowUnfree = true;
|
|
};
|
|
|
|
# The guided installer — live-ISO only (not in the overlay): it bakes
|
|
# in the downstream template, this checkout's flake.lock, and the
|
|
# source identity of this very revision so installs work offline.
|
|
gitUrl = "https://git.bemagri.xyz/bernardo/nomarchy.git";
|
|
nomarchyInstall = pkgs.callPackage ./pkgs/nomarchy-install {
|
|
templateDir = ./templates/downstream;
|
|
nomarchyLock = ./flake.lock;
|
|
hardwareModuleNames = pkgs.writeText "nixos-hardware-modules.txt"
|
|
(nixpkgs.lib.concatStringsSep "\n"
|
|
(builtins.attrNames nixos-hardware.nixosModules));
|
|
nixpkgsPath = nixpkgs.outPath;
|
|
# Branch model: `main` is the development default; `v1` is the
|
|
# release pointer — the stable line for the NixOS 26.05 rewrite,
|
|
# advanced to main once a batch is tested (rolling, no tags). A
|
|
# future major bump would become `v2`. Installed machines track
|
|
# `?ref=v1` on `nix flake update`, not the forge's default branch.
|
|
flakeUrl = "git+${gitUrl}?ref=v1";
|
|
# Future updates re-resolve from the forge (original); the install
|
|
# itself resolves from the ISO store (locked = path) — fully
|
|
# offline, even from a dirty-tree ISO.
|
|
originalNode = { type = "git"; url = gitUrl; ref = "v1"; };
|
|
lockedNode = {
|
|
type = "path";
|
|
path = self.outPath;
|
|
narHash = self.narHash;
|
|
lastModified = self.lastModified or 0;
|
|
};
|
|
rev = self.rev or null;
|
|
};
|
|
in
|
|
{
|
|
# ─── Downstream API ────────────────────────────────────────────
|
|
# A user's machine flake imports these and layers its own
|
|
# system.nix / home.nix on top (see templates/downstream).
|
|
# Their theme-state.json lives in THEIR flake and is wired up via
|
|
# the `nomarchy.stateFile` option — reading it stays pure.
|
|
|
|
overlays.default = final: prev: {
|
|
nomarchy-theme-sync = final.callPackage ./pkgs/nomarchy-theme-sync {
|
|
# Presets baked into the package, so `nomarchy-theme-sync list`
|
|
# works on machines that don't check out this repo.
|
|
themesDir = ./themes;
|
|
};
|
|
};
|
|
|
|
nixosModules.nomarchy = {
|
|
imports = [ ./modules/nixos ];
|
|
nixpkgs.overlays = [ self.overlays.default ];
|
|
};
|
|
|
|
homeModules.nomarchy = {
|
|
# stylix's home module is injected here because it needs the
|
|
# flake input; modules/home/stylix.nix only configures it.
|
|
imports = [ stylix.homeModules.stylix ./modules/home ];
|
|
};
|
|
|
|
# One-call downstream wrapper — see templates/downstream/flake.nix.
|
|
# The generated flake is never hand-edited; machines live in
|
|
# system.nix / home.nix.
|
|
lib = import ./lib.nix {
|
|
inherit nixpkgs home-manager nixos-hardware;
|
|
nomarchy = self;
|
|
};
|
|
|
|
templates.default = {
|
|
path = ./templates/downstream;
|
|
description = "Nomarchy machine configuration (downstream flake)";
|
|
};
|
|
|
|
packages.${system} = {
|
|
nomarchy-theme-sync = pkgs.nomarchy-theme-sync;
|
|
nomarchy-install = nomarchyInstall;
|
|
default = pkgs.nomarchy-theme-sync;
|
|
};
|
|
|
|
# ─── Checks ────────────────────────────────────────────────────
|
|
# `nix flake check` never evaluates templates/, so exercise the
|
|
# downstream template through mkFlake directly (this bypasses the
|
|
# template's own three-line flake.nix, which only resolves once
|
|
# instantiated — everything else is covered here, including the
|
|
# hardwareProfile → nixos-hardware mapping).
|
|
checks.${system} =
|
|
let
|
|
downstream = self.lib.mkFlake {
|
|
src = ./templates/downstream;
|
|
username = "me";
|
|
hardwareProfile = "framework-13-7040-amd"; # exercises the mapping
|
|
};
|
|
in
|
|
{
|
|
downstream-template-system =
|
|
downstream.nixosConfigurations.default.config.system.build.toplevel;
|
|
downstream-template-home =
|
|
downstream.homeConfigurations.me.activationPackage;
|
|
|
|
# Config-level VM assertions for the nomarchy.hardware.* toggles —
|
|
# what they SET (kernel cmdline, fprintd, PAM). Real hardware
|
|
# behaviour (firmware/driver/device) needs bare metal and is out of
|
|
# scope here. Imports only hardware.nix, so the VM stays minimal.
|
|
hardware-toggles = pkgs.testers.runNixOSTest {
|
|
name = "nomarchy-hardware-toggles";
|
|
nodes.machine = { ... }: {
|
|
imports = [ ./modules/nixos/hardware.nix ];
|
|
nomarchy.hardware = {
|
|
intel.enable = true;
|
|
amd.enable = true;
|
|
fingerprint = { enable = true; pam = true; };
|
|
npu.enable = true;
|
|
};
|
|
};
|
|
testScript = ''
|
|
machine.wait_for_unit("multi-user.target")
|
|
cmdline = machine.succeed("cat /proc/cmdline")
|
|
assert "amd_pstate=active" in cmdline, cmdline
|
|
assert "i915.enable_guc=3" in cmdline, cmdline
|
|
machine.succeed("systemctl cat fprintd.service")
|
|
machine.succeed("grep -q pam_fprintd /etc/pam.d/sudo")
|
|
'';
|
|
};
|
|
|
|
# Runtime VM check for the battery-charge-limit re-apply: the udev
|
|
# rule must restart the oneshot on an AC state change (firmware can
|
|
# clear the threshold on unplug). The `test_power` module fakes a
|
|
# Mains adapter we can toggle to emit a real power_supply uevent —
|
|
# so this exercises the trigger, not just the config wiring. (The
|
|
# sysfs *write* needs a real charge_control_end_threshold and stays
|
|
# an on-hardware check.) Imports options.nix (where the power
|
|
# options live) + power.nix, so the VM stays minimal.
|
|
battery-charge-limit = pkgs.testers.runNixOSTest {
|
|
name = "nomarchy-battery-charge-limit";
|
|
nodes.machine = { ... }: {
|
|
imports = [ ./modules/nixos/options.nix ./modules/nixos/power.nix ];
|
|
boot.kernelModules = [ "test_power" ]; # fake Mains + battery
|
|
nomarchy.system.power = {
|
|
enable = true;
|
|
laptop = true;
|
|
batteryChargeLimit = 80;
|
|
};
|
|
};
|
|
testScript = ''
|
|
machine.wait_for_unit("multi-user.target")
|
|
|
|
# The oneshot exists and the fake Mains adapter is present.
|
|
machine.succeed("systemctl cat nomarchy-battery-charge-limit.service")
|
|
machine.succeed("udevadm settle")
|
|
machine.succeed("grep -lx Mains /sys/class/power_supply/*/type")
|
|
|
|
# Let any add-event restart settle, then sample the invocation.
|
|
machine.succeed("sleep 2")
|
|
before = machine.succeed(
|
|
"systemctl show -p InvocationID --value "
|
|
"nomarchy-battery-charge-limit.service"
|
|
).strip()
|
|
|
|
# Simulate an AC unplug → 'change' uevent on the Mains device.
|
|
machine.succeed("echo off > /sys/module/test_power/parameters/ac_online")
|
|
machine.succeed("udevadm settle")
|
|
|
|
# The udev rule must have restarted the oneshot (new InvocationID).
|
|
machine.wait_until_succeeds(
|
|
'test "$(systemctl show -p InvocationID --value '
|
|
'nomarchy-battery-charge-limit.service)" != "' + before + '"',
|
|
timeout=30,
|
|
)
|
|
'';
|
|
};
|
|
|
|
# Memory-pressure protection (oom.nix): earlyoom must kill a
|
|
# runaway allocator BEFORE the kernel thrash point — and must not
|
|
# take anything else with it. A bystander unit survives the kill,
|
|
# proving the process-level granularity that motivated earlyoom
|
|
# over cgroup-level systemd-oomd (which would kill the whole
|
|
# Hyprland session scope). Imports only oom.nix so the VM stays
|
|
# minimal.
|
|
oom-protection = pkgs.testers.runNixOSTest {
|
|
name = "nomarchy-oom-protection";
|
|
nodes.machine = { ... }: {
|
|
imports = [ ./modules/nixos/oom.nix ];
|
|
environment.systemPackages = [ pkgs.python3 ];
|
|
virtualisation.memorySize = 1024;
|
|
};
|
|
testScript = ''
|
|
machine.wait_for_unit("earlyoom.service")
|
|
|
|
# One owner: oomd (nixpkgs default-on, inert) is disabled.
|
|
machine.fail("systemctl is-active --quiet systemd-oomd.service")
|
|
# The session avoid-list made it into the daemon invocation.
|
|
machine.succeed("systemctl cat earlyoom.service | grep -q -- --avoid")
|
|
|
|
# A bystander that must survive (stand-in for the session).
|
|
machine.succeed("systemd-run --unit=bystander sleep infinity")
|
|
|
|
# The hog: allocate in 20 MB chunks with a short sleep, so
|
|
# earlyoom's poll wins the race against the kernel OOM killer.
|
|
machine.succeed(
|
|
"systemd-run --unit=hog python3 -c 'import time; "
|
|
"exec(\"a=[]\\nwhile True:\\n a.append(bytearray(20*1024*1024)); time.sleep(0.05)\")'"
|
|
)
|
|
|
|
# earlyoom (not the kernel) pulled the trigger…
|
|
machine.wait_until_succeeds(
|
|
"journalctl -u earlyoom.service | grep -Eiq 'sending SIG(TERM|KILL)'",
|
|
timeout=120,
|
|
)
|
|
# …the hog is gone…
|
|
machine.wait_until_succeeds(
|
|
'test "$(systemctl show -p ActiveState --value hog.service)" != "active"',
|
|
timeout=60,
|
|
)
|
|
# …and the bystander is untouched.
|
|
machine.succeed("systemctl is-active --quiet bystander.service")
|
|
'';
|
|
};
|
|
|
|
# Snapshot GUI canary: btrfs-assistant crashes in libbtrfsutil's
|
|
# UNPRIVILEGED subvolume iteration (btrfs-progs 6.17.1, fixed
|
|
# upstream after 6.17.1) but runs fine as root — which is how the
|
|
# menu launches it (pkexec launcher). Guard the root path on a
|
|
# real btrfs volume so a lock bump that breaks it fails here, not
|
|
# on a user's machine. The GUI event loop is exercised offscreen
|
|
# (survives a 5s timeout = no startup crash past the Btrfs scan).
|
|
snapshot-gui = pkgs.testers.runNixOSTest {
|
|
name = "nomarchy-snapshot-gui";
|
|
nodes.machine = { pkgs, ... }: {
|
|
environment.systemPackages = [ pkgs.btrfs-assistant pkgs.btrfs-progs ];
|
|
virtualisation.emptyDiskImages = [ 512 ];
|
|
};
|
|
testScript = ''
|
|
machine.wait_for_unit("multi-user.target")
|
|
machine.succeed(
|
|
"mkfs.btrfs /dev/vdb && mkdir -p /mnt && mount /dev/vdb /mnt "
|
|
"&& btrfs subvolume create /mnt/sub1"
|
|
)
|
|
# Root (the launcher's effective context): must work.
|
|
machine.succeed("QT_QPA_PLATFORM=offscreen btrfs-assistant-bin --version")
|
|
# The GUI proper survives startup (timeout kill = alive → 124).
|
|
machine.succeed(
|
|
"set +e; timeout 5 env QT_QPA_PLATFORM=offscreen btrfs-assistant-bin; "
|
|
"[ $? -eq 124 ]"
|
|
)
|
|
'';
|
|
};
|
|
|
|
# The distroId question (roadmap "Distro branding"): set
|
|
# distroId = "nomarchy" so /etc/os-release is honest (ID=nomarchy,
|
|
# ID_LIKE=nixos). The risk is switch-to-configuration's "is this
|
|
# NixOS?" guard — but it builds the check from the *configured*
|
|
# distroId (and /etc/NIXOS still exists), so a rebuild must still
|
|
# work. This boots such a system and runs `switch-to-configuration
|
|
# dry-activate` to prove the guard passes. Inline (not the full
|
|
# module) so the VM stays minimal — the real wiring in default.nix
|
|
# is covered by the downstream-template-system build.
|
|
distro-id = pkgs.testers.runNixOSTest {
|
|
name = "nomarchy-distro-id";
|
|
nodes.machine = { ... }: {
|
|
system.nixos.distroName = "Nomarchy";
|
|
system.nixos.distroId = "nomarchy";
|
|
# Test base omits switch-to-configuration by default; we need it
|
|
# to exercise the "is this NixOS?" guard.
|
|
system.switch.enable = true;
|
|
};
|
|
testScript = { nodes, ... }: ''
|
|
machine.wait_for_unit("multi-user.target")
|
|
|
|
# os-release reflects the rebrand, with the nixos lineage marker.
|
|
machine.succeed("grep -q '^ID=nomarchy$' /etc/os-release")
|
|
machine.succeed("grep -q '^ID_LIKE=nixos$' /etc/os-release")
|
|
machine.succeed("grep -q '^NAME=Nomarchy$' /etc/os-release")
|
|
|
|
# The rebuild path must still recognise this as a NixOS install
|
|
# (the guard is built from the configured distroId, not "nixos").
|
|
machine.succeed(
|
|
"${nodes.machine.system.build.toplevel}/bin/switch-to-configuration dry-activate"
|
|
)
|
|
'';
|
|
};
|
|
};
|
|
|
|
# ─── Reference host ────────────────────────────────────────────
|
|
# Manually wired rather than via lib.mkFlake: the repo-root
|
|
# theme-state.json is load-bearing (live ISO + in-repo CLI dev),
|
|
# which doesn't match mkFlake's src-layout convention.
|
|
# Deliberately split rebuild paths:
|
|
# system → sudo nixos-rebuild switch --flake .#nomarchy (rare)
|
|
# desktop → home-manager switch --flake .#nomarchy (no sudo;
|
|
# this is what `nomarchy-theme-sync apply` runs)
|
|
# Theme changes never touch the system layer, so they never need
|
|
# root and never rebuild the world.
|
|
nixosConfigurations.nomarchy = nixpkgs.lib.nixosSystem {
|
|
inherit system;
|
|
specialArgs = { inherit username; };
|
|
modules = [
|
|
self.nixosModules.nomarchy
|
|
{ nomarchy.system.stateFile = ./theme-state.json; }
|
|
./hosts/default/configuration.nix
|
|
];
|
|
};
|
|
|
|
homeConfigurations.${username} = home-manager.lib.homeManagerConfiguration {
|
|
inherit pkgs;
|
|
modules = [
|
|
self.homeModules.nomarchy
|
|
{
|
|
# The single source of truth — pure read: the file is part
|
|
# of this flake's source.
|
|
nomarchy.stateFile = ./theme-state.json;
|
|
home = {
|
|
inherit username;
|
|
homeDirectory = "/home/${username}";
|
|
};
|
|
}
|
|
];
|
|
};
|
|
|
|
# ─── Live ISO ──────────────────────────────────────────────────
|
|
# Full desktop on a bootable stick, no installation:
|
|
# nix build .#nixosConfigurations.nomarchy-live.config.system.build.isoImage
|
|
# Test in QEMU with tools/test-live-iso.sh. See docs/TESTING.md.
|
|
nixosConfigurations.nomarchy-live = nixpkgs.lib.nixosSystem {
|
|
inherit system;
|
|
specialArgs = { inherit username; nomarchySrc = self; };
|
|
modules = [
|
|
"${nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix"
|
|
self.nixosModules.nomarchy
|
|
./hosts/live.nix
|
|
|
|
# The ISO is a sealed artifact, so the desktop is baked in via
|
|
# the HM NixOS module (the installed-system split into
|
|
# nixos-rebuild vs home-manager switch doesn't apply here —
|
|
# though the seeded ~/.nomarchy flake still allows standalone
|
|
# `home-manager switch` for theme testing).
|
|
home-manager.nixosModules.home-manager
|
|
{
|
|
home-manager = {
|
|
useGlobalPkgs = true;
|
|
useUserPackages = true;
|
|
users.${username} = {
|
|
imports = [ self.homeModules.nomarchy ];
|
|
nomarchy.stateFile = ./theme-state.json;
|
|
};
|
|
};
|
|
|
|
# The standalone CLI that `nomarchy-theme-sync apply` runs for
|
|
# theme switching, from the same pinned input — plus the
|
|
# guided installer.
|
|
environment.systemPackages = [
|
|
home-manager.packages.${system}.home-manager
|
|
nomarchyInstall
|
|
];
|
|
|
|
# Keep the locked flake inputs in the ISO store so theme
|
|
# switching on the live system works without a network: the
|
|
# lockfile's narHashes resolve against these paths instead
|
|
# of fetching from GitHub. Must be *transitive* — evaluating
|
|
# the seeded flake also fetches stylix's own inputs.
|
|
system.extraDependencies =
|
|
let
|
|
collectInputs = input:
|
|
[ input.outPath ] ++ builtins.concatMap collectInputs
|
|
(builtins.attrValues (input.inputs or { }));
|
|
in
|
|
collectInputs self ++ (
|
|
# Pre-build a system shaped like what nomarchy-install
|
|
# GENERATES (snapper, auto-login, LUKS initrd, swapfile +
|
|
# resume — not the bare template!) plus the template
|
|
# desktop, so the offline install never builds packages
|
|
# from source: a custom username/hostname then changes
|
|
# only a handful of derivations. No hardware profile —
|
|
# matches a VM install; profiled installs share most of it.
|
|
let
|
|
template = self.lib.mkFlake {
|
|
src = ./templates/downstream;
|
|
username = username;
|
|
};
|
|
representativeInstall = nixpkgs.lib.nixosSystem {
|
|
inherit system;
|
|
specialArgs = { inherit username; };
|
|
modules = [
|
|
self.nixosModules.nomarchy
|
|
{ environment.systemPackages = [ home-manager.packages.${system}.home-manager ]; }
|
|
# The installer's autodetection emits these on real
|
|
# machines (and the intel CPU module pulls the whole
|
|
# iGPU stack) — without them an offline install on
|
|
# common hardware builds graphics drivers from
|
|
# source. Model-specific profiles may still need
|
|
# network; the common ground is covered.
|
|
nixos-hardware.nixosModules.common-cpu-intel
|
|
nixos-hardware.nixosModules.common-cpu-amd
|
|
nixos-hardware.nixosModules.common-gpu-amd
|
|
nixos-hardware.nixosModules.common-pc-laptop
|
|
nixos-hardware.nixosModules.common-pc-ssd
|
|
nixos-hardware.nixosModules.common-pc
|
|
(./templates/downstream + "/hardware-configuration.nix")
|
|
(./templates/downstream + "/system.nix")
|
|
({ lib, ... }: {
|
|
nomarchy.system.snapper.enable = true;
|
|
nomarchy.system.greeter.autoLogin = username;
|
|
# nixos-generate-config keys microcode off
|
|
# enableRedistributableFirmware (now on): the
|
|
# real machine enables exactly one vendor —
|
|
# pin both, or the offline install builds
|
|
# amd-ucode/intel-ucode from source (found the
|
|
# hard way: the 2700s regression hang).
|
|
hardware.cpu.amd.updateMicrocode = true;
|
|
hardware.cpu.intel.updateMicrocode = true;
|
|
swapDevices = [{ device = "/swap/swapfile"; }];
|
|
boot.resumeDevice = "/dev/disk/by-uuid/00000000-0000-0000-0000-000000000000";
|
|
boot.kernelParams = [ "resume_offset=1" ];
|
|
boot.initrd.luks.devices.crypted.device = "/dev/disk/by-partlabel/disk-main-root";
|
|
# The real install is BTRFS with a vfat ESP — the
|
|
# placeholder's bare ext4 would leave fs-gated bits
|
|
# out of this pin (snapper via btrfs; mtools and
|
|
# dosfstools enter systemPackages via vfat!).
|
|
fileSystems."/" = lib.mkForce {
|
|
device = "/dev/mapper/crypted";
|
|
fsType = "btrfs";
|
|
options = [ "subvol=@" "compress=zstd" "noatime" ];
|
|
};
|
|
fileSystems."/boot" = {
|
|
device = "/dev/disk/by-uuid/0000-0000";
|
|
fsType = "vfat";
|
|
options = [ "umask=0077" ];
|
|
};
|
|
})
|
|
];
|
|
};
|
|
in [
|
|
representativeInstall.config.system.build.toplevel
|
|
template.homeConfigurations.${username}.activationPackage
|
|
|
|
# The live session's `home-manager switch` builds the
|
|
# REPO's standalone generation (the seeded ~/.nomarchy
|
|
# flake) — not the template's, and not the NixOS-module
|
|
# one baked into the ISO. It has drvs the other two
|
|
# variants don't (user-dbus-services et al.), so pin it
|
|
# and its direct build inputs too.
|
|
self.homeConfigurations.${username}.activationPackage
|
|
self.homeConfigurations.${username}.activationPackage.inputDerivation
|
|
# home-files is rebuilt per theme and COPIES some of its
|
|
# inputs (user-dbus-services) instead of referencing
|
|
# them — the activation closure doesn't carry those, so
|
|
# pin home-files' direct build inputs separately.
|
|
self.homeConfigurations.${username}.config.home-files.inputDerivation
|
|
|
|
# A real install rebuilds the drvs that embed the
|
|
# user's hostname/username/UUIDs (etc, initrd, units,
|
|
# toplevel, HM activation). inputDerivation pins each
|
|
# one's direct build inputs…
|
|
representativeInstall.config.system.build.toplevel.inputDerivation
|
|
representativeInstall.config.system.build.etc.inputDerivation
|
|
representativeInstall.config.system.build.initialRamdisk.inputDerivation
|
|
template.homeConfigurations.${username}.activationPackage.inputDerivation
|
|
# home-files COPIES user-dbus-services instead of
|
|
# referencing it (same story as the self pin above) —
|
|
# a custom-username install rebuilds home-files and
|
|
# needs its direct inputs present.
|
|
template.homeConfigurations.${username}.config.home-files.inputDerivation
|
|
] ++ [
|
|
# A theme switch re-renders stylix's base16 templates
|
|
# (gtk.css, kvantum, …) on the machine: the renderer and
|
|
# the stdenv its trivial drvs build with must be on
|
|
# board, or an offline `apply <theme>` cascades into
|
|
# building mustache-go (and eventually stdenv) from
|
|
# source. Found with tools/vm/gap-analysis.py.
|
|
pkgs.mustache-go
|
|
pkgs.stdenv
|
|
] ++ [
|
|
# …and the second-level build tools those rebuilds need
|
|
# (their parents are themselves rebuilt, so parent
|
|
# inputDerivations don't reach them): kernel-module
|
|
# shrinking, unit-dir assembly, dbus config, /etc.
|
|
pkgs.kmod.dev
|
|
pkgs.nukeReferences
|
|
pkgs.xorg.lndir
|
|
pkgs.libxslt.bin
|
|
pkgs.python3Minimal
|
|
# system-path is rebuilt on EVERY machine: buildEnv's
|
|
# package-list order follows module-graph order, and any
|
|
# hardware profile/import reshuffles it. Its builder
|
|
# wants these.
|
|
pkgs.texinfo
|
|
pkgs.getconf
|
|
# greetd.toml embeds the auto-login user and is generated
|
|
# by remarshal — without this pin an offline install
|
|
# tries to BUILD remarshal, whose test closure pulls
|
|
# matplotlib/ffmpeg/x265 (the ~1900-drv cascade).
|
|
pkgs.remarshal
|
|
# system-path/initrd-bin-env are buildEnvs rebuilt per
|
|
# machine; their shared builder.pl is build-time-only
|
|
# (never in any runtime closure) — an empty env's
|
|
# inputDerivation retains it.
|
|
(pkgs.buildEnv { name = "nomarchy-pin-buildenv"; paths = [ ]; }).inputDerivation
|
|
# /etc/dbus-1 reassembly wants this setup hook.
|
|
pkgs.findXMLCatalogs
|
|
# nixos-generate-config keys microcode off
|
|
# enableRedistributableFirmware (now on): exactly one
|
|
# vendor per real machine, so pin both ucode cpios.
|
|
pkgs.microcode-amd
|
|
pkgs.microcode-intel
|
|
|
|
# …and one representative disko script: its tool closure
|
|
# (file, which, wrapper hooks, …) isn't otherwise on the
|
|
# ISO, and offline nix would try to build it from source.
|
|
# The user's actual args produce a different script drv,
|
|
# but with identical inputs — built offline in seconds.
|
|
(import "${pkgs.disko}/share/disko/cli.nix" {
|
|
inherit pkgs;
|
|
mode = "destroy,format,mount";
|
|
diskoFile = ./pkgs/nomarchy-install/disko-config.nix;
|
|
mainDrive = "/dev/vda";
|
|
withLuks = true;
|
|
swapSize = "2G";
|
|
})
|
|
]
|
|
);
|
|
}
|
|
];
|
|
};
|
|
};
|
|
}
|