diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml index a1a49a7..2fd78da 100644 --- a/.github/workflows/pr-test.yml +++ b/.github/workflows/pr-test.yml @@ -14,7 +14,7 @@ jobs: - name: ShellCheck run: | - shellcheck -x install-scripts/*.sh install-scripts/lib/*.sh config/sets/basic/tmux/scripts/*.sh scripts/* + shellcheck -x install-scripts/*.sh install-scripts/lib/*.sh config/sets/*/apply.sh config/sets/basic/tmux/scripts/*.sh scripts/* - name: Fish syntax check run: | diff --git a/README.md b/README.md index 9a16f91..59bc8b2 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,17 @@ config/ gitignore # Linked to ~/.config/git/ignore identity # Copied to ~/.config/git/identity, per-machine apply.sh - kde/ # KDE Plasma keyboard repeat settings + gentoo/ # The gentoo-kernel-upgrade helper + description + manifest + os # "Linux" — hidden from `make picky` elsewhere + apply.sh + gnome/ # GNOME settings (`gsettings`) + description + manifest + os # "Linux" — hidden from `make picky` elsewhere + apply.sh + kde/ # KDE Plasma settings (`kwriteconfig5`/`6`) description manifest os # "Linux" — hidden from `make picky` elsewhere @@ -102,8 +112,22 @@ Config files are grouped into **sets** under `config/sets//`: `~/.config/git/local` file rather than `git config --global`, since with no `~/.gitconfig` yet that resolves to the tracked `~/.config/git/config` symlink -- **`kde`** — sets the KDE Plasma keyboard repeat rate to 50/s with a 250ms - delay (via `kwriteconfig5`/`6` on `kcminputrc`) +- **`gentoo`** — installs `scripts/gentoo-kernel-upgrade` into `/usr/bin`: a + guided, confirm-every-step walkthrough of a `gentoo-kernel-bin` upgrade + (emerge, `eselect kernel`, back up the EFI boot files, regenerate the + initramfs, copy the new image across), plus a cleanup pass over superseded + kernels in `/boot`. It works out on its own whether this system's kernel + images are named `vmlinuz-` or `kernel-`; set + `KERNEL_PREFIX` to override that +- **`gnome`** — the GNOME settings that differ from stock, applied via + `gsettings`: keyboard repeat rate 50/s with a 250ms delay, Caps Lock as + Escape, screen locking and idle display dim/off disabled, device + automounting disabled, an editable path bar in GTK file dialogs, and a + dark color scheme +- **`kde`** — the KDE Plasma equivalents, applied via `kwriteconfig5`/`6`: + the same keyboard repeat rate and Caps Lock as Escape, screen locking and + idle display dim/off disabled, the device automounter disabled, Dolphin's + menu bar hidden with an editable path bar, and the Breeze Dark theme - **`macos`** — the macOS system settings that differ from stock, applied via `defaults write`: fastest keyboard repeat rate with the shortest delay, all automatic text substitution off, text replacements, the input-source and @@ -125,11 +149,17 @@ Config files are grouped into **sets** under `config/sets//`: configures **Kitty** as the default terminal Each set is independent and additive — enabling `kde` or `macos` doesn't -disturb `basic`. `kde`, `macos` and `xfce` each declare an `os` file -restricting them to their platform, so `make picky` only offers `kde` and -`xfce` on Linux and `macos` on macOS in the first place; if one somehow ends -up enabled on the wrong OS anyway (e.g. a shared `sets.conf`), it's skipped -with a warning at deploy time instead of failing. +disturb `basic`. Every set except `basic` and `git` declares an `os` file +restricting it to its platform, so `make picky` only offers `gentoo`, +`gnome`, `kde` and `xfce` on Linux and `macos` on macOS in the first place; +if one somehow ends up enabled on the wrong OS anyway (e.g. a shared +`sets.conf`), it's skipped with a warning at deploy time instead of failing. + +An `os` file is only as specific as `uname -s`, so the Linux sets are offered +on *every* Linux. Each one checks for what it actually needs at deploy time — +`gsettings`, `kwriteconfig`, `xfconf-query`, `/etc/gentoo-release` — and +warns and exits 0 if it isn't there, so picking `gentoo` on Debian is +harmless rather than fatal. A bare `make` (or `make picky`, the same target by name) gives you an interactive checklist (space to toggle, enter to confirm) of every set found @@ -290,7 +320,6 @@ Completes the setup: - Adds Fish to `/etc/shells` - Changes the default shell to Fish - Creates `~/bin` for personal scripts -- On Gentoo, installs the appropriate kernel-upgrade helper (OpenRC or systemd) - On Arch, enables the cron daemon and installs an hourly `sudo pacman -Syy` cron job for the current user; if that user isn't root, grants them passwordless sudo (`/etc/sudoers.d/99--nopasswd`) so the unattended diff --git a/config/sets/gentoo/apply.sh b/config/sets/gentoo/apply.sh new file mode 100755 index 0000000..6a90ba2 --- /dev/null +++ b/config/sets/gentoo/apply.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -euo pipefail + +# Installs the Gentoo kernel upgrade helper (scripts/gentoo-kernel-upgrade) +# into /usr/bin, mirroring config/sets/xfce/apply.sh's install_kitty. +# +# This used to live in install-scripts/07-last-touches.sh, where it ran on +# every Gentoo install and had to stop and ask which init system was in use +# — which blocked unattended installs. The helper works its own kernel +# naming out at runtime now, so this is a plain copy, and it's opt-in via +# `make picky` rather than automatic. + +if [ ! -f /etc/gentoo-release ]; then + echo "Warning: /etc/gentoo-release not found (not a Gentoo system?); skipping Gentoo settings." >&2 + exit 0 +fi + +REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" + +# install(1) rather than cp so the mode is set explicitly, and so an +# already-running copy of the script isn't rewritten underneath itself. +sudo install -m 755 "$REPO/scripts/gentoo-kernel-upgrade" /usr/bin/gentoo-kernel-upgrade + +echo "Installed /usr/bin/gentoo-kernel-upgrade" diff --git a/config/sets/gentoo/description b/config/sets/gentoo/description new file mode 100644 index 0000000..21c0a04 --- /dev/null +++ b/config/sets/gentoo/description @@ -0,0 +1,4 @@ +Gentoo: the gentoo-kernel-upgrade helper installed to /usr/bin — a guided, +confirm-every-step walkthrough of a gentoo-kernel-bin upgrade (emerge, eselect +kernel, back up the EFI boot files, regenerate the initramfs, copy the new +image across) plus cleanup of superseded kernels in /boot diff --git a/config/sets/gentoo/manifest b/config/sets/gentoo/manifest new file mode 100644 index 0000000..5a7828e --- /dev/null +++ b/config/sets/gentoo/manifest @@ -0,0 +1,3 @@ +# See config/sets/basic/manifest for the full manifest format reference. + +run apply.sh diff --git a/config/sets/gentoo/os b/config/sets/gentoo/os new file mode 100644 index 0000000..9b07567 --- /dev/null +++ b/config/sets/gentoo/os @@ -0,0 +1 @@ +Linux diff --git a/install-scripts/07-last-touches.sh b/install-scripts/07-last-touches.sh index 7d5641c..365faa4 100755 --- a/install-scripts/07-last-touches.sh +++ b/install-scripts/07-last-touches.sh @@ -19,20 +19,8 @@ fi # create local bin directory mkdir -p ~/bin -# Gentoo specific kernel script -if [ -f /etc/gentoo-release ]; then - init_system=openrc - echo "Gentoo detected, need clarification on which init system is used." - echo -e "Which init system?\n\n1> openrc\n2> systemd" - read -p "[1]/2: " -n 1; - echo - if [ "$REPLY" == "2" ]; then - init_system=systemd - fi - - sudo cp scripts/gentoo-kernel-upgrade-$init_system /usr/bin/gentoo-kernel-upgrade - -fi +# (The Gentoo kernel-upgrade helper used to be installed here, unconditionally +# on every Gentoo box. It's an opt-in config set now — config/sets/gentoo/.) # Arch specific: keep the local package database fresh via an hourly cron job if [ -f /etc/arch-release ]; then diff --git a/scripts/gentoo-kernel-upgrade-openrc b/scripts/gentoo-kernel-upgrade similarity index 86% rename from scripts/gentoo-kernel-upgrade-openrc rename to scripts/gentoo-kernel-upgrade index 1eeeb95..9e8eb5a 100755 --- a/scripts/gentoo-kernel-upgrade-openrc +++ b/scripts/gentoo-kernel-upgrade @@ -20,6 +20,14 @@ NC='\033[0m' # No Color EFI_DIR="/boot/efi" BOOT_DIR="/boot" +# Gentoo's installkernel names the kernel image in /boot differently +# depending on the layout it was configured for: the traditional one uses +# vmlinuz-, the systemd/UAPI one uses kernel-. That naming +# was the *only* difference between the two copies of this script this file +# replaces, so it's detected at runtime instead. Set KERNEL_PREFIX to +# override. +KERNEL_PREFIX="${KERNEL_PREFIX:-}" + # Print functions info() { echo -e "${BLUE}==>${NC} ${BOLD}$1${NC}"; } warn() { echo -e "${YELLOW}WARNING:${NC} $1"; } @@ -48,6 +56,44 @@ get_current_version() { uname -r } +# Work out whether this system's kernel images are named vmlinuz- +# or kernel-, and set KERNEL_PREFIX accordingly. +detect_kernel_prefix() { + # An explicit KERNEL_PREFIX from the environment always wins. + if [[ -n "$KERNEL_PREFIX" ]]; then + return 0 + fi + + local running prefix + running=$(get_current_version) + + # Strongest signal: whichever name the *running* kernel is installed + # under, since that's the one this system's installkernel actually used. + for prefix in vmlinuz kernel; do + if [[ -f "${BOOT_DIR}/${prefix}-${running}" ]]; then + KERNEL_PREFIX="$prefix" + return 0 + fi + done + + # Next best: whichever name anything else in /boot uses (the running + # kernel may already have been cleaned up, or /boot only just mounted). + for prefix in vmlinuz kernel; do + if ls "${BOOT_DIR}/${prefix}"-* >/dev/null 2>&1; then + KERNEL_PREFIX="$prefix" + return 0 + fi + done + + # Nothing in /boot to go on. Fall back to the init system, which is what + # the layout was chosen for in the first place. + if [[ -d /run/systemd/system ]]; then + KERNEL_PREFIX="kernel" + else + KERNEL_PREFIX="vmlinuz" + fi +} + # Get the latest installed kernel version from /usr/src get_latest_installed_version() { local latest @@ -185,7 +231,7 @@ generate_initramfs() { # Copy new kernel to EFI partition copy_kernel() { local version="$1" - local kernel_source="${BOOT_DIR}/vmlinuz-${version}" + local kernel_source="${BOOT_DIR}/${KERNEL_PREFIX}-${version}" info "Copying new kernel to EFI partition..." echo @@ -219,15 +265,13 @@ cleanup_old_versions() { local initramfs_to_delete=() local kernels_to_delete=() - - while IFS= read -r f; do initramfs_to_delete+=("$f") done < <(ls ${BOOT_DIR}/initramfs-*.img 2>/dev/null | grep -v "$current_version" || true) while IFS= read -r f; do kernels_to_delete+=("$f") - done < <(ls ${BOOT_DIR}/vmlinuz-* 2>/dev/null | grep -v "$current_version" || true) + done < <(ls ${BOOT_DIR}/"${KERNEL_PREFIX}"-* 2>/dev/null | grep -v "$current_version" || true) # Check if there's anything to delete if [[ ${#initramfs_to_delete[@]} -eq 0 ]] && [[ ${#kernels_to_delete[@]} -eq 0 ]]; then @@ -298,6 +342,9 @@ main() { local current_version current_version=$(get_current_version) info "Currently running kernel: ${current_version}" + + detect_kernel_prefix + info "Kernel images in ${BOOT_DIR} are named: ${KERNEL_PREFIX}-" echo # Check for updates diff --git a/scripts/gentoo-kernel-upgrade-systemd b/scripts/gentoo-kernel-upgrade-systemd deleted file mode 100755 index fcc1c63..0000000 --- a/scripts/gentoo-kernel-upgrade-systemd +++ /dev/null @@ -1,397 +0,0 @@ -#!/bin/bash -# -# Gentoo Kernel Upgrade Script -# This script helps upgrade the gentoo-kernel-bin package safely. -# -# IMPORTANT: This script modifies boot files. A failed upgrade could -# prevent your system from booting. Ensure you have a backup plan. -# - -set -euo pipefail - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -BOLD='\033[1m' -NC='\033[0m' # No Color - -EFI_DIR="/boot/efi" -BOOT_DIR="/boot" - -# Print functions -info() { echo -e "${BLUE}==>${NC} ${BOLD}$1${NC}"; } -warn() { echo -e "${YELLOW}WARNING:${NC} $1"; } -error() { echo -e "${RED}ERROR:${NC} $1" >&2; } -success() { echo -e "${GREEN}==>${NC} $1"; } - -# Check if running as root -check_root() { - if [[ $EUID -ne 0 ]]; then - error "This script must be run as root" - exit 1 - fi -} - -# Prompt user for confirmation -confirm() { - local prompt="$1" - local response - echo -e "${YELLOW}${prompt}${NC}" - read -p "Type 'yes' to confirm: " response - [[ "$response" == "yes" ]] -} - -# Get the currently running kernel version -get_current_version() { - uname -r -} - -# Get the latest installed kernel version from /usr/src -get_latest_installed_version() { - local latest - latest=$(ls -1d /usr/src/linux-*-gentoo-dist 2>/dev/null | sort -V | tail -1 | sed 's|.*/linux-||') - echo "$latest" -} - -# Check for available updates using emerge -check_for_updates() { - info "Checking for gentoo-kernel-bin updates..." - echo - - # Use emerge to check for updates (pretend mode) - if emerge -pvu gentoo-kernel-bin 2>/dev/null | grep -q "gentoo-kernel-bin"; then - local update_info - update_info=$(emerge -pvu gentoo-kernel-bin 2>/dev/null | grep -E "gentoo-kernel-bin|ebuild") - echo "$update_info" - return 0 - else - return 1 - fi -} - -# Install the kernel update -install_kernel_update() { - info "Installing gentoo-kernel-bin update..." - echo - - echo -e "${BOLD}The following command will be executed:${NC}" - echo -e " ${BLUE}emerge gentoo-kernel-bin${NC}" - echo - - if ! confirm "Proceed with kernel package installation?"; then - warn "Installation cancelled by user" - return 1 - fi - - echo - emerge gentoo-kernel-bin - - success "Kernel package installed successfully" -} - -# Select the new kernel with eselect -select_kernel() { - local new_version="$1" - - info "Available kernel versions:" - eselect kernel list - echo - - # Find the number corresponding to the new version - local kernel_num - kernel_num=$(eselect kernel list | grep "$new_version" | sed 's/.*\[\([0-9]*\)\].*/\1/') - - if [[ -z "$kernel_num" ]]; then - error "Could not find kernel version $new_version in eselect list" - echo "Please select the kernel manually:" - eselect kernel list - read -p "Enter the number to select: " kernel_num - fi - - echo -e "${BOLD}The following command will be executed:${NC}" - echo -e " ${BLUE}eselect kernel set $kernel_num${NC}" - echo - - if ! confirm "Set kernel $new_version as active?"; then - warn "Kernel selection cancelled by user" - return 1 - fi - - eselect kernel set "$kernel_num" - - # Verify - info "Current kernel symlink:" - eselect kernel list | grep '\*' - echo -} - -# Backup current boot files -backup_boot_files() { - info "Backing up current boot files..." - - echo -e "${BOLD}The following operations will be performed in ${EFI_DIR}:${NC}" - echo -e " ${BLUE}mv vmlinuz.efi -> vmlinuz.efi.bak${NC}" - echo -e " ${BLUE}mv initramfs.img -> initramfs.img.bak${NC}" - echo - - if [[ -f "${EFI_DIR}/vmlinuz.efi.bak" ]] || [[ -f "${EFI_DIR}/initramfs.img.bak" ]]; then - warn "Existing backup files will be overwritten!" - fi - - if ! confirm "Backup current boot files?"; then - warn "Backup cancelled by user" - return 1 - fi - - cd "${EFI_DIR}" - - if [[ -f "vmlinuz.efi" ]]; then - mv vmlinuz.efi vmlinuz.efi.bak - success "Backed up vmlinuz.efi" - fi - - if [[ -f "initramfs.img" ]]; then - mv initramfs.img initramfs.img.bak - success "Backed up initramfs.img" - fi - - echo -} - -# Generate new initramfs -generate_initramfs() { - local version="$1" - - info "Generating new initramfs for kernel ${version}..." - echo - - echo -e "${BOLD}The following command will be executed:${NC}" - echo -e " ${BLUE}${EFI_DIR}/generate_initramfs.sh ${version} ${EFI_DIR}/initramfs.img${NC}" - echo - - if ! confirm "Generate initramfs?"; then - warn "Initramfs generation cancelled by user" - return 1 - fi - - bash "${EFI_DIR}/generate_initramfs.sh" "${version}" "${EFI_DIR}/initramfs.img" - - success "Initramfs generated successfully" - echo -} - -# Copy new kernel to EFI partition -copy_kernel() { - local version="$1" - local kernel_source="${BOOT_DIR}/kernel-${version}" - - info "Copying new kernel to EFI partition..." - echo - - if [[ ! -f "$kernel_source" ]]; then - error "Kernel file not found: $kernel_source" - return 1 - fi - - echo -e "${BOLD}The following command will be executed:${NC}" - echo -e " ${BLUE}cp ${kernel_source} ${EFI_DIR}/vmlinuz.efi${NC}" - echo - - if ! confirm "Copy new kernel to EFI partition?"; then - warn "Kernel copy cancelled by user" - return 1 - fi - - cp "$kernel_source" "${EFI_DIR}/vmlinuz.efi" - - success "Kernel copied successfully" - echo -} - -# Cleanup old kernel versions from /boot -cleanup_old_versions() { - info "Checking for old kernel versions to clean up..." - echo - - # Find old initramfs and kernel files (excluding current version) - local initramfs_to_delete=() - local kernels_to_delete=() - - while IFS= read -r f; do - initramfs_to_delete+=("$f") - done < <(ls ${BOOT_DIR}/initramfs-*.img 2>/dev/null | grep -v "$current_version" || true) - - while IFS= read -r f; do - kernels_to_delete+=("$f") - done < <(ls ${BOOT_DIR}/kernel-* 2>/dev/null | grep -v "$current_version" || true) - - # Check if there's anything to delete - if [[ ${#initramfs_to_delete[@]} -eq 0 ]] && [[ ${#kernels_to_delete[@]} -eq 0 ]]; then - success "No old kernel versions to clean up" - echo - return 0 - fi - - echo -e "${BOLD}The following files will be DELETED:${NC}" - echo - for f in "${initramfs_to_delete[@]}" "${kernels_to_delete[@]}"; do - echo -e " ${RED}$f${NC}" - done - echo - - warn "This action cannot be undone!" - echo - - if ! confirm "Delete these old kernel files?"; then - warn "Cleanup cancelled by user" - return 1 - fi - - echo - for f in "${initramfs_to_delete[@]}" "${kernels_to_delete[@]}"; do - rm -v "$f" - done - - echo - success "Old kernel versions cleaned up" - echo -} - -# Print summary of what will be done -print_summary() { - local current="$1" - local new="$2" - - echo - echo -e "${BOLD}╔════════════════════════════════════════════════════════════════╗${NC}" - echo -e "${BOLD}║ GENTOO KERNEL UPGRADE SUMMARY ║${NC}" - echo -e "${BOLD}╚════════════════════════════════════════════════════════════════╝${NC}" - echo - echo -e " Current running kernel: ${YELLOW}${current}${NC}" - echo -e " New kernel version: ${GREEN}${new}${NC}" - echo - echo -e "${BOLD}The following steps will be performed:${NC}" - echo " 1. Backup current vmlinuz.efi and initramfs.img" - echo " 2. Generate new initramfs using dracut" - echo " 3. Copy new kernel to EFI partition" - echo - echo -e "${RED}${BOLD}WARNING: This process modifies boot files!${NC}" - echo -e "${RED}If something goes wrong, your system may not boot.${NC}" - echo -e "${RED}Make sure you have a way to recover (live USB, backup, etc.)${NC}" - echo -} - -# Main function -main() { - echo - echo -e "${BOLD}╔════════════════════════════════════════════════════════════════╗${NC}" - echo -e "${BOLD}║ GENTOO KERNEL UPGRADE HELPER ║${NC}" - echo -e "${BOLD}╚════════════════════════════════════════════════════════════════╝${NC}" - echo - - check_root - - local current_version - current_version=$(get_current_version) - info "Currently running kernel: ${current_version}" - echo - - # Check for updates - if ! check_for_updates; then - success "No updates available for gentoo-kernel-bin" - echo - - local latest_installed - latest_installed=$(get_latest_installed_version) - - if [[ "$latest_installed" != "$current_version" ]] && [[ -n "$latest_installed" ]]; then - # Installed kernel differs from running - offer to set up boot files - warn "Installed kernel ($latest_installed) differs from running kernel ($current_version)" - echo - if confirm "Would you like to set up boot files for $latest_installed?"; then - print_summary "$current_version" "$latest_installed" - - if ! confirm "Proceed with the upgrade process?"; then - echo "Upgrade cancelled." - exit 0 - fi - - select_kernel "$latest_installed" - backup_boot_files - generate_initramfs "$latest_installed" - copy_kernel "$latest_installed" - - echo - success "Kernel upgrade complete!" - echo - echo -e "${BOLD}Next steps:${NC}" - echo " 1. Reboot your system" - echo " 2. Verify the new kernel is running: uname -r" - echo " 3. Run this script again to clean up old versions" - echo - fi - else - # Running kernel is the newest - offer cleanup - cleanup_old_versions - fi - exit 0 - fi - - echo - if ! confirm "Would you like to install this kernel update?"; then - echo "Update cancelled." - exit 0 - fi - - echo - install_kernel_update - - # Get the new version after installation - local new_version - new_version=$(get_latest_installed_version) - - if [[ -z "$new_version" ]]; then - error "Could not determine new kernel version" - exit 1 - fi - - print_summary "$current_version" "$new_version" - - if ! confirm "Proceed with the upgrade process?"; then - echo "Upgrade process cancelled. Kernel package is installed but boot files unchanged." - exit 0 - fi - - echo - select_kernel "$new_version" - backup_boot_files - generate_initramfs "$new_version" - copy_kernel "$new_version" - - echo - success "Kernel upgrade complete!" - echo - echo -e "${BOLD}╔════════════════════════════════════════════════════════════════╗${NC}" - echo -e "${BOLD}║ NEXT STEPS ║${NC}" - echo -e "${BOLD}╚════════════════════════════════════════════════════════════════╝${NC}" - echo - echo " 1. ${YELLOW}Reboot your system${NC}" - echo " 2. Verify the new kernel is running:" - echo " uname -r" - echo " Expected: ${GREEN}${new_version}${NC}" - echo - echo " 3. If the new kernel works correctly, run this script again" - echo " to clean up old versions" - echo - echo " 4. ${RED}If the system fails to boot:${NC}" - echo " - Boot from a live USB" - echo " - Mount your EFI partition" - echo " - Restore backups:" - echo " mv vmlinuz.efi.bak vmlinuz.efi" - echo " mv initramfs.img.bak initramfs.img" - echo -} - -main "$@"