nicer scripts

This commit is contained in:
randogoth 2026-02-04 15:21:29 +02:00
parent 978a439cfe
commit 7a42926fba
2 changed files with 128 additions and 75 deletions

View file

@ -1,76 +1,92 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
UID="$(id -u)"
USER_BUS="/run/user/$UID/bus"
HM_DIR="$HOME/.config/home-manager"
SKEL_DIR="/etc/skel/.config/home-manager"
# Ensure basic PATH for user units # Ensure basic PATH for user units
export PATH="/run/current-system/sw/bin:${PATH:-}" export PATH="/run/current-system/sw/bin:${PATH:-}"
# Try to hook into the session bus if available # Attach to session bus if possible
if [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ] && [ -S "/run/user/$(id -u)/bus" ]; then if [[ -z "${DBUS_SESSION_BUS_ADDRESS:-}" && -S "$USER_BUS" ]]; then
export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u)/bus" export DBUS_SESSION_BUS_ADDRESS="unix:path=$USER_BUS"
fi fi
# Only continue in an active, unlocked user session have() { command -v "$1" >/dev/null 2>&1; }
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 sanity check ---------------------------------------------------
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 have loginctl && [[ -n "${XDG_SESSION_ID:-}" ]]; then
if [ "${session_class}" != "user" ] || [ "${session_state}" != "active" ] || [ "${session_locked}" != "no" ]; then # One loginctl call instead of three
exit 0 eval "$(
fi loginctl show-session "$XDG_SESSION_ID" \
-p Class -p State -p LockedHint \
--value 2>/dev/null |
awk '
NR==1{print "SESSION_CLASS="$0}
NR==2{print "SESSION_STATE="$0}
NR==3{print "SESSION_LOCKED="$0}
'
)"
[[ "${SESSION_CLASS:-}" == "user" ]] || exit 0
[[ "${SESSION_STATE:-}" == "active" ]] || exit 0
[[ "${SESSION_LOCKED:-yes}" == "no" ]] || exit 0
fi fi
wait_for_notifications() { # ---- 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. notifications_ready() {
if [ "${XDG_SESSION_CLASS:-}" != "user" ]; then [[ "${XDG_SESSION_CLASS:-user}" == "user" ]] || return 1
return 1 [[ -n "${DBUS_SESSION_BUS_ADDRESS:-}" ]] || return 1
fi have gdbus || return 1
# If loginctl is available, wait until this session is unlocked and class=user (not greeter). # Wait for unlock if loginctl is present
if command -v loginctl >/dev/null 2>&1 && [ -n "${XDG_SESSION_ID:-}" ]; then if have loginctl && [[ -n "${XDG_SESSION_ID:-}" ]]; then
for _ in 1 2 3 4 5 6 7; do for _ in {1..7}; do
session_class=$(loginctl show-session "${XDG_SESSION_ID}" -p Class --value 2>/dev/null || echo "") [[ "$(loginctl show-session "$XDG_SESSION_ID" \
locked=$(loginctl show-session "${XDG_SESSION_ID}" -p LockedHint --value 2>/dev/null || echo "yes") -p LockedHint --value 2>/dev/null)" == "no" ]] && break
if [ "${session_class}" = "user" ] && [ "${locked}" = "no" ]; then
break
fi
sleep 2 sleep 2
done done
fi fi
for _ in 1 2 3 4 5 6 7; do # Wait for notification service
if gdbus introspect --session \ for _ in {1..7}; do
gdbus introspect --session \
--dest org.freedesktop.Notifications \ --dest org.freedesktop.Notifications \
--object-path /org/freedesktop/Notifications >/dev/null 2>&1; then --object-path /org/freedesktop/Notifications \
return 0 >/dev/null 2>&1 && return 0
fi
sleep 2 sleep 2
done done
return 1 return 1
} }
notify() { notify() {
local title="$1" have notify-send || return 0
shift || true notifications_ready || return 0
if command -v notify-send >/dev/null 2>&1 && wait_for_notifications; then notify-send \
notify-send --app-name="Bootstrap" --urgency=critical --expire-time=0 "$title" "$@" >/dev/null 2>&1 || true --app-name="Bootstrap" \
fi --urgency=critical \
--expire-time=0 \
"$@" >/dev/null 2>&1 || true
} }
notify "Reticulating Splines" "Bootstrapping. Please stay tuned." notify "Reticulating Splines" "Bootstrapping. Please stay tuned."
trap 'notify "Bootstrap finished" "Your system is fully hydrated. It is recommended to logout and back in."' EXIT trap 'notify "Bootstrap finished" "Your system is fully hydrated. It is recommended to logout and back in."' EXIT
mkdir -p "$HOME/.config/home-manager" # ---- Home Manager bootstrap -------------------------------------------------
mkdir -p "$HM_DIR"
for f in flake.nix home.nix; do for f in flake.nix home.nix; do
if [ -f "/etc/skel/.config/home-manager/$f" ] && [ ! -e "$HOME/.config/home-manager/$f" ]; then src="$SKEL_DIR/$f"
cp "/etc/skel/.config/home-manager/$f" "$HOME/.config/home-manager/$f" dst="$HM_DIR/$f"
chmod u+rw "$HOME/.config/home-manager/$f" [[ -f "$src" && ! -e "$dst" ]] || continue
fi install -m 600 "$src" "$dst"
done done
home-manager switch --flake "$HOME/.config/home-manager#admin" home-manager switch --flake "$HM_DIR#admin"
touch "$HOME/.config/home-manager/.hm_bootstrap_done" touch "$HM_DIR/.hm_bootstrap_done"

