Files
Nomarchy/installer/hardware-db.sh
Bernardo Magri ec6046793e fix(installer): hardware-db references real modules + add ROG Ally + CI lint
Audited every entry in `installer/hardware-db.sh` against
`inputs.nixos-hardware.nixosModules` and found **21 of 43 entries (49%)
referenced modules that don't exist** in the upstream attribute set —
those installs would fail at eval time with "attribute not found"
errors on real hardware. Specifically:

  - Framework 13 per-gen: nixos-hardware uses `framework-11th-gen-intel`,
    not `framework-13-11th-gen-intel`. Fixed all four generations.
  - Framework 13 AMD AI 300: `framework-amd-ai-300-series` (no "13-").
  - Framework Intel Core Ultra: added `framework-intel-core-ultra-series1`.
  - Framework 16 AMD AI 300: added `framework-16-amd-ai-300-series`.
  - Framework generic fallback now uses the `framework` umbrella module.

  - ThinkPad X1 Carbon: modules are `lenovo-thinkpad-x1-Nth-gen`,
    not `-x1-carbon-genN`. Fixed gens 6/7/9/10/11; added X1 Nano.
  - ThinkPad P14s: requires arch+gen suffix; switched to the AMD gen3/4/5
    modules (the prior `lenovo-thinkpad-p14s` had no attribute).

  - Surface Pro 6/7/8/10: all share `microsoft-surface-pro-intel`. Pro 9
    keeps its dedicated module. Pro 3 fixed to `-pro-3`. Surface Book
    2/3 and Intel-based Surface Laptop 3/4/5: no nixos-hardware module
    — rows dropped; generic chassis+cpu+gpu detection still emits
    sensible `common-pc-laptop`.

  - ASUS ROG Strix G513 → `asus-rog-strix-g513im` (correct attr name).
  - ASUS ROG Zephyrus GA403 didn't exist — dropped. Added `ga402x`,
    `gu603h`, `g533zw`.
  - ASUS Zenbook generic `asus-zenbook-ux` was non-existent — dropped
    (too vague; available modules are per-model like `asus-zenbook-ux481`).

  - Dell Latitude 5400 / 7480: no modules — replaced with the existing
    `dell-latitude-7420`, `7430`, `7490`.

Added:

  - ROG Ally / Ally X support (`asus-ally-rc71l` for `RC71L`,
    `RC72LA`, and the "ROG Ally" product string). nixos-hardware
    currently ships one module for both revisions.

Documented (in a footer comment) the devices nixos-hardware doesn't
cover so they're known-unsupported rather than accidentally missing:

  - Valve Steam Deck → Jovian-NixOS as a separate flake input.
  - Snapdragon X laptops → aarch64 only; Nomarchy installer is x86_64.
  - Raspberry Pi → same as above.

Bug discovered along the way: the DB's pipe-separated row format
collides with bash regex alternation. A row like
`Microsoft|Surface Pro (10|8|7|6)|_|module` parses as 7 fields, with
"7" extracted as the module name. Surface Pro variants are now one
row per version.

CI gate added (`.forgejo/workflows/check.yml`): a new step extracts
every 4th-pipe-field from `HARDWARE_DB` and `comm -23`s it against
`inputs.nixos-hardware.nixosModules`. Any future entry pointing at a
non-existent module fails CI with a clear error. Closes the regression
class entirely.

Verified locally: bash -n + shellcheck --severity=error pass on
hardware-db.sh; the CI step's exact commands pass against the new DB.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-18 18:31:48 +01:00

213 lines
9.7 KiB
Bash

# Nomarchy Hardware Database
#
# Flat table mapping detected DMI fields to `nixos-hardware` flake modules.
# Sourced by installer/install.sh at runtime.
#
# Format (pipe-separated):
# sys_vendor_regex | product_regex | nomarchy_hw_opt | nixos_hardware_module
#
# - Matching is bash `[[ =~ ]]` regex, case-insensitive.
# - Use "_" for `nomarchy_hw_opt` when there's no Nomarchy toggle to set.
# - Multiple modules can be joined with "+" if a device needs >1.
# - First match wins — put more specific entries (e.g. exact model years) above
# broader fallbacks.
#
# To add a new device: grab the string from `/sys/class/dmi/id/product_name`
# on the target machine and add a line here. See:
# https://github.com/NixOS/nixos-hardware/tree/master/<vendor>
# for the list of available module attributes.
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|isFramework=true|framework-16-7040-amd"
"Framework|Laptop 16.*Ryzen AI 300|isFramework=true|framework-16-amd-ai-300-series"
"Framework|Laptop 13.*Ryzen AI 300|isFramework=true|framework-amd-ai-300-series"
"Framework|Laptop 13.*Ryzen 7040|isFramework=true|framework-13-7040-amd"
"Framework|Laptop 13.*Core Ultra|isFramework=true|framework-intel-core-ultra-series1"
"Framework|Laptop 13.*13th Gen Intel|isFramework=true|framework-13th-gen-intel"
"Framework|Laptop 13.*12th Gen Intel|isFramework=true|framework-12th-gen-intel"
"Framework|Laptop 13.*11th Gen Intel|isFramework=true|framework-11th-gen-intel"
"Framework|Laptop \(13.*|isFramework=true|framework"
# Dell XPS / Precision / Latitude ----------------------------------------
"Dell|XPS 15 9500|isXPS=true|dell-xps-15-9500"
"Dell|XPS 15 9510|isXPS=true|dell-xps-15-9510"
"Dell|XPS 15 9520|isXPS=true|dell-xps-15-9520"
"Dell|XPS 13 9310|isXPS=true|dell-xps-13-9310"
"Dell|XPS 13 9370|isXPS=true|dell-xps-13-9370"
"Dell|XPS 13 9380|isXPS=true|dell-xps-13-9380"
"Dell|XPS 13 7390|isXPS=true|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" — both naming schemes appeared in nixos-hardware and
# the old DB references picked the wrong one. Carbon-specific quirks
# match the X1 modules because 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: Intel Surface
# Pros (6 through 10) all use `microsoft-surface-pro-intel`; AMD Surface
# Laptops use `microsoft-surface-laptop-amd`. Surface Pro 9 has its own
# variant for the SQ3 / ARM model — kept separate. Surface Book and
# Intel-based Surface Laptops have no dedicated module; we fall back to
# the common detection (chassis + cpu + gpu).
"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 --------------------------------------
# Ally is the handheld (Z1 Extreme / Z1). RC71L is the original Ally,
# RC72LA is the Ally X — both share the same nixos-hardware module
# currently.
"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 falls back to asahi elsewhere) ---------------
"Apple.*|MacBookPro15|isT2Mac=true|apple-t2"
"Apple.*|MacBookPro16|isT2Mac=true|apple-t2"
"Apple.*|MacBookAir8|isT2Mac=true|apple-t2"
"Apple.*|MacBookAir9|isT2Mac=true|apple-t2"
"Apple.*|iMac19|isT2Mac=true|apple-t2"
"Apple.*|iMacPro1|isT2Mac=true|apple-t2"
# System76 ---------------------------------------------------------------
"System76|Oryx Pro.*|_|system76"
"System76|Lemur Pro.*|_|system76"
"System76|Darter Pro.*|_|system76"
"System76|Galago Pro.*|_|system76"
"System76|Pangolin.*|_|system76"
# Devices nixos-hardware doesn't cover (yet) -----------------------------
# Listed here so future contributors know they're known-unsupported, not
# accidentally missing:
# - Valve Steam Deck (Galileo / Jupiter): try Jovian-NixOS as a flake
# input instead — separate ecosystem, not in nixos-hardware.
# - Snapdragon X laptops (Surface Pro 11, Lenovo Yoga Slim 7x, …):
# aarch64-only and the Nomarchy installer is x86_64 only.
# - Raspberry Pi (ARM): same — installer is x86_64 only.
)
# ----------------------------------------------------------------------------
# nomarchy_detect_hw
#
# Inspects DMI + lspci + /sys to figure out which nixos-hardware modules fit
# the running machine. Emits (on stdout) one line per result:
#
# MODULE <module-name>
# OPT <nomarchy_hw_opt> # zero or more, one per line
# DETAIL <human-readable hit>
#
# Return codes: 0 if at least one module was detected, 1 otherwise.
# ----------------------------------------------------------------------------
nomarchy_detect_hw() {
local sys_vendor product_name board_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 "")
board_name=$(cat /sys/class/dmi/id/board_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 multiple; handle 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
# Laptop / SSD ----------------------------------------------------------
if compgen -G "/sys/class/power_supply/BAT*" >/dev/null; then
echo "MODULE common-pc-laptop"
echo "DETAIL chassis: laptop (battery present)"
detected=1
else
echo "MODULE common-pc"
echo "DETAIL chassis: desktop"
detected=1
fi
# Model-specific match from the DB --------------------------------------
local entry v_re p_re opt mod
for entry in "${HARDWARE_DB[@]}"; do
IFS='|' read -r v_re p_re opt mod <<< "$entry"
shopt -s nocasematch
if [[ "$sys_vendor" =~ $v_re ]] && [[ "$product_name" =~ $p_re ]]; then
shopt -u nocasematch
echo "MODULE $mod"
[[ "$opt" != "_" ]] && echo "OPT $opt"
echo "DETAIL model: $sys_vendor $product_name$mod"
detected=1
break
fi
shopt -u nocasematch
done
return $(( 1 - detected ))
}
# ----------------------------------------------------------------------------
# nomarchy_hw_summary
#
# Pretty-prints the output of `nomarchy_detect_hw` for TUI consumption.
# Reads from stdin.
# ----------------------------------------------------------------------------
nomarchy_hw_summary() {
local line key val
while IFS= read -r line; do
key="${line%% *}"
val="${line#* }"
case "$key" in
DETAIL) echo "$val" ;;
esac
done
}