ui_quiet_run wraps every install_packages/install_optional/group install/remove and the system update: while gum is available and the run is interactive, dnf output is hidden behind a spinner, then a single 'Installing: <pkgs> (N packages)' line. Full output is appended to $SETUP_DNF_LOG (/tmp/fedora-setup-dnf-<uid>.log); on failure the last 20 lines print in red so nothing is lost. Unattended and no-gum runs keep plain full output (logs/cron contract). Also: fallback ui_choose accepts 'x' to exit (muscle memory from the old menu), fixed a stray stdout newline leaking into captured answers (same class as the earlier '\nno' bug), fixed pluralization. Harness: piped fallback, pty gum run incl. a failing VirtualBox pick (red failure + log tail, menu survives, subsequent qemu install ok), unattended regression.
575 lines
19 KiB
Bash
Executable File
575 lines
19 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# setup.sh — unified Fedora configuration
|
|
# Target: bare/minimal Fedora 44 and newer
|
|
#
|
|
set -uo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
# shellcheck source=lib/common.sh
|
|
source "$SCRIPT_DIR/lib/common.sh"
|
|
# shellcheck source=lib/session.sh
|
|
source "$SCRIPT_DIR/lib/session.sh"
|
|
# shellcheck source=lib/ui.sh
|
|
source "$SCRIPT_DIR/lib/ui.sh"
|
|
|
|
# Full dnf output from quiet transactions lands here (shown on failure).
|
|
export SETUP_DNF_LOG="${SETUP_DNF_LOG:-/tmp/fedora-setup-dnf-$(id -u).log}"
|
|
: >> "$SETUP_DNF_LOG"
|
|
|
|
#------------------------------------------
|
|
# Defaults + argument parsing
|
|
# DEBUG_MODE must be initialised before anything reads it under set -u.
|
|
#------------------------------------------
|
|
DEBUG_MODE=false
|
|
ASSUME_YES=false
|
|
DE=""
|
|
TWM=""
|
|
SELINUX_OPT=""
|
|
SNAPPER_OPT=""
|
|
DOTFILES_OPT=""
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
setup.sh — unified Fedora configuration (Fedora 44+)
|
|
|
|
Usage:
|
|
./setup.sh interactive: pick a DE and a TWM
|
|
./setup.sh --de=none --twm=niri non-interactive, explicit choices
|
|
./setup.sh --debug pause after each section
|
|
|
|
Options:
|
|
--de=NAME gnome | plasma | xfce | none
|
|
--twm=NAME chadwm | hyprland | mango | niri | none
|
|
--selinux=X keep | disabled (asked, default keep)
|
|
--snapper=X yes | no (automatic on btrfs; use 'no' to opt out)
|
|
--dotfiles=X yes | no (clone personal dotfiles, default no)
|
|
-y, --yes never prompt (requires --de and --twm)
|
|
-d, --debug pause after each section instead of aborting on error
|
|
-h, --help show this help
|
|
|
|
Valid DE/TWM combinations:
|
|
any DE + any TWM DE provides the session, TWM is added alongside it
|
|
none + any TWM TWM-only machine, SDDM is installed as the greeter
|
|
any DE + none plain desktop, no tiling window manager
|
|
none + none refused: that is not a graphical system
|
|
|
|
Notes:
|
|
* chadwm is an X11 window manager; the other three are Wayland compositors.
|
|
* Run as your normal user, not root. sudo is used where needed.
|
|
EOF
|
|
}
|
|
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
-d|--debug) DEBUG_MODE=true ;;
|
|
-y|--yes) ASSUME_YES=true ;;
|
|
--de=*) DE="${arg#*=}" ;;
|
|
--selinux=*) SELINUX_OPT="${arg#*=}" ;;
|
|
--snapper=*) SNAPPER_OPT="${arg#*=}" ;;
|
|
--dotfiles=*) DOTFILES_OPT="${arg#*=}" ;;
|
|
--twm=*) TWM="${arg#*=}" ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*)
|
|
err "Unknown argument: $arg"
|
|
printf "\n"
|
|
usage
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
export DEBUG_MODE ASSUME_YES
|
|
|
|
if is_debug; then
|
|
set +e # walk through failures instead of dying on the first one
|
|
else
|
|
set -e
|
|
fi
|
|
|
|
#------------------------------------------
|
|
# Preconditions
|
|
#------------------------------------------
|
|
# clear can fail without TERM (cron, piped install, ssh without a tty) and would
|
|
# abort the whole run under set -e.
|
|
clear 2>/dev/null || true
|
|
|
|
printf "\n"
|
|
color_yellow "----------------------------------------------------------------"
|
|
color_yellow "Fedora unified configuration"
|
|
color_yellow "----------------------------------------------------------------"
|
|
|
|
if [[ ${EUID} -eq 0 ]]; then
|
|
err "Do not run this as root. Run it as your user; it calls sudo itself."
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$ASSUME_YES" == "true" && ( -z "$DE" || -z "$TWM" ) ]]; then
|
|
err "--yes requires explicit --de and --twm, so nothing is guessed on an"
|
|
err "unattended run. Example:"
|
|
err " ./setup.sh --yes --de=none --twm=niri"
|
|
exit 2
|
|
fi
|
|
|
|
if is_debug; then
|
|
color_red "!!! DEBUG MODE ENABLED !!!"
|
|
color_red "The script will pause after each section."
|
|
fi
|
|
|
|
#------------------------------------------
|
|
# OS gate — Fedora only, 44+
|
|
#------------------------------------------
|
|
step "OS detection"
|
|
rule
|
|
|
|
# Overridable so the script can be tested on a non-Fedora host.
|
|
OS_RELEASE_FILE="${OS_RELEASE_FILE:-/etc/os-release}"
|
|
# shellcheck source=/dev/null
|
|
source "$OS_RELEASE_FILE"
|
|
|
|
OS_ID="${ID:-unknown}"; OS_ID="${OS_ID,,}"
|
|
OS_PRETTY="${PRETTY_NAME:-unknown}"
|
|
|
|
if [[ "$OS_ID" != "fedora" ]]; then
|
|
err "Unsupported distribution: $OS_PRETTY (ID=${OS_ID})"
|
|
err "This repo targets Fedora only. RHEL clones are refused on purpose:"
|
|
err "they ship no dnf5 config-manager and no RPM Fusion, so both the base"
|
|
err "setup and every module would fail half-way."
|
|
exit 1
|
|
fi
|
|
|
|
FEDORA_REL=$(rpm -E %fedora)
|
|
if [[ "$FEDORA_REL" =~ ^[0-9]+$ ]] && (( FEDORA_REL < 44 )); then
|
|
err "$OS_PRETTY reports release ${FEDORA_REL}, but this setup targets Fedora 44+."
|
|
exit 1
|
|
fi
|
|
|
|
ok "Detected: $OS_PRETTY (release ${FEDORA_REL})"
|
|
pause_if_debug
|
|
|
|
#------------------------------------------
|
|
# 1 Base settings
|
|
#------------------------------------------
|
|
step "1 Base settings"
|
|
rule
|
|
|
|
if ! command -v curl >/dev/null 2>&1; then
|
|
info "curl missing. Installing..."
|
|
install_packages curl
|
|
fi
|
|
|
|
# gum drives the styled menus/spinners when a TTY is present; the script's
|
|
# plain-text fallback means this is an enhancement, not a dependency.
|
|
if ! pkg_installed gum; then
|
|
install_optional gum
|
|
fi
|
|
|
|
# config-manager lives in dnf5-plugins; every repo step below depends on it.
|
|
if ! dnf config-manager --help >/dev/null 2>&1; then
|
|
info "dnf config-manager missing. Installing dnf5-plugins..."
|
|
install_packages dnf5-plugins
|
|
fi
|
|
|
|
info "Tuning DNF..."
|
|
sudo dnf config-manager setopt max_parallel_downloads=20
|
|
sudo dnf config-manager setopt defaultyes=True
|
|
|
|
info "Refreshing metadata..."
|
|
sudo dnf makecache --refresh
|
|
|
|
add_rpmfusion_repo
|
|
# Terra up front: it carries mangowc (noctalia moved into Fedora proper in
|
|
# F44). Idempotent; also kept for the standalone-mango-module case.
|
|
add_terra_repo
|
|
pause_if_debug
|
|
|
|
if ! command -v flatpak >/dev/null 2>&1; then
|
|
info "Flatpak missing. Installing..."
|
|
install_packages flatpak
|
|
fi
|
|
info "Ensuring Flathub is available (system-wide)..."
|
|
sudo flatpak remote-add --if-not-exists --system flathub https://dl.flathub.org/repo/flathub.flatpakrepo
|
|
|
|
# Update the system (spinner + one-line summary; full output in $SETUP_DNF_LOG)
|
|
ui_quiet_run "Updating the system" sudo dnf update -y
|
|
pause_if_debug
|
|
|
|
#------------------------------------------
|
|
# 2 Menu helpers
|
|
#------------------------------------------
|
|
# $1 = prompt, $2 = default answer, rest = valid answers
|
|
#------------------------------------------
|
|
# 3 System settings
|
|
#------------------------------------------
|
|
SELINUX_DISABLED=false
|
|
BTRFS_SNAPPER=false
|
|
|
|
if [[ -z "$SELINUX_OPT" ]]; then
|
|
step "3 System settings"
|
|
rule
|
|
printf "\n"
|
|
printf "\n"
|
|
choice=$(ui_confirm "Disable SELinux permanently? (not recommended)" "no")
|
|
[[ "$choice" == "yes" ]] && SELINUX_DISABLED=true
|
|
printf "\n"
|
|
if findmnt -n -o FSTYPE / 2>/dev/null | grep -q btrfs; then
|
|
ok "Root filesystem is btrfs — snapshots + zstd compression will be set up."
|
|
BTRFS_SNAPPER=true
|
|
else
|
|
info "Root filesystem is not btrfs; skipping snapshot setup."
|
|
fi
|
|
fi
|
|
|
|
case "${SELINUX_OPT:-}" in
|
|
disabled) SELINUX_DISABLED=true ;;
|
|
keep|"") : ;;
|
|
*) err "Unknown --selinux value: '$SELINUX_OPT' (keep|disabled)"; exit 2 ;;
|
|
esac
|
|
case "${SNAPPER_OPT:-}" in
|
|
yes) BTRFS_SNAPPER=true ;;
|
|
no) BTRFS_SNAPPER=false ;; # explicit flag beats the interactive default
|
|
""|keep) : ;;
|
|
*) err "Unknown --snapper value: '$SNAPPER_OPT' (yes|no)"; exit 2 ;;
|
|
esac
|
|
|
|
DOTFILES=false
|
|
if [[ -z "$DOTFILES_OPT" ]]; then
|
|
printf "\n"
|
|
choice=$(ui_confirm "Clone personal dotfiles (fedora-dots) into \$HOME?" "no")
|
|
[[ "$choice" == "yes" ]] && DOTFILES=true
|
|
else
|
|
case "$DOTFILES_OPT" in
|
|
yes) DOTFILES=true ;;
|
|
no) : ;;
|
|
*) err "Unknown --dotfiles value: '$DOTFILES_OPT' (yes|no)"; exit 2 ;;
|
|
esac
|
|
fi
|
|
pause_if_debug
|
|
|
|
#------------------------------------------
|
|
# 4 Desktop environment selection
|
|
#------------------------------------------
|
|
if [[ -z "$DE" ]]; then
|
|
step "4 Desktop environment"
|
|
rule
|
|
color_gray " Bare Fedora install — picking a DE is what gives you a graphical login."
|
|
choice=$(ui_choose "Desktop environment" "Select desktop environment:" \
|
|
"None (TWM only, SDDM via TWM module)" \
|
|
"GNOME (gdm)" "Plasma (sddm)" "XFCE (sddm)" "None (TWM only, SDDM via TWM module)")
|
|
case "$choice" in
|
|
GNOME*) DE="gnome" ;;
|
|
Plasma*) DE="plasma" ;;
|
|
XFCE*) DE="xfce" ;;
|
|
*) DE="none" ;;
|
|
esac
|
|
fi
|
|
|
|
case "$DE" in
|
|
gnome|plasma|xfce|none) ;;
|
|
*) err "Unknown --de value: '$DE' (gnome|plasma|xfce|none)"; exit 2 ;;
|
|
esac
|
|
pause_if_debug
|
|
|
|
#------------------------------------------
|
|
# 5 Tiling window manager selection
|
|
#------------------------------------------
|
|
if [[ -z "$TWM" ]]; then
|
|
step "5 Tiling window manager"
|
|
rule
|
|
choice=$(ui_choose "Tiling window manager" "Select a tiling window manager:" \
|
|
"None" \
|
|
"Niri (Wayland, scrollable)" "Hyprland (Wayland, dynamic)" \
|
|
"MangoWC (Wayland, Terra repo)" "chadwm (X11, source build)" "None")
|
|
case "$choice" in
|
|
Niri*) TWM="niri" ;;
|
|
Hyprland*) TWM="hyprland" ;;
|
|
MangoWC*) TWM="mango" ;;
|
|
chadwm*) TWM="chadwm" ;;
|
|
*) TWM="none" ;;
|
|
esac
|
|
fi
|
|
|
|
case "$TWM" in
|
|
niri|hyprland|mango|chadwm|none) ;;
|
|
*) err "Unknown --twm value: '$TWM' (niri|hyprland|mango|chadwm|none)"; exit 2 ;;
|
|
esac
|
|
|
|
ok "Selection: DE=${DE} TWM=${TWM}"
|
|
|
|
# A bare install with neither is not a graphical system. Refuse rather than
|
|
# leave the user with a machine that boots to a black screen.
|
|
if [[ "$DE" == "none" && "$TWM" == "none" ]]; then
|
|
err "DE=none with TWM=none would leave no graphical session at all."
|
|
err "Pick a desktop environment, a tiling window manager, or both."
|
|
exit 2
|
|
fi
|
|
pause_if_debug
|
|
|
|
#------------------------------------------
|
|
# 5 Dispatch
|
|
#------------------------------------------
|
|
export DE TWM
|
|
|
|
run_module() {
|
|
local path="$1"
|
|
if [[ ! -f "$path" ]]; then
|
|
err "Module not found: $path"
|
|
return 1
|
|
fi
|
|
info "Running $(basename "$path")"
|
|
printf "\n"
|
|
# Separate process: a module's own shell options and exit codes stay its own.
|
|
bash "$path"
|
|
}
|
|
|
|
step "5 Installation"
|
|
rule
|
|
|
|
if [[ "$SELINUX_DISABLED" == "true" ]]; then
|
|
disable_selinux
|
|
pause_if_debug
|
|
fi
|
|
|
|
if [[ "$BTRFS_SNAPPER" == "true" ]]; then
|
|
ensure_btrfs_compression
|
|
setup_snapper
|
|
pause_if_debug
|
|
fi
|
|
|
|
if [[ "$DOTFILES" == "true" ]]; then
|
|
run_module "$SCRIPT_DIR/modules/user/dotfiles.sh"
|
|
pause_if_debug
|
|
fi
|
|
|
|
if [[ "$DE" != "none" ]]; then
|
|
run_module "$SCRIPT_DIR/modules/de/${DE}.sh"
|
|
pause_if_debug
|
|
fi
|
|
|
|
if [[ "$TWM" != "none" ]]; then
|
|
run_module "$SCRIPT_DIR/modules/twm/${TWM}.sh"
|
|
pause_if_debug
|
|
fi
|
|
|
|
#------------------------------------------
|
|
# 6 Done
|
|
#------------------------------------------
|
|
|
|
#------------------------------------------
|
|
# 6 Always-installed packages
|
|
#------------------------------------------
|
|
# Add a category here and it is installed on every run, no questions asked.
|
|
# Keep each category one line so diffs stay readable.
|
|
ALWAYS_PACKAGES=(
|
|
# Terminals
|
|
"ghostty ghostty-bash-completion"
|
|
)
|
|
|
|
step "6 Always-installed packages"
|
|
rule
|
|
|
|
for category in "${ALWAYS_PACKAGES[@]}"; do
|
|
# shellcheck disable=SC2086
|
|
install_packages $category
|
|
done
|
|
ok "Always-packages installed."
|
|
pause_if_debug
|
|
|
|
|
|
#------------------------------------------
|
|
# 7 Advanced: optional tool selection (menu-driven)
|
|
#------------------------------------------
|
|
# Add categories/apps by editing these parallel arrays:
|
|
# ADV_CATEGORIES : display order
|
|
# ADV_<NAME> : "pkg1 pkg2 ..." for each category (dots/minus -> underscore)
|
|
ADV_CATEGORIES=(
|
|
"Virtualisation"
|
|
"Browsers"
|
|
)
|
|
# shellcheck disable=SC2034 # arrays are read via nameref from ADV_CATEGORIES
|
|
ADV_Virtualisation=(
|
|
"qemu-kvm:QEMU/KVM (full virt stack):qemu-kvm libvirt virt-install virt-manager virt-viewer edk2-ovmf swtpm guestfs-tools libguestfs-tools"
|
|
"virtualbox:VirtualBox (Oracle):VirtualBox kernel-devel kernel-headers dkms akmod-VirtualBox"
|
|
)
|
|
# shellcheck disable=SC2034 # arrays are read via nameref from ADV_CATEGORIES
|
|
ADV_Browsers=(
|
|
"firefox:Firefox:firefox"
|
|
"chromium:Chromium:chromium"
|
|
"google-chrome:Google Chrome (adds repo):google-chrome-stable"
|
|
"brave:Brave (adds repo):brave-browser"
|
|
)
|
|
|
|
run_advanced_menu() {
|
|
local done_any=false
|
|
while true; do
|
|
local cat
|
|
cat=$(ui_choose "Optional tools" "Select a category (last item exits):" \
|
|
"Done with optional tools" \
|
|
"${ADV_CATEGORIES[@]}" "Done with optional tools")
|
|
[[ "$cat" == "Done with optional tools" ]] && break
|
|
|
|
# apps for this category — nameref, because ${!var} on an array name
|
|
# would only give element 0 (that bug showed in testing: Browsers
|
|
# listed exactly one entry)
|
|
local var="ADV_${cat//[ .-]/_}"
|
|
local -n entries_ref="$var"
|
|
local -a entries
|
|
# shellcheck disable=SC2206
|
|
entries=("${entries_ref[@]}")
|
|
|
|
# Labels for the picker (gum multi-select or numbered fallback).
|
|
# Entry format: id:Label:packages...
|
|
local entry rest lbl
|
|
local -a labels=()
|
|
for entry in "${entries[@]}"; do
|
|
rest="${entry#*:}"
|
|
labels+=("${rest%%:*}")
|
|
done
|
|
|
|
# ui_choose_multi prints the chosen labels (one per line).
|
|
local sel picked
|
|
sel=$(ui_choose_multi "$cat" "Install which? (multi-select, none = back):" "${labels[@]}")
|
|
[[ -z "$sel" ]] && continue
|
|
|
|
# Map chosen labels back to their package lists. Word-split each
|
|
# package list into SEPARATE args: quoting it whole makes dnf look for
|
|
# one package named "qemu-kvm libvirt ..." (seen on the VM).
|
|
local -a to_install=()
|
|
while IFS= read -r picked; do
|
|
[[ -z "$picked" ]] && continue
|
|
for entry in "${entries[@]}"; do
|
|
rest="${entry#*:}"
|
|
lbl="${rest%%:*}"
|
|
if [[ "$lbl" == "$picked" ]]; then
|
|
rest="${entry#*:}"; rest="${rest#*:}" # drop id and label
|
|
# shellcheck disable=SC2206
|
|
to_install+=(${rest})
|
|
fi
|
|
done
|
|
done <<< "$sel"
|
|
|
|
if (( ${#to_install[@]} > 0 )); then
|
|
step "Installing from $cat: ${to_install[*]}"
|
|
# install_category_pkgs wires any needed third-party repo first.
|
|
# Failure must NOT kill the script: warn in red and drop back to
|
|
# the menu (set -e is bypassed for this one call).
|
|
if install_category_pkgs "$cat" "${to_install[@]}"; then
|
|
done_any=true
|
|
else
|
|
color_red " Installation failed: ${to_install[*]}"
|
|
color_red " (dnf reported no match / transaction failure — see output above)"
|
|
warn " Returning to the menu. The system is unchanged."
|
|
pause_if_debug
|
|
fi
|
|
unset to_install; local -a to_install=() # fresh slate for next pick
|
|
fi
|
|
done
|
|
# not `&& ok` — a false done_any would return 1 and kill the script under set -e
|
|
if [[ "$done_any" == "true" ]]; then
|
|
ok "Optional tools installed."
|
|
fi
|
|
}
|
|
|
|
# Per-category pre-repo wiring. Add third-party repos here when you add an
|
|
# app that needs one; packages alone stay generic.
|
|
install_category_pkgs() {
|
|
local cat="$1"; shift
|
|
case "$cat" in
|
|
Virtualisation)
|
|
# qemu:///system without password prompts: libvirt group + enabled
|
|
# daemon. Only when the picked packages actually use libvirt.
|
|
local wants_libvirt=false item
|
|
for item in "$@"; do
|
|
[[ "$item" == *libvirt* || "$item" == *virt-manager* || "$item" == *virt-install* ]] && wants_libvirt=true
|
|
done
|
|
if $wants_libvirt; then
|
|
local real_user="${SUDO_USER:-$USER}"
|
|
info "Enabling libvirtd and adding $real_user to the libvirt group..."
|
|
sudo systemctl enable --now libvirtd 2>/dev/null || true
|
|
sudo usermod -aG libvirt "$real_user" || true
|
|
warn "libvirt group membership applies after re-login."
|
|
fi
|
|
;;
|
|
Browsers)
|
|
local needs_chrome=false needs_brave=false item
|
|
for item in "$@"; do
|
|
[[ "$item" == *google-chrome* ]] && needs_chrome=true
|
|
[[ "$item" == *brave* ]] && needs_brave=true
|
|
done
|
|
if $needs_chrome && ! pkg_installed google-chrome-stable; then
|
|
info "Adding Google Chrome repo..."
|
|
sudo dnf install -y fedora-workstation-repositories 2>/dev/null || true
|
|
sudo dnf config-manager setopt google-chrome.enabled=1 2>/dev/null || \
|
|
sudo dnf install -y "https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm"
|
|
fi
|
|
if $needs_brave && ! pkg_installed brave-browser; then
|
|
info "Adding Brave repo..."
|
|
sudo dnf install -y dnf-plugins-core
|
|
sudo dnf config-manager add --from-repofile=https://brave-browser-rpm-release.s3.brave.com/brave-browser.repo || \
|
|
true
|
|
sudo rpm --import https://brave-browser-rpm-release.s3.brave.com/brave-core.asc 2>/dev/null || true
|
|
fi
|
|
;;
|
|
esac
|
|
# Resilient install: report failure but return non-zero instead of
|
|
# aborting under set -e; the caller turns it into a red warning.
|
|
install_packages "$@" || return 1
|
|
return 0
|
|
}
|
|
|
|
# Interactive only: an unattended --yes run must not hang on this menu.
|
|
# Skip silently there; use --de/--twm/--dotfiles for everything unattended.
|
|
if [[ "$ASSUME_YES" != "true" ]]; then
|
|
run_advanced_menu
|
|
fi
|
|
pause_if_debug
|
|
|
|
step "8 Summary"
|
|
rule
|
|
|
|
# Post-install wiring that must see the FINAL package state. The libvirt
|
|
# group add earlier (menu/module time) can miss packages installed later in
|
|
# the same run — this is the authoritative pass (VM-proven: a fresh run left
|
|
# the user out of the group when virt-manager landed after the check).
|
|
ensure_libvirt_group() {
|
|
# shellcheck source=lib/common.sh
|
|
source "$SCRIPT_DIR/lib/common.sh" 2>/dev/null || true
|
|
if pkg_installed_any libvirt libvirt-daemon libvirt-daemon-driver-qemu virt-manager \
|
|
|| [[ -x /usr/sbin/libvirtd ]]; then
|
|
local real_user="${SUDO_USER:-$USER}"
|
|
if ! id -nG "$real_user" 2>/dev/null | grep -qw libvirt; then
|
|
info "Adding $real_user to the libvirt group (re-login to apply)..."
|
|
sudo usermod -aG libvirt "$real_user" || true
|
|
warn "Group membership applies after re-login — do it before using virt-manager."
|
|
fi
|
|
fi
|
|
}
|
|
ensure_libvirt_group
|
|
ok "DE: $DE"
|
|
ok "TWM: $TWM"
|
|
ok "SELinux: $([[ "$SELINUX_DISABLED" == "true" ]] && echo disabled || echo keeping)"
|
|
ok "Btrfs snapshots: $([[ "$BTRFS_SNAPPER" == "true" ]] && echo yes || echo skipped)"
|
|
ok "Dotfiles: $([[ "$DOTFILES" == "true" ]] && echo clone || echo no)"
|
|
DM=$(detect_display_manager)
|
|
ok "Display manager: ${DM:-none}"
|
|
|
|
if [[ -z "$DM" ]]; then
|
|
warn "No display manager is active. You will boot to a text console."
|
|
warn "Install one, or run a TWM module which sets up SDDM."
|
|
fi
|
|
|
|
printf "\n"
|
|
color_green "Fedora setup complete. A reboot is recommended."
|
|
if [[ "$ASSUME_YES" == "true" ]]; then
|
|
info "Unattended run: not rebooting."
|
|
exit 0
|
|
fi
|
|
|
|
reboot_choice=$(ui_confirm "Reboot now?" "no")
|
|
if [[ "$reboot_choice" == "yes" ]]; then
|
|
color_red "Rebooting now."
|
|
sudo reboot
|
|
else
|
|
color_yellow "Skipping reboot."
|
|
exit 0
|
|
fi
|