Add HM bootstrap script and tidy installer workflow
This commit is contained in:
parent
dd15c09fdd
commit
d1713bdc99
10 changed files with 184 additions and 43 deletions
|
|
@ -161,10 +161,9 @@ Example feature module skeleton:
|
||||||
|
|
||||||
## Home Manager Policy
|
## Home Manager Policy
|
||||||
|
|
||||||
* **Home Manager must be integrated as a NixOS module**
|
* Home Manager is **provided as a CLI tool system-wide** (`home-manager` in `environment.systemPackages`).
|
||||||
* No standalone Home Manager flakes
|
* Users manage their own HM configs (per-user, standalone). No system-wide HM module imports.
|
||||||
* No per-user Home Manager flakes
|
* `modules/users/*` must not declare `home-manager.users.*`; keep user accounts declarative via NixOS only.
|
||||||
* User configuration lives under `modules/users/`
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ Run the non-interactive installer:
|
||||||
sudo /etc/nixos/scripts/install-btrfs.sh
|
sudo /etc/nixos/scripts/install-btrfs.sh
|
||||||
|
|
||||||
|
|
||||||
Optionally set DISK and HOSTNAME (defaults: DISK=/dev/vda, HOSTNAME=nanuqsaurus)
|
Optionally set DISK and TARGET_HOST (defaults: DISK=/dev/vda, TARGET_HOST=nanuqsaurus)
|
||||||
|
|
||||||
sudo DISK=/dev/vda HOSTNAME=nanuqsaurus /etc/nixos/scripts/install-btrfs.sh
|
sudo DISK=/dev/vda TARGET_HOST=nanuqsaurus /etc/nixos/scripts/install-btrfs.sh
|
||||||
|
|
||||||
|
|
||||||
The script wipes the whole disk, creates Btrfs subvolumes (root, home, nix), copies the flake, generates hardware config, and installs. It writes host files under `/etc/nixos/hosts/local-<hostname>.nix` and `local-<hostname>-hardware.nix` (kept local to the machine).
|
The script wipes the whole disk, creates Btrfs subvolumes (root, home, nix), copies the flake, generates hardware config, and installs. It writes host files under `/etc/nixos/hosts/local-<hostname>.nix` and `local-<hostname>-hardware.nix` (kept local to the machine).
|
||||||
|
|
@ -16,7 +16,7 @@ The script wipes the whole disk, creates Btrfs subvolumes (root, home, nix), cop
|
||||||
|
|
||||||
If you need a more custom setup please run the partitioning manually, mount the target to /mnt and then install the system:
|
If you need a more custom setup please run the partitioning manually, mount the target to /mnt and then install the system:
|
||||||
|
|
||||||
nixos-install --root /mnt --flake "/mnt/etc/nixos#${HOSTNAME}" --no-root-passwd
|
nixos-install --root /mnt --flake "/mnt/etc/nixos#local-${TARGET_HOST}" --no-root-passwd
|
||||||
|
|
||||||
|
|
||||||
After install finishes, reboot into the new system.
|
After install finishes, reboot into the new system.
|
||||||
|
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
{ config, pkgs, inputs, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
inputs.lix-module.nixosModules.lixFromNixpkgs
|
|
||||||
../modules/system/base.nix
|
|
||||||
../modules/desktop/gnome-minimal.nix
|
|
||||||
../modules/users/admin.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
networking.hostName = "nanuqsaurus";
|
|
||||||
|
|
||||||
environment.etc."INSTALL.txt".source = ../docs/install-help.txt;
|
|
||||||
environment.etc."motd".text = builtins.readFile ../docs/install-help.txt;
|
|
||||||
environment.etc."issue".text = ''
|
|
||||||
${builtins.readFile ../docs/install-help.txt}
|
|
||||||
|
|
||||||
Login: \l
|
|
||||||
'';
|
|
||||||
|
|
||||||
# Place the flake (including scripts) under /etc/nixos in the live system.
|
|
||||||
environment.etc."nixos".source = ../.;
|
|
||||||
}
|
|
||||||
|
|
@ -4,10 +4,6 @@
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
(inputs.nixpkgs + "/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix")
|
(inputs.nixpkgs + "/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix")
|
||||||
inputs.lix-module.nixosModules.lixFromNixpkgs
|
|
||||||
../modules/system/base.nix
|
|
||||||
../modules/desktop/gnome-minimal.nix
|
|
||||||
../modules/users/admin.nix
|
|
||||||
];
|
];
|
||||||
|
|
||||||
networking.hostName = "iso-installer";
|
networking.hostName = "iso-installer";
|
||||||
|
|
|
||||||
14
hosts/nanuqsaurus.nix
Normal file
14
hosts/nanuqsaurus.nix
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
{ config, pkgs, inputs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
inputs.lix-module.nixosModules.lixFromNixpkgs
|
||||||
|
../modules/system/base.nix
|
||||||
|
../modules/system/packages.nix
|
||||||
|
../modules/system/home-manager-skel.nix
|
||||||
|
../modules/desktop/gnome-minimal.nix
|
||||||
|
../modules/users/admin.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.hostName = "nanuqsaurus";
|
||||||
|
}
|
||||||
48
modules/system/home-manager-skel.nix
Normal file
48
modules/system/home-manager-skel.nix
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
{ ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
flakeText = ''
|
||||||
|
{
|
||||||
|
description = "Home Manager configuration of admin";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
|
home-manager = {
|
||||||
|
url = "github:nix-community/home-manager";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { nixpkgs, home-manager, ... }: {
|
||||||
|
homeConfigurations."admin" = home-manager.lib.homeManagerConfiguration {
|
||||||
|
pkgs = nixpkgs.legacyPackages.x86_64-linux;
|
||||||
|
modules = [ ./home.nix ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
|
||||||
|
homeText = ''
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
home.username = "admin";
|
||||||
|
home.homeDirectory = "/home/admin";
|
||||||
|
home.stateVersion = "25.05";
|
||||||
|
|
||||||
|
home.packages = [ pkgs.ptyxis ];
|
||||||
|
|
||||||
|
home.file = { };
|
||||||
|
|
||||||
|
home.sessionVariables = { };
|
||||||
|
|
||||||
|
programs.home-manager.enable = true;
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
environment.etc = {
|
||||||
|
"skel/.config/home-manager/flake.nix".text = flakeText;
|
||||||
|
"skel/.config/home-manager/home.nix".text = homeText;
|
||||||
|
};
|
||||||
|
}
|
||||||
10
modules/system/packages.nix
Normal file
10
modules/system/packages.nix
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
{ lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# Baseline system tools available everywhere; users run Home Manager standalone.
|
||||||
|
config.environment.systemPackages = lib.mkAfter [
|
||||||
|
pkgs.home-manager
|
||||||
|
pkgs.ghostty
|
||||||
|
pkgs.libnotify
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{ lib, ... }:
|
{ lib, pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
users.users.admin = {
|
users.users.admin = {
|
||||||
|
|
@ -8,4 +8,24 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
security.sudo.wheelNeedsPassword = lib.mkDefault true;
|
security.sudo.wheelNeedsPassword = lib.mkDefault true;
|
||||||
|
|
||||||
|
# Bootstrap Home Manager for admin on first login (per-user, standalone)
|
||||||
|
systemd.user.services.hm-bootstrap = {
|
||||||
|
description = "One-time Home Manager bootstrap for admin";
|
||||||
|
unitConfig = {
|
||||||
|
ConditionPathExists = "!%h/.config/home-manager/.hm_bootstrap_done";
|
||||||
|
After = [ "graphical-session.target" ];
|
||||||
|
Wants = [ "graphical-session.target" ];
|
||||||
|
PartOf = [ "graphical-session.target" ];
|
||||||
|
};
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
TimeoutStartSec = "30min";
|
||||||
|
Environment = [ "PATH=/run/current-system/sw/bin:/etc/profiles/per-user/%u/bin" ];
|
||||||
|
StandardOutput = "journal";
|
||||||
|
StandardError = "journal";
|
||||||
|
ExecStart = pkgs.writeShellScript "hm-bootstrap.sh" (builtins.readFile ../../scripts/hm-bootstrap.sh);
|
||||||
|
};
|
||||||
|
wantedBy = [ "graphical-session.target" ];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
75
scripts/hm-bootstrap.sh
Normal file
75
scripts/hm-bootstrap.sh
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Ensure basic PATH for user units
|
||||||
|
export PATH="/run/current-system/sw/bin:${PATH:-}"
|
||||||
|
|
||||||
|
# Try to hook into the session bus if available
|
||||||
|
if [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ] && [ -S "/run/user/$(id -u)/bus" ]; then
|
||||||
|
export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u)/bus"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Only continue in an active, unlocked user session
|
||||||
|
if command -v loginctl >/dev/null 2>&1 && [ -n "${XDG_SESSION_ID:-}" ]; then
|
||||||
|
session_class=$(loginctl show-session "${XDG_SESSION_ID}" -p Class --value 2>/dev/null || echo "")
|
||||||
|
session_state=$(loginctl show-session "${XDG_SESSION_ID}" -p State --value 2>/dev/null || echo "")
|
||||||
|
session_locked=$(loginctl show-session "${XDG_SESSION_ID}" -p LockedHint --value 2>/dev/null || echo "yes")
|
||||||
|
if [ "${session_class}" != "user" ] || [ "${session_state}" != "active" ] || [ "${session_locked}" != "no" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
wait_for_notifications() {
|
||||||
|
# Wait briefly for GNOME Shell notifications to come up and the session to be unlocked.
|
||||||
|
if [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ] || ! command -v gdbus >/dev/null 2>&1; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Do not notify in greeter sessions.
|
||||||
|
if [ "${XDG_SESSION_CLASS:-}" != "user" ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If loginctl is available, wait until this session is unlocked and class=user (not greeter).
|
||||||
|
if command -v loginctl >/dev/null 2>&1 && [ -n "${XDG_SESSION_ID:-}" ]; then
|
||||||
|
for _ in 1 2 3 4 5 6 7; do
|
||||||
|
session_class=$(loginctl show-session "${XDG_SESSION_ID}" -p Class --value 2>/dev/null || echo "")
|
||||||
|
locked=$(loginctl show-session "${XDG_SESSION_ID}" -p LockedHint --value 2>/dev/null || echo "yes")
|
||||||
|
if [ "${session_class}" = "user" ] && [ "${locked}" = "no" ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
for _ in 1 2 3 4 5 6 7; do
|
||||||
|
if gdbus introspect --session \
|
||||||
|
--dest org.freedesktop.Notifications \
|
||||||
|
--object-path /org/freedesktop/Notifications >/dev/null 2>&1; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
notify() {
|
||||||
|
local title="$1"
|
||||||
|
shift || true
|
||||||
|
if command -v notify-send >/dev/null 2>&1 && wait_for_notifications; then
|
||||||
|
notify-send --app-name="Bootstrap" --urgency=critical --expire-time=0 "$title" "$@" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
notify "System setup running" "Please wait until setup completes."
|
||||||
|
trap 'notify "System setup finished" "You may continue using the system."' EXIT
|
||||||
|
|
||||||
|
mkdir -p "$HOME/.config/home-manager"
|
||||||
|
for f in flake.nix home.nix; do
|
||||||
|
if [ -f "/etc/skel/.config/home-manager/$f" ] && [ ! -e "$HOME/.config/home-manager/$f" ]; then
|
||||||
|
cp "/etc/skel/.config/home-manager/$f" "$HOME/.config/home-manager/$f"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
home-manager switch --flake "$HOME/.config/home-manager#admin"
|
||||||
|
touch "$HOME/.config/home-manager/.hm_bootstrap_done"
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# Non-interactive Btrfs installer using the flake in this repo.
|
# Non-interactive Btrfs installer using the flake in this repo.
|
||||||
# Defaults: DISK=/dev/vda HOSTNAME=nanuqsaurus
|
# Defaults: DISK=/dev/vda TARGET_HOST=nanuqsaurus
|
||||||
|
|
||||||
DISK=${DISK:-/dev/vda}
|
DISK=${DISK:-/dev/vda}
|
||||||
HOSTNAME=${HOSTNAME:-nanuqsaurus}
|
TARGET_HOST=${TARGET_HOST:-nanuqsaurus}
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
SCRIPT_DIR=$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||||
REPO_ROOT=$(cd -- "${SCRIPT_DIR}/.." && pwd)
|
REPO_ROOT=$(cd -- "${SCRIPT_DIR}/.." && pwd)
|
||||||
|
|
@ -44,9 +44,9 @@ fi
|
||||||
|
|
||||||
echo "[6/7] Generating hardware config"
|
echo "[6/7] Generating hardware config"
|
||||||
mkdir -p /mnt/etc/nixos/hosts
|
mkdir -p /mnt/etc/nixos/hosts
|
||||||
nixos-generate-config --root /mnt --show-hardware-config > "/mnt/etc/nixos/hosts/local-${HOSTNAME}-hardware.nix"
|
nixos-generate-config --root /mnt --show-hardware-config > "/mnt/etc/nixos/hosts/local-${TARGET_HOST}-hardware.nix"
|
||||||
|
|
||||||
host_file="/mnt/etc/nixos/hosts/local-${HOSTNAME}.nix"
|
host_file="/mnt/etc/nixos/hosts/local-${TARGET_HOST}.nix"
|
||||||
if [ ! -e "${host_file}" ]; then
|
if [ ! -e "${host_file}" ]; then
|
||||||
cat > "${host_file}" <<EOF
|
cat > "${host_file}" <<EOF
|
||||||
{ inputs, ... }:
|
{ inputs, ... }:
|
||||||
|
|
@ -55,18 +55,20 @@ if [ ! -e "${host_file}" ]; then
|
||||||
imports = [
|
imports = [
|
||||||
inputs.lix-module.nixosModules.lixFromNixpkgs
|
inputs.lix-module.nixosModules.lixFromNixpkgs
|
||||||
../modules/system/base.nix
|
../modules/system/base.nix
|
||||||
|
../modules/system/packages.nix
|
||||||
|
../modules/system/home-manager-skel.nix
|
||||||
../modules/desktop/gnome-minimal.nix
|
../modules/desktop/gnome-minimal.nix
|
||||||
../modules/users/admin.nix
|
../modules/users/admin.nix
|
||||||
./local-${HOSTNAME}-hardware.nix
|
./local-${TARGET_HOST}-hardware.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
networking.hostName = "${HOSTNAME}";
|
networking.hostName = "${TARGET_HOST}";
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "[7/7] Installing ${HOSTNAME} via flake"
|
echo "[7/7] Installing ${TARGET_HOST} via flake (local-${TARGET_HOST})"
|
||||||
nixos-install --root /mnt --flake "/mnt/etc/nixos#${HOSTNAME}" --no-root-passwd |& tee /tmp/nixos-install.log
|
nixos-install --root /mnt --flake "/mnt/etc/nixos#local-${TARGET_HOST}" --no-root-passwd |& tee /tmp/nixos-install.log
|
||||||
echo "Install log saved to /tmp/nixos-install.log"
|
echo "Install log saved to /tmp/nixos-install.log"
|
||||||
|
|
||||||
echo "Install complete. You can reboot now."
|
echo "Install complete. You can reboot now."
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue