Compare commits
2 Commits
877da19770
...
04512eabcd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04512eabcd | ||
|
|
528447cc19 |
11
core/system/branding.nix
Normal file
11
core/system/branding.nix
Normal file
@@ -0,0 +1,11 @@
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
# Identify the distribution as Nomarchy in /etc/os-release.
|
||||
# Anything that reads os-release picks this up: fastfetch, login banners,
|
||||
# GUI "About" dialogs, neofetch, etc.
|
||||
system.nixos = {
|
||||
distroId = "nomarchy";
|
||||
distroName = "Nomarchy";
|
||||
};
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
imports = [
|
||||
./options.nix
|
||||
./state.nix
|
||||
./branding.nix
|
||||
./graphics.nix
|
||||
./nix.nix
|
||||
./scripts.nix
|
||||
|
||||
21
flake.nix
21
flake.nix
@@ -38,13 +38,14 @@
|
||||
system = "x86_64-linux";
|
||||
lib = nixpkgs.lib;
|
||||
|
||||
# Overlays
|
||||
overlays = [
|
||||
(final: prev: {
|
||||
makima-bin = prev.makima;
|
||||
nomarchy-system-scripts = final.callPackage ./core/system/scripts-derivation.nix { };
|
||||
})
|
||||
];
|
||||
# Overlays — the function form lives here so both Nomarchy itself and
|
||||
# any downstream flake (see `overlays.default` in the outputs) can layer
|
||||
# the same Nomarchy packages onto their nixpkgs.
|
||||
nomarchyOverlay = final: prev: {
|
||||
makima-bin = prev.makima;
|
||||
nomarchy-system-scripts = final.callPackage ./core/system/scripts-derivation.nix { };
|
||||
};
|
||||
overlays = [ nomarchyOverlay ];
|
||||
|
||||
pkgs = import nixpkgs {
|
||||
inherit system overlays;
|
||||
@@ -90,6 +91,12 @@
|
||||
# Expose inputs for downstream use
|
||||
inherit inputs;
|
||||
|
||||
# Downstream flakes consume this to layer Nomarchy's packages onto their
|
||||
# own nixpkgs. Used by the installer-generated flake so both the
|
||||
# nixosSystem and the standalone homeManagerConfiguration share one
|
||||
# `pkgs` with the overlay applied.
|
||||
overlays.default = nomarchyOverlay;
|
||||
|
||||
nixosModules = {
|
||||
system = import ./core;
|
||||
home = import ./features;
|
||||
|
||||
@@ -17,12 +17,13 @@
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
# EFI System Partition
|
||||
# EFI System Partition. 1 GiB leaves room for several kernel
|
||||
# generations + initrd + Plymouth assets without filling up.
|
||||
ESP = {
|
||||
priority = 1;
|
||||
name = "ESP";
|
||||
start = "1M";
|
||||
end = "512M";
|
||||
end = "1G";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
@@ -32,16 +33,17 @@
|
||||
};
|
||||
};
|
||||
|
||||
# LUKS-encrypted root partition
|
||||
# LUKS-encrypted root partition. The installer writes the
|
||||
# passphrase to an in-memory tmpfs (/dev/shm/nomarchy-luks.key)
|
||||
# rather than the spinning /tmp so the secret never touches disk.
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted";
|
||||
# Password will be provided via /tmp/secret.key
|
||||
settings = {
|
||||
allowDiscards = true; # Enable TRIM for SSDs
|
||||
passwordFile = "/tmp/secret.key";
|
||||
passwordFile = "/dev/shm/nomarchy-luks.key";
|
||||
};
|
||||
content = {
|
||||
type = "btrfs";
|
||||
@@ -76,6 +78,13 @@
|
||||
mountpoint = "/var/log";
|
||||
mountOptions = [ "compress=zstd" "noatime" ];
|
||||
};
|
||||
|
||||
# Snapshots — kept off the rolled-back root so tools like
|
||||
# snapper / btrbk / nomarchy-rollback have a stable home.
|
||||
"@snapshots" = {
|
||||
mountpoint = "/.snapshots";
|
||||
mountOptions = [ "compress=zstd" "noatime" ];
|
||||
};
|
||||
};
|
||||
|
||||
# Create a read-only snapshot of root for impermanence rollback
|
||||
|
||||
182
installer/hardware-db.sh
Normal file
182
installer/hardware-db.sh
Normal file
@@ -0,0 +1,182 @@
|
||||
# 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 ---------------------------------------------------------------
|
||||
"Framework|Laptop 16.*AMD|isFramework=true|framework-16-7040-amd"
|
||||
"Framework|Laptop 13.*AMD Ryzen AI 300|isFramework=true|framework-13-amd-ai-300-series"
|
||||
"Framework|Laptop 13.*AMD Ryzen 7040|isFramework=true|framework-13-7040-amd"
|
||||
"Framework|Laptop 13.*13th Gen Intel|isFramework=true|framework-13-13th-gen-intel"
|
||||
"Framework|Laptop 13.*12th Gen Intel|isFramework=true|framework-13-12th-gen-intel"
|
||||
"Framework|Laptop 13.*11th Gen Intel|isFramework=true|framework-13-11th-gen-intel"
|
||||
"Framework|Laptop \(13.*|isFramework=true|framework-13-11th-gen-intel"
|
||||
|
||||
# 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 7480|_|dell-latitude-7480"
|
||||
"Dell|Latitude 5400|_|dell-latitude-5400"
|
||||
|
||||
# Lenovo ThinkPad --------------------------------------------------------
|
||||
"LENOVO|ThinkPad X1 Carbon Gen 11|_|lenovo-thinkpad-x1-carbon-gen11"
|
||||
"LENOVO|ThinkPad X1 Carbon Gen 10|_|lenovo-thinkpad-x1-carbon-gen10"
|
||||
"LENOVO|ThinkPad X1 Carbon Gen 9|_|lenovo-thinkpad-x1-carbon-gen9"
|
||||
"LENOVO|ThinkPad X1 Extreme|_|lenovo-thinkpad-x1-extreme"
|
||||
"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|_|lenovo-thinkpad-p14s"
|
||||
|
||||
# Microsoft Surface ------------------------------------------------------
|
||||
"Microsoft|Surface Pro 9|_|microsoft-surface-pro-9"
|
||||
"Microsoft|Surface Pro 8|_|microsoft-surface-pro-8"
|
||||
"Microsoft|Surface Pro 7|_|microsoft-surface-pro-7"
|
||||
"Microsoft|Surface Pro 6|_|microsoft-surface-pro-6"
|
||||
"Microsoft|Surface Laptop 5|_|microsoft-surface-laptop-5"
|
||||
"Microsoft|Surface Laptop 4|_|microsoft-surface-laptop-4"
|
||||
"Microsoft|Surface Laptop 3|_|microsoft-surface-laptop-3"
|
||||
"Microsoft|Surface Go|_|microsoft-surface-go"
|
||||
"Microsoft|Surface Book 3|_|microsoft-surface-book-3"
|
||||
"Microsoft|Surface Book 2|_|microsoft-surface-book-2"
|
||||
|
||||
# ASUS ROG / Zephyrus ----------------------------------------------------
|
||||
"ASUS.*|ROG Zephyrus G14.*2024|_|asus-zephyrus-ga403"
|
||||
"ASUS.*|ROG Zephyrus G14.*2023|_|asus-zephyrus-ga402"
|
||||
"ASUS.*|ROG Zephyrus G14.*2021|_|asus-zephyrus-ga401"
|
||||
"ASUS.*|ROG Zephyrus G15|_|asus-zephyrus-ga503"
|
||||
"ASUS.*|ROG Strix G15|_|asus-rog-strix-g513"
|
||||
"ASUS.*|Zenbook UX|_|asus-zenbook-ux"
|
||||
|
||||
# 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"
|
||||
|
||||
# Raspberry Pi (ARM) — listed for completeness; installer is x86_64 only -
|
||||
# "Raspberry Pi|Raspberry Pi 5|_|raspberry-pi-5"
|
||||
# "Raspberry Pi|Raspberry Pi 4|_|raspberry-pi-4"
|
||||
)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# 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
|
||||
}
|
||||
@@ -8,6 +8,13 @@ set -e
|
||||
# For a customized installation, manually set up your disk and use the generated
|
||||
# flake configuration as a starting point.
|
||||
|
||||
# Load the hardware-detection database — resolved relative to this script so it
|
||||
# works whether we're invoked from /etc/install.sh on the live ISO or straight
|
||||
# from a checkout.
|
||||
_NOMARCHY_INSTALL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# shellcheck source=hardware-db.sh
|
||||
source "$_NOMARCHY_INSTALL_DIR/hardware-db.sh"
|
||||
|
||||
# Colors and styling
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
@@ -19,6 +26,8 @@ BOLD='\033[1m'
|
||||
|
||||
# Installer state
|
||||
NOMARCHY_REPO=""
|
||||
NOMARCHY_REV=""
|
||||
HOSTNAME=""
|
||||
TARGET_DRIVE=""
|
||||
USERNAME=""
|
||||
LUKS_PASSWORD=""
|
||||
@@ -93,6 +102,18 @@ check_environment() {
|
||||
fi
|
||||
success "Found Nomarchy at $NOMARCHY_REPO"
|
||||
|
||||
# Capture the exact commit we're installing from. The generated flake
|
||||
# pins `nomarchy.url` to this revision so the installed system can't
|
||||
# silently drift onto a newer (possibly breaking) main.
|
||||
if command -v git >/dev/null 2>&1 && [[ -d "$NOMARCHY_REPO/.git" ]]; then
|
||||
NOMARCHY_REV=$(git -C "$NOMARCHY_REPO" rev-parse HEAD 2>/dev/null || echo "")
|
||||
fi
|
||||
if [[ -n "$NOMARCHY_REV" ]]; then
|
||||
success "Pinning Nomarchy to $NOMARCHY_REV"
|
||||
else
|
||||
info "Could not determine Nomarchy revision; downstream flake will track main."
|
||||
fi
|
||||
|
||||
# Check internet
|
||||
gum spin --spinner dot --title "Checking internet connection..." -- sleep 1
|
||||
while ! ping -c 1 -W 2 1.1.1.1 &>/dev/null; do
|
||||
@@ -184,6 +205,13 @@ configure_user() {
|
||||
|
||||
success "Username: $USERNAME"
|
||||
|
||||
HOSTNAME=$(nrun gum input --value "nomarchy" --placeholder "Hostname for this machine")
|
||||
if [[ -z "$HOSTNAME" ]] || [[ ! "$HOSTNAME" =~ ^[a-z0-9][a-z0-9-]*$ ]]; then
|
||||
error "Invalid hostname (use lowercase letters, digits, and hyphens only)"
|
||||
exit 1
|
||||
fi
|
||||
success "Hostname: $HOSTNAME"
|
||||
|
||||
# User password (can be same as LUKS or different)
|
||||
info "Set a password for your user account"
|
||||
local pass1 pass2
|
||||
@@ -226,66 +254,147 @@ select_timezone() {
|
||||
select_hardware() {
|
||||
section "Hardware Configuration"
|
||||
|
||||
local product_name cpu_vendor
|
||||
product_name=$(cat /sys/class/dmi/id/product_name 2>/dev/null || echo "Unknown")
|
||||
cpu_vendor=$(lscpu 2>/dev/null | grep "Vendor ID" | awk '{print $3}' || echo "Unknown")
|
||||
|
||||
info "Detected: $product_name"
|
||||
info "CPU: $cpu_vendor"
|
||||
local dmi_vendor dmi_product detect_output
|
||||
dmi_vendor=$(cat /sys/class/dmi/id/sys_vendor 2>/dev/null || echo "Unknown")
|
||||
dmi_product=$(cat /sys/class/dmi/id/product_name 2>/dev/null || echo "Unknown")
|
||||
info "DMI: $dmi_vendor / $dmi_product"
|
||||
echo ""
|
||||
|
||||
# Set CPU-specific module
|
||||
if [[ "$cpu_vendor" == "AuthenticAMD" ]]; then
|
||||
HARDWARE_MODULES="inputs.nixos-hardware.nixosModules.common-cpu-amd"
|
||||
elif [[ "$cpu_vendor" == "GenuineIntel" ]]; then
|
||||
HARDWARE_MODULES="inputs.nixos-hardware.nixosModules.common-cpu-intel"
|
||||
fi
|
||||
# Auto-detect CPU, GPU, chassis, and known model from hardware-db.sh.
|
||||
detect_output=$(nomarchy_detect_hw || true)
|
||||
|
||||
local vendor
|
||||
vendor=$(gum choose --header "Select hardware vendor" \
|
||||
"Generic (Auto-detect)" \
|
||||
"Framework" \
|
||||
"Dell" \
|
||||
"Lenovo" \
|
||||
"Apple (T2 Mac)" \
|
||||
"Microsoft Surface" \
|
||||
"Other...")
|
||||
echo "Auto-detected:"
|
||||
nomarchy_hw_summary <<< "$detect_output"
|
||||
echo ""
|
||||
|
||||
case "$vendor" in
|
||||
*Framework*)
|
||||
local model
|
||||
model=$(gum choose "16-7040-amd" "13-7040-amd" "13-intel-13th-gen" "13-intel-12th-gen")
|
||||
HARDWARE_MODULES="$HARDWARE_MODULES\n inputs.nixos-hardware.nixosModules.framework-$model"
|
||||
NOMARCHY_HW_OPTS="nomarchy.hardware.isFramework = true;"
|
||||
# Collect modules + nomarchy options from the detector output.
|
||||
local modules=() hw_opts=()
|
||||
while IFS= read -r line; do
|
||||
case "$line" in
|
||||
"MODULE "*) modules+=("${line#MODULE }") ;;
|
||||
"OPT "*) hw_opts+=("${line#OPT }") ;;
|
||||
esac
|
||||
done <<< "$detect_output"
|
||||
|
||||
# Let the user accept, extend, or replace the detection.
|
||||
local choice
|
||||
choice=$(nrun gum choose --header "Hardware configuration" \
|
||||
"Accept detected modules" \
|
||||
"Add an extra nixos-hardware module" \
|
||||
"Pick from the manual list (override)")
|
||||
|
||||
case "$choice" in
|
||||
"Add an extra nixos-hardware module")
|
||||
local extra
|
||||
extra=$(nrun gum input --placeholder "e.g. asus-zephyrus-ga401 (no 'nixos-hardware.' prefix)")
|
||||
[[ -n "$extra" ]] && modules+=("$extra")
|
||||
;;
|
||||
*Dell*)
|
||||
local model
|
||||
model=$(gum choose "xps-15-9500" "xps-15-9510" "xps-13-9310" "xps-13-9380" "precision-5530")
|
||||
HARDWARE_MODULES="$HARDWARE_MODULES\n inputs.nixos-hardware.nixosModules.dell-$model"
|
||||
[[ "$model" == *"xps"* ]] && NOMARCHY_HW_OPTS="nomarchy.hardware.isXPS = true;"
|
||||
;;
|
||||
*Lenovo*)
|
||||
local model
|
||||
model=$(gum choose "thinkpad-x1-carbon-gen10" "thinkpad-t14-amd" "thinkpad-t480" "thinkpad-x1-extreme")
|
||||
HARDWARE_MODULES="$HARDWARE_MODULES\n inputs.nixos-hardware.nixosModules.lenovo-$model"
|
||||
;;
|
||||
*Apple*)
|
||||
NOMARCHY_HW_OPTS="nomarchy.hardware.isT2Mac = true;"
|
||||
;;
|
||||
*Surface*)
|
||||
local model
|
||||
model=$(gum choose "surface-pro-9" "surface-pro-8" "surface-laptop-4")
|
||||
HARDWARE_MODULES="$HARDWARE_MODULES\n inputs.nixos-hardware.nixosModules.microsoft-$model"
|
||||
;;
|
||||
*Other*)
|
||||
info "Enter nixos-hardware module path (or leave empty):"
|
||||
local custom_mod
|
||||
custom_mod=$(gum input --placeholder "e.g., inputs.nixos-hardware.nixosModules.asus-zephyrus-ga401")
|
||||
[[ -n "$custom_mod" ]] && HARDWARE_MODULES="$HARDWARE_MODULES\n $custom_mod"
|
||||
"Pick from the manual list (override)")
|
||||
modules=()
|
||||
hw_opts=()
|
||||
_select_hardware_manual modules hw_opts
|
||||
;;
|
||||
esac
|
||||
|
||||
success "Hardware configuration set"
|
||||
# De-duplicate while preserving order.
|
||||
local seen="" uniq_mods=() m
|
||||
for m in "${modules[@]}"; do
|
||||
if [[ ":$seen:" != *":$m:"* ]]; then
|
||||
uniq_mods+=("$m")
|
||||
seen="$seen:$m"
|
||||
fi
|
||||
done
|
||||
|
||||
# Emit a list the heredoc in generate_flake_config splats into
|
||||
# hardware-selection.nix's imports. The heredoc already indents the first
|
||||
# line by 4 spaces — we add real newlines + 4 spaces (via $'\n ') for
|
||||
# subsequent lines so every entry lines up.
|
||||
HARDWARE_MODULES=""
|
||||
for m in "${uniq_mods[@]}"; do
|
||||
[[ -z "$HARDWARE_MODULES" ]] || HARDWARE_MODULES+=$'\n '
|
||||
HARDWARE_MODULES+="inputs.nixos-hardware.nixosModules.${m}"
|
||||
done
|
||||
|
||||
# Same treatment for nomarchy.hardware.* toggles.
|
||||
NOMARCHY_HW_OPTS=""
|
||||
local o
|
||||
for o in "${hw_opts[@]}"; do
|
||||
# opt is e.g. `isFramework=true` → `nomarchy.hardware.isFramework = true;`
|
||||
local key="${o%%=*}" val="${o#*=}"
|
||||
NOMARCHY_HW_OPTS+="nomarchy.hardware.${key} = ${val};"$'\n '
|
||||
done
|
||||
|
||||
success "Hardware configuration set (${#uniq_mods[@]} module$([[ ${#uniq_mods[@]} -eq 1 ]] || echo s))"
|
||||
}
|
||||
|
||||
# Manual fallback menu, kept for odd hardware the DB doesn't recognise yet.
|
||||
# Writes into the two arrays named by its arguments (bash 4.3+ nameref).
|
||||
_select_hardware_manual() {
|
||||
local -n _mods_ref="$1"
|
||||
local -n _opts_ref="$2"
|
||||
|
||||
local vendor
|
||||
vendor=$(nrun gum choose --header "Pick vendor" \
|
||||
"Framework" "Dell" "Lenovo" "Apple (T2 Mac)" "Microsoft Surface" "ASUS" "System76" "Other...")
|
||||
|
||||
case "$vendor" in
|
||||
Framework)
|
||||
local model
|
||||
model=$(nrun gum choose \
|
||||
"framework-16-7040-amd" \
|
||||
"framework-13-amd-ai-300-series" \
|
||||
"framework-13-7040-amd" \
|
||||
"framework-13-13th-gen-intel" \
|
||||
"framework-13-12th-gen-intel" \
|
||||
"framework-13-11th-gen-intel")
|
||||
_mods_ref+=("$model")
|
||||
_opts_ref+=("isFramework=true")
|
||||
;;
|
||||
Dell)
|
||||
local model
|
||||
model=$(nrun gum choose \
|
||||
"dell-xps-15-9500" "dell-xps-15-9510" "dell-xps-15-9520" \
|
||||
"dell-xps-13-9310" "dell-xps-13-9370" "dell-xps-13-9380" \
|
||||
"dell-precision-5530" "dell-latitude-7480")
|
||||
_mods_ref+=("$model")
|
||||
[[ "$model" == *xps* ]] && _opts_ref+=("isXPS=true")
|
||||
;;
|
||||
Lenovo)
|
||||
local model
|
||||
model=$(nrun gum choose \
|
||||
"lenovo-thinkpad-x1-carbon-gen11" "lenovo-thinkpad-x1-carbon-gen10" \
|
||||
"lenovo-thinkpad-x1-carbon-gen9" "lenovo-thinkpad-x1-extreme" \
|
||||
"lenovo-thinkpad-t14-amd-gen3" "lenovo-thinkpad-t14-amd-gen2" \
|
||||
"lenovo-thinkpad-t480" "lenovo-thinkpad-l13")
|
||||
_mods_ref+=("$model")
|
||||
;;
|
||||
"Apple (T2 Mac)")
|
||||
_mods_ref+=("apple-t2")
|
||||
_opts_ref+=("isT2Mac=true")
|
||||
;;
|
||||
"Microsoft Surface")
|
||||
local model
|
||||
model=$(nrun gum choose \
|
||||
"microsoft-surface-pro-9" "microsoft-surface-pro-8" "microsoft-surface-pro-7" \
|
||||
"microsoft-surface-laptop-5" "microsoft-surface-laptop-4" "microsoft-surface-laptop-3")
|
||||
_mods_ref+=("$model")
|
||||
;;
|
||||
ASUS)
|
||||
local model
|
||||
model=$(nrun gum choose \
|
||||
"asus-zephyrus-ga403" "asus-zephyrus-ga402" "asus-zephyrus-ga401" \
|
||||
"asus-zephyrus-ga503" "asus-rog-strix-g513" "asus-zenbook-ux")
|
||||
_mods_ref+=("$model")
|
||||
;;
|
||||
System76)
|
||||
_mods_ref+=("system76")
|
||||
;;
|
||||
"Other...")
|
||||
local custom
|
||||
custom=$(nrun gum input --placeholder "e.g. asus-zephyrus-ga401 (no 'nixos-hardware.' prefix)")
|
||||
[[ -n "$custom" ]] && _mods_ref+=("$custom")
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
@@ -316,9 +425,11 @@ review_configuration() {
|
||||
section "Review Configuration"
|
||||
|
||||
echo " Drive: $TARGET_DRIVE (BTRFS + LUKS2)"
|
||||
echo " Hostname: $HOSTNAME"
|
||||
echo " Username: $USERNAME"
|
||||
echo " Timezone: $TIMEZONE"
|
||||
echo " Impermanence: $ENABLE_IMPERMANENCE"
|
||||
echo " Nomarchy rev: ${NOMARCHY_REV:-main (unpinned)}"
|
||||
echo ""
|
||||
|
||||
nrun gum style --foreground 9 "This will DESTROY all data on $TARGET_DRIVE"
|
||||
@@ -345,10 +456,16 @@ execute_installation() {
|
||||
|
||||
sed "s|@TARGET_DRIVE@|${TARGET_DRIVE}|g" "$disko_file" > "$tmp_disko"
|
||||
|
||||
# Provide the LUKS passphrase via a temporary file for disk encryption
|
||||
echo -n "$LUKS_PASSWORD" > /tmp/secret.key
|
||||
# Provide the LUKS passphrase via tmpfs so the secret never touches a
|
||||
# spinning disk. /dev/shm is tmpfs on the live ISO. We restrict perms
|
||||
# to root and shred the file (overwrite) on the way out, even though
|
||||
# it's already in RAM — defense in depth.
|
||||
local luks_key="/dev/shm/nomarchy-luks.key"
|
||||
install -m 600 /dev/null "$luks_key"
|
||||
printf '%s' "$LUKS_PASSWORD" > "$luks_key"
|
||||
disko --mode disko "$tmp_disko"
|
||||
rm /tmp/secret.key
|
||||
shred -u "$luks_key" 2>/dev/null || rm -f "$luks_key"
|
||||
unset LUKS_PASSWORD
|
||||
success "Disk partitioned"
|
||||
|
||||
# 9.2 Generate hardware config
|
||||
@@ -362,7 +479,16 @@ execute_installation() {
|
||||
generate_flake_config
|
||||
success "Configuration generated"
|
||||
|
||||
# 9.4 Initialize git repo
|
||||
# 9.4 Resolve inputs once, here, and lock them. First boot then consumes
|
||||
# the same flake.lock and doesn't re-resolve a newer upstream.
|
||||
info "Resolving flake inputs (this pins nomarchy, nixpkgs, etc.)..."
|
||||
(
|
||||
cd /mnt/etc/nixos
|
||||
nix --extra-experimental-features "nix-command flakes" flake lock >/dev/null
|
||||
)
|
||||
success "flake.lock written"
|
||||
|
||||
# 9.5 Initialize git repo so `nix` treats /etc/nixos as a flake worktree.
|
||||
info "Initializing git repository..."
|
||||
(
|
||||
cd /mnt/etc/nixos
|
||||
@@ -374,7 +500,7 @@ execute_installation() {
|
||||
)
|
||||
success "Git repository initialized"
|
||||
|
||||
# 9.5 Handle impermanence
|
||||
# 9.6 Handle impermanence
|
||||
if [[ "$ENABLE_IMPERMANENCE" == "true" ]]; then
|
||||
info "Setting up impermanence..."
|
||||
mkdir -p /mnt/persist/etc
|
||||
@@ -384,9 +510,30 @@ execute_installation() {
|
||||
success "Impermanence configured"
|
||||
fi
|
||||
|
||||
# 9.6 Install
|
||||
# 9.7 Install the NixOS system from the freshly-generated flake.
|
||||
info "Running nixos-install (this will take a while)..."
|
||||
nixos-install --flake /mnt/etc/nixos#default --no-root-passwd
|
||||
nixos-install --flake "/mnt/etc/nixos#$HOSTNAME" --no-root-passwd
|
||||
success "NixOS installed"
|
||||
|
||||
# 9.8 Activate Home Manager for $USERNAME inside the new system so the
|
||||
# user's first login already has Nomarchy's dotfiles. `home-manager
|
||||
# switch` must run as the target user with a real $HOME, so we use
|
||||
# `runuser` (sudo -u keeps the caller's HOME → files land in /root).
|
||||
info "Activating Home Manager for $USERNAME..."
|
||||
if nixos-enter --root /mnt -- bash -c "
|
||||
set -e
|
||||
install -d -o '$USERNAME' -g users -m 0755 '/home/$USERNAME'
|
||||
runuser -u '$USERNAME' -- env HOME='/home/$USERNAME' \
|
||||
nix --extra-experimental-features 'nix-command flakes' \
|
||||
run 'home-manager/release-25.11' -- switch \
|
||||
--flake '/etc/nixos#$USERNAME' --impure
|
||||
"; then
|
||||
success "Home Manager activated"
|
||||
else
|
||||
error "Home Manager activation failed (non-fatal)."
|
||||
info "Run \`nomarchy-env-update\` after the first login to retry."
|
||||
fi
|
||||
|
||||
success "Installation complete!"
|
||||
}
|
||||
|
||||
@@ -398,14 +545,25 @@ generate_flake_config() {
|
||||
local impermanence_opt=""
|
||||
[[ "$ENABLE_IMPERMANENCE" == "true" ]] && impermanence_opt="nomarchy.system.impermanence.enable = true;"
|
||||
|
||||
# flake.nix
|
||||
cat > /mnt/etc/nixos/flake.nix << 'FLAKE_EOF'
|
||||
# Pin the upstream Nomarchy flake to the exact commit we're installing
|
||||
# from so the first post-reboot `nixos-rebuild` doesn't silently pull a
|
||||
# newer main. Fall back to tracking main if we couldn't resolve a SHA.
|
||||
local nomarchy_url
|
||||
if [[ -n "$NOMARCHY_REV" ]]; then
|
||||
nomarchy_url="github:bemagri/nomarchy/$NOMARCHY_REV"
|
||||
else
|
||||
nomarchy_url="github:bemagri/nomarchy"
|
||||
fi
|
||||
|
||||
# flake.nix — the generator uses a non-quoted heredoc so $HOSTNAME,
|
||||
# $USERNAME, and $nomarchy_url expand inline.
|
||||
cat > /mnt/etc/nixos/flake.nix <<FLAKE_EOF
|
||||
{
|
||||
description = "My Nomarchy Configuration";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
|
||||
nomarchy.url = "github:bemagri/nomarchy";
|
||||
nomarchy.url = "$nomarchy_url";
|
||||
nixos-hardware.url = "github:NixOS/nixos-hardware/master";
|
||||
home-manager = {
|
||||
url = "github:nix-community/home-manager/release-25.11";
|
||||
@@ -413,35 +571,52 @@ generate_flake_config() {
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, nomarchy, home-manager, nixos-hardware, ... }@inputs: {
|
||||
nixosConfigurations.default = nixpkgs.lib.nixosSystem {
|
||||
specialArgs = { inputs = nomarchy.inputs // inputs; };
|
||||
modules = [
|
||||
{ nixpkgs.hostPlatform = "x86_64-linux"; }
|
||||
./hardware-configuration.nix
|
||||
./hardware-selection.nix
|
||||
nomarchy.nixosModules.system
|
||||
./system.nix
|
||||
];
|
||||
};
|
||||
# Two-track Nomarchy workflow:
|
||||
# * System changes → sudo nixos-rebuild switch --flake /etc/nixos#$HOSTNAME
|
||||
# * Dotfiles/themes → nomarchy-env-update (home-manager switch, no rebuild)
|
||||
#
|
||||
# Both consume the same \`pkgs\` below so overlays and allowUnfree stay in
|
||||
# sync across the two paths.
|
||||
outputs = { self, nixpkgs, nomarchy, home-manager, nixos-hardware, ... }@inputs:
|
||||
let
|
||||
system = "x86_64-linux";
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [ nomarchy.overlays.default ];
|
||||
config.allowUnfree = true;
|
||||
};
|
||||
in
|
||||
{
|
||||
nixosConfigurations.$HOSTNAME = nixpkgs.lib.nixosSystem {
|
||||
inherit pkgs;
|
||||
specialArgs = { inputs = nomarchy.inputs // inputs; };
|
||||
modules = [
|
||||
./hardware-configuration.nix
|
||||
./hardware-selection.nix
|
||||
nomarchy.nixosModules.system
|
||||
./system.nix
|
||||
];
|
||||
};
|
||||
|
||||
homeConfigurations.@USERNAME@ = home-manager.lib.homeManagerConfiguration {
|
||||
pkgs = nixpkgs.legacyPackages.x86_64-linux;
|
||||
extraSpecialArgs = { inputs = nomarchy.inputs // inputs; };
|
||||
modules = [
|
||||
nomarchy.nixosModules.home
|
||||
./home.nix
|
||||
{
|
||||
home.username = "@USERNAME@";
|
||||
home.homeDirectory = "/home/@USERNAME@";
|
||||
home.stateVersion = "25.11";
|
||||
}
|
||||
];
|
||||
# Standalone Home Manager — \`home-manager switch --flake /etc/nixos#$USERNAME\`
|
||||
# (which is what \`nomarchy-env-update\` runs). Kept separate from the
|
||||
# NixOS config so dotfile/theme iterations don't rebuild the system.
|
||||
homeConfigurations.$USERNAME = home-manager.lib.homeManagerConfiguration {
|
||||
inherit pkgs;
|
||||
extraSpecialArgs = { inputs = nomarchy.inputs // inputs; };
|
||||
modules = [
|
||||
nomarchy.nixosModules.home
|
||||
./home.nix
|
||||
{
|
||||
home.username = "$USERNAME";
|
||||
home.homeDirectory = "/home/$USERNAME";
|
||||
home.stateVersion = "25.11";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
FLAKE_EOF
|
||||
sed -i "s/@USERNAME@/$USERNAME/g" /mnt/etc/nixos/flake.nix
|
||||
|
||||
# hardware-selection.nix
|
||||
cat > /mnt/etc/nixos/hardware-selection.nix << EOF
|
||||
@@ -455,10 +630,11 @@ FLAKE_EOF
|
||||
EOF
|
||||
|
||||
# system.nix — curated system-level options. Uncomment what you want and
|
||||
# run \`sudo nixos-rebuild switch --flake /etc/nixos#default\` to apply.
|
||||
# run \`sudo nixos-rebuild switch --flake /etc/nixos#$HOSTNAME\` to apply.
|
||||
cat > /mnt/etc/nixos/system.nix << EOF
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
networking.hostName = "$HOSTNAME";
|
||||
time.timeZone = "$TIMEZONE";
|
||||
|
||||
$impermanence_opt
|
||||
@@ -609,8 +785,12 @@ finish() {
|
||||
echo "Next steps:"
|
||||
echo " 1. Remove the installation media"
|
||||
echo " 2. Reboot your computer"
|
||||
echo " 3. Log in with username: $USERNAME"
|
||||
echo " 4. Your configuration is at /etc/nixos/"
|
||||
echo " 3. Log in as: $USERNAME (host: $HOSTNAME)"
|
||||
echo " 4. Your configuration lives at /etc/nixos/"
|
||||
echo ""
|
||||
echo "Rebuild commands:"
|
||||
echo " • System: sudo nixos-rebuild switch --flake /etc/nixos#$HOSTNAME"
|
||||
echo " • Dotfiles: nomarchy-env-update (runs home-manager switch)"
|
||||
echo ""
|
||||
echo "Tip: run 'nomarchy-themes-prebuild' once to pre-cache every theme"
|
||||
echo " variant. Theme switches after that are instant (no rebuild)."
|
||||
@@ -641,7 +821,3 @@ main() {
|
||||
}
|
||||
|
||||
main "$@"
|
||||
finish
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
Reference in New Issue
Block a user