View file

@ -4,51 +4,84 @@ 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 TARGET_HOST=nanuqsaurus # Defaults: DISK=/dev/vda TARGET_HOST=nanuqsaurus
DISK=${DISK:-/dev/vda} DISK="${DISK:-/dev/vda}"
TARGET_HOST=${TARGET_HOST:-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)"
MNT=/mnt
EFI_SIZE=550M
have() { command -v "$1" >/dev/null 2>&1; }
die() {
echo "ERROR: $*" >&2
exit 1
}
confirm_disk() {
echo "About to DESTROY ALL DATA on ${DISK}"
lsblk "$DISK" || die "Disk not found: $DISK"
echo "Continuing in 5 seconds… (Ctrl+C to abort)"
sleep 5
}
clear clear
confirm_disk
echo "[1/7] Partitioning ${DISK}" echo "[1/7] Partitioning ${DISK}"
printf "label: gpt\n,550M,U\n,,L\n" | sfdisk "${DISK}" sfdisk "$DISK" <<EOF
label: gpt
,${EFI_SIZE},U
,,L
EOF
echo "[2/7] Formatting" echo "[2/7] Formatting filesystems"
mkfs.fat -F 32 "${DISK}1" mkfs.fat -F32 "${DISK}1"
mkfs.btrfs -f "${DISK}2" mkfs.btrfs -f "${DISK}2"
echo "[3/7] Creating Btrfs subvolumes" echo "[3/7] Creating Btrfs subvolumes"
mkdir -p /mnt mkdir -p "$MNT"
mount "${DISK}2" /mnt mount "${DISK}2" "$MNT"
btrfs subvolume create /mnt/root
btrfs subvolume create /mnt/home for subvol in root home nix; do
btrfs subvolume create /mnt/nix btrfs subvolume create "$MNT/$subvol"
umount /mnt done
umount "$MNT"
echo "[4/7] Mounting subvolumes" echo "[4/7] Mounting subvolumes"
mount -o compress=zstd,subvol=root "${DISK}2" /mnt mount -o compress=zstd,subvol=root "${DISK}2" "$MNT"
mkdir -p /mnt/{home,nix,boot} mkdir -p "$MNT"/{home,nix,boot}
mount -o compress=zstd,subvol=home "${DISK}2" /mnt/home
mount -o compress=zstd,subvol=nix "${DISK}2" /mnt/nix mount -o compress=zstd,subvol=home "${DISK}2" "$MNT/home"
mount "${DISK}1" /mnt/boot mount -o compress=zstd,subvol=nix "${DISK}2" "$MNT/nix"
mount "${DISK}1" "$MNT/boot"
echo "[5/7] Copying flake to /etc/nixos" echo "[5/7] Copying flake to /etc/nixos"
mkdir -p /mnt/etc/nixos mkdir -p "$MNT/etc/nixos"
if command -v rsync >/dev/null 2>&1; then
rsync -a --exclude '.git' --exclude 'result' --exclude 'node_modules' "${REPO_ROOT}/" /mnt/etc/nixos/ EXCLUDES=(--exclude=.git --exclude=result --exclude=node_modules)
if have rsync; then
rsync -a "${EXCLUDES[@]}" "$REPO_ROOT/" "$MNT/etc/nixos/"
else else
(cd "${REPO_ROOT}" && tar -cf - --exclude=.git --exclude=result --exclude=node_modules .) | (cd /mnt/etc/nixos && tar -xf -) (cd "$REPO_ROOT" && tar -cf - "${EXCLUDES[@]/#/--exclude=}" .) \
| (cd "$MNT/etc/nixos" && tar -xf -)
fi fi
echo "[6/7] Generating hardware config" echo "[6/7] Generating hardware config"
mkdir -p /mnt/etc/nixos/hosts HOSTS_DIR="$MNT/etc/nixos/hosts"
nixos-generate-config --root /mnt --show-hardware-config > "/mnt/etc/nixos/hosts/local-${TARGET_HOST}-hardware.nix" mkdir -p "$HOSTS_DIR"
host_file="/mnt/etc/nixos/hosts/local-${TARGET_HOST}.nix" HW_FILE="$HOSTS_DIR/local-${TARGET_HOST}-hardware.nix"
if [ ! -e "${host_file}" ]; then HOST_FILE="$HOSTS_DIR/local-${TARGET_HOST}.nix"
cat > "${host_file}" <<EOF
nixos-generate-config --root "$MNT" --show-hardware-config > "$HW_FILE"
if [[ ! -e "$HOST_FILE" ]]; then
cat > "$HOST_FILE" <<EOF
{ inputs, ... }: { inputs, ... }:
{ {
@ -67,8 +100,12 @@ if [ ! -e "${host_file}" ]; then
EOF EOF
fi fi
echo "[7/7] Installing ${TARGET_HOST} via flake (local-${TARGET_HOST})" echo "[7/7] Installing ${TARGET_HOST} via flake"
nixos-install --root /mnt --flake "/mnt/etc/nixos#local-${TARGET_HOST}" --no-root-passwd |& tee /tmp/nixos-install.log LOG=/tmp/nixos-install.log
echo "Install log saved to /tmp/nixos-install.log" nixos-install \
--root "$MNT" \
--flake "$MNT/etc/nixos#local-${TARGET_HOST}" \
--no-root-passwd |& tee "$LOG"
echo "Install log saved to $LOG"
echo "Install complete. You can reboot now." echo "Install complete. You can reboot now."