feat: nomarchy-install — guided live-ISO installer (disko + mkFlake)

Ported from the previous iteration's installer (3bdfc35), adapted to the
mkFlake world. gum TUI: disk pick, optional LUKS2, user/hostname/timezone,
DMI → nixos-hardware autodetection (hardware-db.sh). disko partitions
GPT + 1 GiB ESP + BTRFS subvolumes; the generated machine flake lands at
~user/.nomarchy (one mkFlake call, /etc/nixos symlinks to it) and
nixos-install makes it bootable (UEFI/systemd-boot, v1 single disk).

Offline by construction: the target flake.lock is composed from the rev
the ISO was built from (compose-lock.py), `nix flake archive` seeds the
target store, and the ISO pre-builds the template system + desktop.
First boot lands themed: the HM generation is pre-activated in chroot.

mkFlake grows two things for this: hardwareProfile now also takes a list
(autodetection emits several common-* modules), and installed systems get
the standalone home-manager CLI from the pinned input. Unattended mode
(NOMARCHY_UNATTENDED=1 + env) documented in docs/TESTING.md §4.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Bernardo Magri
2026-06-10 16:05:29 +01:00
parent 8ded92ea63
commit f3707357a6
10 changed files with 862 additions and 18 deletions

View File

@@ -0,0 +1,177 @@
# Nomarchy hardware database — sourced by nomarchy-install.
#
# Flat table mapping detected DMI fields to nixos-hardware module names
# (the strings nomarchy.lib.mkFlake's hardwareProfile accepts). Ported
# from the previous iteration (installer/hardware-db.sh at 3bdfc35).
#
# Format (pipe-separated):
# sys_vendor_regex | product_regex | nixos_hardware_module
#
# - Matching is bash `[[ =~ ]]` regex, case-insensitive.
# - First match wins — put more specific entries (e.g. exact model years)
# above broader fallbacks.
#
# To add a new device: grab `/sys/class/dmi/id/product_name` on the
# target machine and add a line. Module names must exist in
# nixos-hardware.nixosModules (mkFlake fails with suggestions if not).
HARDWARE_DB=(
# Framework ---------------------------------------------------------------
# Module names follow nixos-hardware's actual attrs — for Framework 13
# the per-generation modules dropped the "13-" prefix.
"Framework|Laptop 16.*AMD|framework-16-7040-amd"
"Framework|Laptop 16.*Ryzen AI 300|framework-16-amd-ai-300-series"
"Framework|Laptop 13.*Ryzen AI 300|framework-amd-ai-300-series"
"Framework|Laptop 13.*Ryzen 7040|framework-13-7040-amd"
"Framework|Laptop 13.*Core Ultra|framework-intel-core-ultra-series1"
"Framework|Laptop 13.*13th Gen Intel|framework-13th-gen-intel"
"Framework|Laptop 13.*12th Gen Intel|framework-12th-gen-intel"
"Framework|Laptop 13.*11th Gen Intel|framework-11th-gen-intel"
"Framework|Laptop \(13.*|framework"
# Dell XPS / Precision / Latitude ----------------------------------------
"Dell|XPS 15 9500|dell-xps-15-9500"
"Dell|XPS 15 9510|dell-xps-15-9510"
"Dell|XPS 15 9520|dell-xps-15-9520"
"Dell|XPS 13 9310|dell-xps-13-9310"
"Dell|XPS 13 9370|dell-xps-13-9370"
"Dell|XPS 13 9380|dell-xps-13-9380"
"Dell|XPS 13 7390|dell-xps-13-7390"
"Dell|Precision 5530|dell-precision-5530"
"Dell|Latitude 7490|dell-latitude-7490"
"Dell|Latitude 7430|dell-latitude-7430"
"Dell|Latitude 7420|dell-latitude-7420"
# Lenovo ThinkPad --------------------------------------------------------
# X1 Carbon: the per-gen modules are named "x1-Nth-gen", not
# "x1-carbon-genN" — the X1 series IS the Carbon line.
"LENOVO|ThinkPad X1 Carbon Gen 11|lenovo-thinkpad-x1-11th-gen"
"LENOVO|ThinkPad X1 Carbon Gen 10|lenovo-thinkpad-x1-10th-gen"
"LENOVO|ThinkPad X1 Carbon Gen 9|lenovo-thinkpad-x1-9th-gen"
"LENOVO|ThinkPad X1 Carbon Gen 7|lenovo-thinkpad-x1-7th-gen"
"LENOVO|ThinkPad X1 Carbon Gen 6|lenovo-thinkpad-x1-6th-gen"
"LENOVO|ThinkPad X1 Extreme|lenovo-thinkpad-x1-extreme"
"LENOVO|ThinkPad X1 Nano|lenovo-thinkpad-x1-nano-gen1"
"LENOVO|ThinkPad T14 Gen 3|lenovo-thinkpad-t14-amd-gen3"
"LENOVO|ThinkPad T14 Gen 2|lenovo-thinkpad-t14-amd-gen2"
"LENOVO|ThinkPad T14 Gen 1|lenovo-thinkpad-t14-amd-gen1"
"LENOVO|ThinkPad T480|lenovo-thinkpad-t480"
"LENOVO|ThinkPad L13|lenovo-thinkpad-l13"
"LENOVO|ThinkPad P14s.*Gen 5|lenovo-thinkpad-p14s-amd-gen5"
"LENOVO|ThinkPad P14s.*Gen 4|lenovo-thinkpad-p14s-amd-gen4"
"LENOVO|ThinkPad P14s.*Gen 3|lenovo-thinkpad-p14s-amd-gen3"
# Microsoft Surface ------------------------------------------------------
# nixos-hardware ships per-chip modules, not per-revision.
"Microsoft|Surface Pro 10|microsoft-surface-pro-intel"
"Microsoft|Surface Pro 9|microsoft-surface-pro-9"
"Microsoft|Surface Pro 8|microsoft-surface-pro-intel"
"Microsoft|Surface Pro 7|microsoft-surface-pro-intel"
"Microsoft|Surface Pro 6|microsoft-surface-pro-intel"
"Microsoft|Surface Pro 3|microsoft-surface-pro-3"
"Microsoft|Surface Laptop.*Ryzen|microsoft-surface-laptop-amd"
"Microsoft|Surface Go|microsoft-surface-go"
# ASUS ROG Ally / Zephyrus / Strix ---------------------------------------
"ASUS.*|RC71L|asus-ally-rc71l"
"ASUS.*|RC72LA|asus-ally-rc71l"
"ASUS.*|ROG Ally|asus-ally-rc71l"
"ASUS.*|ROG Zephyrus G14.*GA402X|asus-zephyrus-ga402x"
"ASUS.*|ROG Zephyrus G14.*GA402|asus-zephyrus-ga402"
"ASUS.*|ROG Zephyrus G14.*GA401|asus-zephyrus-ga401"
"ASUS.*|ROG Zephyrus G15|asus-zephyrus-ga503"
"ASUS.*|ROG Zephyrus.*GU603|asus-zephyrus-gu603h"
"ASUS.*|ROG Strix G513|asus-rog-strix-g513im"
"ASUS.*|ROG Strix G533|asus-rog-strix-g533zw"
# Apple (T2 Intel; M-series is aarch64 — out of scope) -------------------
"Apple.*|MacBookPro15|apple-t2"
"Apple.*|MacBookPro16|apple-t2"
"Apple.*|MacBookAir8|apple-t2"
"Apple.*|MacBookAir9|apple-t2"
"Apple.*|iMac19|apple-t2"
"Apple.*|iMacPro1|apple-t2"
# System76 ---------------------------------------------------------------
"System76|Oryx Pro.*|system76"
"System76|Lemur Pro.*|system76"
"System76|Darter Pro.*|system76"
"System76|Galago Pro.*|system76"
"System76|Pangolin.*|system76"
# Known-unsupported (so contributors know they're not missing):
# - Valve Steam Deck: Jovian-NixOS territory, not nixos-hardware.
# - Snapdragon X laptops / Raspberry Pi: aarch64; installer is x86_64.
)
# ----------------------------------------------------------------------------
# nomarchy_detect_hw — inspects DMI + lspci + /sys, emits one line per hit:
# MODULE <nixos-hardware module name>
# DETAIL <human-readable explanation>
# Returns 0 if at least one module was detected.
# ----------------------------------------------------------------------------
nomarchy_detect_hw() {
local sys_vendor product_name cpu_vendor
sys_vendor=$(cat /sys/class/dmi/id/sys_vendor 2>/dev/null || echo "")
product_name=$(cat /sys/class/dmi/id/product_name 2>/dev/null || echo "")
cpu_vendor=$(lscpu 2>/dev/null | awk -F: '/Vendor ID/{gsub(/ /,"",$2); print $2; exit}')
local detected=0
# CPU
case "$cpu_vendor" in
AuthenticAMD) echo "MODULE common-cpu-amd"; echo "DETAIL cpu: AMD"; detected=1 ;;
GenuineIntel) echo "MODULE common-cpu-intel"; echo "DETAIL cpu: Intel"; detected=1 ;;
esac
# GPU (lspci may list several; report all)
if command -v lspci >/dev/null 2>&1; then
local gpu_line nvidia=0 amdgpu=0 intelgpu=0
while IFS= read -r gpu_line; do
case "$gpu_line" in
*"[10de:"*|*"NVIDIA"*) nvidia=1 ;;
*"[1002:"*|*"AMD/ATI"*|*"Advanced Micro Devices"*) amdgpu=1 ;;
*"[8086:"*|*"Intel Corporation"*) intelgpu=1 ;;
esac
done < <(lspci -nn 2>/dev/null | grep -iE 'vga|3d|display')
(( nvidia )) && { echo "MODULE common-gpu-nvidia"; echo "DETAIL gpu: NVIDIA"; detected=1; }
(( amdgpu )) && { echo "MODULE common-gpu-amd"; echo "DETAIL gpu: AMD"; detected=1; }
(( intelgpu )) && { echo "MODULE common-gpu-intel"; echo "DETAIL gpu: Intel"; detected=1; }
fi
# Chassis
if compgen -G "/sys/class/power_supply/BAT*" >/dev/null; then
echo "MODULE common-pc-laptop"
echo "DETAIL chassis: laptop (battery present)"
else
echo "MODULE common-pc"
echo "DETAIL chassis: desktop"
fi
detected=1
# SSD
local rotational
rotational=$(cat /sys/block/nvme0n1/queue/rotational 2>/dev/null \
|| cat /sys/block/sda/queue/rotational 2>/dev/null || echo "")
if [[ "$rotational" == "0" ]]; then
echo "MODULE common-pc-ssd"
echo "DETAIL storage: SSD"
fi
# Model-specific match from the DB
local entry v_re p_re mod
for entry in "${HARDWARE_DB[@]}"; do
IFS='|' read -r v_re p_re mod <<< "$entry"
shopt -s nocasematch
if [[ "$sys_vendor" =~ $v_re ]] && [[ "$product_name" =~ $p_re ]]; then
shopt -u nocasematch
echo "MODULE $mod"
echo "DETAIL model: $sys_vendor $product_name$mod"
break
fi
shopt -u nocasematch
done
return $(( 1 - detected ))
}