Files
Fedora-PIS/postinstall.sh
T

816 lines
29 KiB
Bash

#!/bin/bash
# Post install script for Fedora
# Author: Jacob Schantli
# Version: 1.1
# Make a pipeline fail if any command in it fails. Without this,
# `curl ... | bash` reports success even when the download fails.
set -o pipefail
# Steps that failed during this run (shown in the summary at the end)
FAILED_STEPS=()
# -----------------------------------------------------------------------------
# Global Configuration
# -----------------------------------------------------------------------------
DNF_PACKAGES=(
"gnome-tweaks"
"steam"
"lutris"
"btop"
"fastfetch"
"distrobox"
"pipx"
"bash-completion"
"tar"
"bat"
"tree"
"unzip"
"git"
"fzf"
"mpv"
"fuse"
"fuse-libs"
"nodejs"
)
FLATPAK_PACKAGES=(
"com.github.tchx84.Flatseal"
"net.nokyan.Resources"
"com.mattjakeman.ExtensionManager"
"io.github.realmazharhussain.GdmSettings"
"com.ranfdev.DistroShelf"
"it.mijorus.gearlever"
"io.github.fastrizwaan.WineZGUI"
"com.vysp3r.ProtonPlus"
"io.missioncenter.MissionCenter"
"io.github.peazip.PeaZip"
#"app.devsuite.Ptyxis"
"re.sonny.Junction"
#"com.github.rafostar.Clapper"
"io.github.flattool.Ignition"
"io.github.swordpuffin.rewaita"
"page.tesk.Refine"
#"io.gitlab.adhami3310.Converter"
"com.usebottles.bottles"
"com.bambulab.BambuStudio"
"com.collaboraoffice.Office"
"io.github.kolunmi.Bazaar"
"com.fastmail.Fastmail"
"org.waywallen.waywallen"
)
GNOME_EXTENSIONS=(
"dash-to-dock@micxgx.gmail.com"
"dynamic-music-pill@andbal"
"gamemodeshellextension@trsnaqe.com"
"gnome-fuzzy-app-search@gnome-shell-extensions.Czarlie.gitlab.com"
"IP-Finder@linxgem33.com"
"lan-ip-address@mrhuber.com"
"add-to-steam@pupper.space"
"appindicatorsupport@rgcjonas.gmail.com"
"bazaar-integration@kolunmi.github.io"
"blur-my-shell@aunetx"
"caffeine@patapon.info"
"compiz-alike-magic-lamp-effect@hermes83.github.com"
"gsconnect@andyholmes.github.io"
"hotedge@jonathan.jdoda.ca"
"logomenu@aryan_k"
"restartto@tiagoporsch.github.io"
"user-theme@gnome-shell-extensions.gcampax.github.com"
)
# -----------------------------------------------------------------------------
# Helper Functions
# -----------------------------------------------------------------------------
# Colors for output
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Check if the last command was successful
check_status() {
local status=$?
if [ $status -eq 0 ]; then
log_info "$1 successful."
else
log_error "$1 failed."
FAILED_STEPS+=("$1")
# If the second argument is "critical", exit the script
if [ "$2" == "critical" ]; then
log_error "Critical error encountered. Exiting."
exit 1
fi
fi
}
# Append text to a file if it doesn't already exist
append_to_file_if_missing() {
local file="$1"
local text="$2"
local description="$3"
local use_sudo="$4"
if grep -Fq "$text" "$file"; then
log_warn "$description already exists in $file. Skipping."
else
if [ "$use_sudo" == "true" ]; then
echo "$text" | sudo tee -a "$file" > /dev/null
else
echo "$text" >> "$file"
fi
log_info "Added $description to $file."
fi
}
# -----------------------------------------------------------------------------
# Installation Functions
# -----------------------------------------------------------------------------
optimize_dnf() {
log_info "----------------------------------------------------"
log_info "Modifying /etc/dnf/dnf.conf for faster downloads."
log_info "----------------------------------------------------"
DNF_CONF="/etc/dnf/dnf.conf"
if [ -f "$DNF_CONF" ]; then
append_to_file_if_missing "$DNF_CONF" "max_parallel_downloads=10" "max_parallel_downloads" "true"
append_to_file_if_missing "$DNF_CONF" "defaultyes=True" "defaultyes" "true"
append_to_file_if_missing "$DNF_CONF" "keepcache=True" "keepcache" "true"
else
log_error "$DNF_CONF not found!"
fi
sleep 1
}
install_fonts() {
log_info "----------------------------------------------------"
log_info "Installing Meslo Nerd Font."
log_info "----------------------------------------------------"
log_info "Updating system and installing prerequisites..."
sudo dnf upgrade --refresh -y
check_status "System upgrade" "critical"
sudo dnf install -y curl fontconfig wget unzip
check_status "Prerequisites installation" "critical"
log_info "Installing Meslo Nerd Font..."
FONT_NAME="MesloLGS Nerd Font Mono"
# Redirect instead of `grep -q` so fc-list isn't killed by SIGPIPE (pipefail)
if fc-list :family | grep -i "$FONT_NAME" > /dev/null; then
log_info "Font '$FONT_NAME' is already installed."
else
log_info "Installing font '$FONT_NAME'..."
FONT_URL="https://github.com/ryanoasis/nerd-fonts/releases/latest/download/Meslo.zip"
FONT_DIR="$HOME/.local/share/fonts"
TEMP_DIR=$(mktemp -d)
wget -q -O "$TEMP_DIR/Meslo.zip" "$FONT_URL" \
&& unzip -q "$TEMP_DIR/Meslo.zip" -d "$TEMP_DIR" \
&& mkdir -p "$FONT_DIR/$FONT_NAME" \
&& mv "$TEMP_DIR"/*.ttf "$FONT_DIR/$FONT_NAME/" \
&& fc-cache -f "$FONT_DIR"
check_status "Meslo Nerd Font installation" "non-critical"
rm -rf "$TEMP_DIR"
fi
}
install_repos() {
log_info "----------------------------------------------------"
log_info "Adding RPM Fusion repositories."
log_info "----------------------------------------------------"
sudo dnf install -y \
"https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm" \
"https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm"
check_status "RPM Fusion repositories installation" "non-critical"
}
install_software() {
log_info "----------------------------------------------------"
log_info "Installing most used software."
log_info "----------------------------------------------------"
log_info "Installing DNF packages..."
sudo dnf install -y "${DNF_PACKAGES[@]}"
check_status "DNF packages installation" "non-critical"
# Ensure flatpak is set up
if ! command -v flatpak &> /dev/null; then
log_info "Flatpak not found. Installing..."
sudo dnf install -y flatpak
fi
log_info "Adding Flathub remote and setting its priority..."
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
sudo flatpak remote-modify --prio=10 flathub || true
check_status "Flathub remote add" "non-critical"
log_info "Installing Flatpak packages..."
# One transaction is much faster (single dependency resolution, shared
# runtimes downloaded once). If it fails, retry one-by-one so a single
# bad app ID doesn't block the rest.
if flatpak install flathub -y "${FLATPAK_PACKAGES[@]}"; then
log_info "Flatpak packages installation successful."
else
log_warn "Batch Flatpak install failed. Retrying apps individually..."
for app in "${FLATPAK_PACKAGES[@]}"; do
log_info "Installing $app..."
flatpak install flathub -y "$app"
check_status "Flatpak $app" "non-critical"
done
fi
log_info "----------------------------------------------------"
log_info "Installing Homebrew"
log_info "----------------------------------------------------"
# Install Homebrew (also detect it when it isn't on PATH yet)
if command_exists brew || [ -x "/home/linuxbrew/.linuxbrew/bin/brew" ]; then
log_info "Homebrew already installed."
else
log_info "Installing Homebrew..."
# Download first so a failed download isn't reported as success.
# NONINTERACTIVE=1 avoids prompts during brew install.
BREW_INSTALLER=$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh) \
&& NONINTERACTIVE=1 /bin/bash -c "$BREW_INSTALLER"
check_status "Homebrew installation" "non-critical"
# Add brew to path for the current session
if [ -d "/home/linuxbrew/.linuxbrew/bin" ]; then
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
elif [ -d "$HOME/.linuxbrew/bin" ]; then
eval "$($HOME/.linuxbrew/bin/brew shellenv)"
fi
fi
}
install_discord() {
log_info "----------------------------------------------------"
log_info "Installing Discord"
log_info "----------------------------------------------------"
if rpm -q discord > /dev/null 2>&1; then
log_info "Discord already installed."
else
log_info "Downloading and installing Discord..."
sudo dnf install -y "https://discord.com/api/download?platform=linux&format=rpm"
check_status "Discord installation" "non-critical"
fi
}
install_1password() {
log_info "----------------------------------------------------"
log_info "Installing 1Password"
log_info "----------------------------------------------------"
if rpm -q 1password > /dev/null 2>&1; then
log_info "1Password already installed."
else
log_info "Downloading and installing 1Password..."
sudo dnf install -y https://downloads.1password.com/linux/rpm/stable/x86_64/1password-latest.rpm
check_status "1Password installation" "non-critical"
fi
}
install_PIA() {
log_info "----------------------------------------------------"
log_info "Installing Private Internet Access (PIA)"
log_info "----------------------------------------------------"
if [ -d "/opt/piavpn" ]; then
log_info "PIA is already installed."
else
log_info "Downloading and installing PIA..."
PIA_URL=$(curl -s https://www.privateinternetaccess.com/download/linux-vpn | grep -oP 'https://[^\"]+pia-linux-[0-9\.\-]+\.run' | head -n 1)
if [ -n "$PIA_URL" ]; then
wget -qO /tmp/pia-linux.run "$PIA_URL"
chmod +x /tmp/pia-linux.run
# Run the installer as the current user, letting it prompt for sudo/pkexec if needed
/tmp/pia-linux.run --quiet --accept
rm /tmp/pia-linux.run
check_status "PIA installation" "non-critical"
else
log_error "Failed to fetch PIA download URL."
FAILED_STEPS+=("PIA installation")
fi
fi
}
install_cachyos() {
log_info "----------------------------------------------------"
log_info "Installing CachyOS kernel"
log_info "----------------------------------------------------"
# kernel-cachyos is built for x86-64-v3 CPUs. Ask before installing it on
# an older CPU, where the new (default) boot entry may not start.
if ! /lib64/ld-linux-x86-64.so.2 --help 2>/dev/null | grep 'x86-64-v3 (supported' > /dev/null; then
log_warn "Your CPU does not appear to support x86-64-v3, which kernel-cachyos targets."
read -p "Install the CachyOS kernel anyway? [y/N]: " reply
if [[ ! "$reply" =~ ^[Yy]$ ]]; then
log_info "Skipping CachyOS kernel."
return
fi
fi
sudo dnf copr enable -y bieszczaders/kernel-cachyos
check_status "Enabling CachyOS Copr" "non-critical"
sudo dnf install -y kernel-cachyos kernel-cachyos-devel-matched
check_status "CachyOS Kernel installation" "non-critical"
log_info "Installing CachyOS addons"
sudo dnf copr enable -y bieszczaders/kernel-cachyos-addons
check_status "Enabling CachyOS Addons Copr" "non-critical"
sudo dnf swap -y zram-generator-defaults cachyos-settings
sudo dracut -f
sudo dnf -y install scx-scheds scx-tools scx-manager ananicy-cpp
check_status "CachyOS addons installation" "non-critical"
}
install_p03() {
log_info "----------------------------------------------------"
log_info "Installing P03 kernel"
log_info "----------------------------------------------------"
# The default kernel-p03 build needs x86-64-v3 and won't boot on older
# CPUs. Those get the x86-64-v2 build (kernel-p03-gcc) instead.
if /lib64/ld-linux-x86-64.so.2 --help 2>/dev/null | grep 'x86-64-v3 (supported' > /dev/null; then
P03_PACKAGE="kernel-p03"
else
log_warn "CPU lacks x86-64-v3 support. Installing the x86-64-v2 build (kernel-p03-gcc)."
P03_PACKAGE="kernel-p03-gcc"
fi
sudo dnf copr enable -y catpieleaf/kernel-p03
check_status "Enabling P03 Copr" "non-critical"
sudo dnf install -y "$P03_PACKAGE"
check_status "P03 kernel installation" "non-critical"
# P03 signs itself with a locally generated key. With Secure Boot on, that
# key must be enrolled or the kernel won't boot.
if mokutil --sb-state 2>/dev/null | grep -i 'SecureBoot enabled' > /dev/null; then
log_info "Secure Boot is enabled. Enrolling the P03 signing key..."
log_info "Pick a one-time password. On the next boot, choose 'Enroll MOK' and enter it."
sudo mokutil --import /etc/kernel/certs/p03-kernel/mok.der
check_status "P03 Secure Boot key enrollment" "non-critical"
fi
if rpm -q kernel-cachyos > /dev/null 2>&1; then
log_warn "The CachyOS kernel is also installed. The newest kernel usually boots by default;"
log_warn "pick the other one from the boot menu if needed."
fi
log_warn "P03 uses the PRJC scheduler, so sched_ext schedulers (scx-scheds) likely won't work on it."
}
install_linuxtoys() {
log_info "----------------------------------------------------"
log_info "Installing LinuxToys"
log_info "----------------------------------------------------"
curl -fsSL https://linux.toys/install.sh | bash
check_status "LinuxToys installation" "non-critical"
}
install_shell_env() {
log_info "----------------------------------------------------"
log_info "Installing Shell Environment (Starship, FZF, Zoxide, MyBash)"
log_info "----------------------------------------------------"
# Install Starship
if command_exists starship; then
log_info "Starship already installed."
else
log_info "Installing Starship..."
# -y skips the installer's confirmation prompt
curl -sSL https://starship.rs/install.sh | sudo sh -s -- -y
check_status "Starship installation" "non-critical"
fi
# Install FZF (Fallback if not installed via DNF)
if ! command_exists fzf; then
log_info "Installing FZF via git..."
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
~/.fzf/install --all
fi
# Install Zoxide
if command_exists zoxide; then
log_info "Zoxide already installed."
else
log_info "Installing Zoxide..."
curl -sSL https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | sh
check_status "Zoxide installation" "non-critical"
fi
# Clone MyBash
log_info "Cloning MyBash configuration..."
GITPATH="$HOME/.local/share/mybash"
if [ -d "$GITPATH" ]; then
rm -rf "$GITPATH"
fi
mkdir -p "$HOME/.local/share"
if git clone https://gitea.schantli.ca/jschantli/mybash.git "$GITPATH"; then
log_info "MyBash cloned successfully."
# Link Config
log_info "Linking configuration files..."
OLD_BASHRC="$HOME/.bashrc"
# Check if .bashrc exists in the cloned repo
if [ -f "$GITPATH/.bashrc" ]; then
if [ -e "$OLD_BASHRC" ] && [ ! -e "$HOME/.bashrc.bak" ]; then
log_info "Backing up .bashrc to .bashrc.bak..."
mv "$OLD_BASHRC" "$HOME/.bashrc.bak"
fi
log_info "Linking new .bashrc..."
ln -svf "$GITPATH/.bashrc" "$HOME/.bashrc"
# Ensure Starship is initialized in the new .bashrc
if ! grep -q "starship init bash" "$HOME/.bashrc"; then
log_warn ".bashrc does not contain starship init. Appending it..."
echo 'eval "$(starship init bash)"' >> "$HOME/.bashrc"
fi
else
log_error "$GITPATH/.bashrc not found! Skipping .bashrc linking."
fi
# Check if starship.toml exists in the cloned repo
if [ -f "$GITPATH/starship.toml" ]; then
log_info "Linking starship.toml..."
mkdir -p "$HOME/.config"
ln -svf "$GITPATH/starship.toml" "$HOME/.config/starship.toml"
else
log_warn "$GITPATH/starship.toml not found! Skipping Starship config linking."
fi
# Check if config.jsonc exists in the cloned repo
if [ -f "$GITPATH/config.jsonc" ]; then
log_info "Linking config.jsonc..."
mkdir -p "$HOME/.config/fastfetch/"
ln -svf "$GITPATH/config.jsonc" "$HOME/.config/fastfetch/config.jsonc"
else
log_warn "$GITPATH/config.jsonc not found! Skipping fastfetch config linking."
fi
check_status "Linking config files" "non-critical"
else
log_error "Failed to clone MyBash repository. Skipping shell configuration."
fi
}
install_topgrade() {
log_info "----------------------------------------------------"
log_info "Installing Topgrade"
log_info "----------------------------------------------------"
if command_exists topgrade; then
log_info "Topgrade already installed."
return
fi
sudo dnf copr enable -y lilay/topgrade
check_status "Enabling Topgrade" "non-critical"
sudo dnf install -y topgrade
check_status "Topgrade installation" "non-critical"
}
install_gnome_extensions() {
log_info "----------------------------------------------------"
log_info "Installing GNOME extensions"
log_info "----------------------------------------------------"
# Ensure pipx is installed and path is set
if ! command -v pipx &> /dev/null; then
log_info "pipx not found. Installing..."
sudo dnf install -y pipx
pipx ensurepath
fi
# Install gnome-extensions-cli
log_info "Installing gnome-extensions-cli..."
pipx install gnome-extensions-cli --system-site-packages
check_status "gnome-extensions-cli installation" "non-critical"
# Define the tool path explicitly to avoid 'pipx run' overhead/warnings
EXTENSION_TOOL="$HOME/.local/bin/gnome-extensions-cli"
log_info "Installing GNOME extensions without user prompts (--filesystem backend)..."
for extension in "${GNOME_EXTENSIONS[@]}"; do
log_info "Processing $extension..."
# Install using the filesystem backend to bypass the GUI confirmation popups
"$EXTENSION_TOOL" --filesystem install "$extension"
check_status "GNOME Extension $extension" "non-critical"
# Attempt to enable the extension (in case it's installed but disabled)
log_info "Ensuring $extension is enabled..."
gnome-extensions enable "$extension" || true
done
log_info "Installing waywallen-display extension from GitHub..."
WAYWALLEN_URL=$(curl -s https://api.github.com/repos/waywallen/waywallen-display/releases/latest | grep -oP 'https://[^"]+waywallen-gnome-[^"]+-x86_64\.zip' | head -n 1)
if [ -n "$WAYWALLEN_URL" ]; then
TEMP_EXT=$(mktemp -d)
curl -sL "$WAYWALLEN_URL" -o "$TEMP_EXT/waywallen.zip"
gnome-extensions install -f "$TEMP_EXT/waywallen.zip"
gnome-extensions enable org.waywallen.gnome@waywallen.io || true
rm -rf "$TEMP_EXT"
check_status "Waywallen GNOME Extension" "non-critical"
else
log_error "Failed to resolve Waywallen extension download URL."
fi
}
install_antigravity() {
log_info "----------------------------------------------------"
log_info "Installing Antigravity App, IDE, and CLI"
log_info "----------------------------------------------------"
log_info "Installing Antigravity CLI..."
curl -fsSL https://antigravity.google/cli/install.sh | bash
check_status "Antigravity CLI installation" "non-critical"
log_info "Installing Antigravity App and IDE..."
sudo dnf install -y python3 nautilus-python curl tar
log_info "Fetching latest download URLs from Google..."
AG_URL=$(curl -fsSL --compressed https://antigravity.google/download | grep -oP 'https://\S+linux-x64/Antigravity\.tar\.gz' | head -n 1)
AG_IDE_URL=$(curl -fsSL --compressed https://antigravity.google/download | grep -oP 'https://\S+linux-x64/Antigravity%20IDE\.tar\.gz' | head -n 1)
if [ -z "$AG_URL" ] || [ -z "$AG_IDE_URL" ]; then
log_error "Failed to resolve Antigravity download URLs."
FAILED_STEPS+=("Antigravity installation")
return
fi
log_info "Installing Antigravity 2.0 App..."
sudo rm -rf /opt/antigravity
sudo mkdir -p /opt/antigravity
if ! curl -sL "$AG_URL" | sudo tar -xz -C /opt/antigravity --strip-components=1; then
log_error "Failed to extract Antigravity 2.0 App."
FAILED_STEPS+=("Antigravity installation")
return
fi
sudo ln -sfn /opt/antigravity/antigravity /usr/local/bin/antigravity
sudo mkdir -p /usr/share/applications /usr/share/icons/hicolor/512x512/apps
# Extract icon from app.asar
if [ -f "/opt/antigravity/resources/app.asar" ]; then
sudo python3 - /opt/antigravity/resources/app.asar /usr/share/icons/hicolor/512x512/apps/antigravity.png <<'PY'
import json, struct, sys
from pathlib import Path
asar = Path(sys.argv[1])
out = Path(sys.argv[2])
with asar.open('rb') as f:
f.read(4)
header_size = struct.unpack('<I', f.read(4))[0]
f.read(4)
json_size = struct.unpack('<I', f.read(4))[0]
header = json.loads(f.read(json_size).decode())
icon = header.get('files', {}).get('icon.png')
if icon:
with asar.open('rb') as f:
f.seek(8 + header_size + int(icon['offset']))
out.write_bytes(f.read(int(icon['size'])))
PY
fi
sudo bash -c 'cat > /usr/share/applications/antigravity.desktop' <<EOF
[Desktop Entry]
Name=Antigravity
Comment=Google Antigravity 2.0
Exec=/usr/local/bin/antigravity %U
Icon=antigravity
Terminal=false
Type=Application
Categories=Development;IDE;
StartupNotify=true
StartupWMClass=antigravity
EOF
log_info "Installing Antigravity IDE..."
sudo rm -rf /opt/antigravity-ide
sudo mkdir -p /opt/antigravity-ide
if ! curl -sL "$AG_IDE_URL" | sudo tar -xz -C /opt/antigravity-ide --strip-components=1; then
log_error "Failed to extract Antigravity IDE."
FAILED_STEPS+=("Antigravity IDE installation")
return
fi
sudo ln -sfn /opt/antigravity-ide/antigravity-ide /usr/local/bin/antigravity-ide
# Copy IDE icon from uncompressed resources
if [ -f "/opt/antigravity-ide/resources/app/resources/linux/code.png" ]; then
sudo cp "/opt/antigravity-ide/resources/app/resources/linux/code.png" /usr/share/icons/hicolor/512x512/apps/antigravity-ide.png
fi
sudo bash -c 'cat > /usr/share/applications/antigravity-ide.desktop' <<EOF
[Desktop Entry]
Name=Antigravity IDE
Comment=Google Antigravity IDE
Exec=/usr/local/bin/antigravity-ide %F
Icon=antigravity-ide
Terminal=false
Type=Application
Categories=Development;IDE;
StartupNotify=true
StartupWMClass=antigravity-ide
EOF
log_info "Refreshing desktop databases and icon caches..."
sudo update-desktop-database /usr/share/applications || true
sudo gtk-update-icon-cache -f -q /usr/share/icons/hicolor || true
log_info "Antigravity App and IDE installed successfully."
}
# -----------------------------------------------------------------------------
# Main Menu
# -----------------------------------------------------------------------------
show_menu() {
clear
echo "===================================================="
echo " Fedora Post-Install Script - Main Menu"
echo "===================================================="
echo "1. Install Everything (Prompts for Kernel)"
echo "2. Install Everything for Work (No Gaming, No Custom Kernels)"
echo "3. Optimize DNF"
echo "4. Install Fonts"
echo "5. Add Repositories (RPM Fusion)"
echo "6. Install Software (DNF & Flatpak)"
echo "7. Install CachyOS Kernel"
echo "8. Install LinuxToys"
echo "9. Install Shell Environment (Starship, MyBash)"
echo "10. Install GNOME Extensions"
echo "11. Install Discord"
echo "12. Install 1Password"
echo "13. Install Private Internet Access (PIA)"
echo "14. Install Topgrade"
echo "15. Install Antigravity App, IDE, and CLI"
echo "16. Install P03 Kernel (experimental, not in Install Everything)"
echo "0. Exit"
echo "===================================================="
read -p "Enter your choice [0-16]: " choice
}
enable_work_mode() {
log_info "Work Mode selected: Removing gaming-related packages from installation list..."
local new_dnf=()
for p in "${DNF_PACKAGES[@]}"; do
if [[ "$p" != "steam" && "$p" != "lutris" ]]; then
new_dnf+=("$p")
fi
done
DNF_PACKAGES=("${new_dnf[@]}")
local new_flatpak=()
for p in "${FLATPAK_PACKAGES[@]}"; do
if [[ "$p" != "com.usebottles.bottles" && "$p" != "io.github.fastrizwaan.WineZGUI" && "$p" != "com.vysp3r.ProtonPlus" && "$p" != "io.github.kolunmi.Bazaar" ]]; then
new_flatpak+=("$p")
fi
done
FLATPAK_PACKAGES=("${new_flatpak[@]}")
local new_ext=()
for p in "${GNOME_EXTENSIONS[@]}"; do
if [[ "$p" != "add-to-steam@pupper.space" && "$p" != "gamemodeshellextension@trsnaqe.com" && "$p" != "bazaar-integration@kolunmi.github.io" ]]; then
new_ext+=("$p")
fi
done
GNOME_EXTENSIONS=("${new_ext[@]}")
}
# Run every installation step. Pass "skip_kernel" to leave out CachyOS.
run_all() {
if [ "$1" = "work_mode" ]; then
enable_work_mode
fi
optimize_dnf
install_fonts
install_repos
install_software
if [ "$1" != "work_mode" ]; then
install_discord
fi
install_1password
install_PIA
install_topgrade
if [ "$1" != "skip_kernel" ] && [ "$1" != "work_mode" ]; then
if [ "$1" = "ask_kernel" ]; then
echo ""
echo "Which kernel would you like to install?"
echo "1. CachyOS Kernel"
echo "2. P03 Kernel"
echo "3. Stock Fedora"
read -p "Select a kernel [1-3]: " kernel_choice
case $kernel_choice in
1) install_cachyos ;;
2) install_p03 ;;
3) log_info "Keeping Stock Fedora kernel. Skipping custom kernel installation." ;;
*) log_warn "Invalid choice. Keeping Stock Fedora kernel." ;;
esac
else
install_cachyos
fi
fi
install_linuxtoys
install_shell_env
install_gnome_extensions
install_antigravity
}
# Show which steps failed during this run, if any
print_summary() {
log_info "----------------------------------------------------"
if [ ${#FAILED_STEPS[@]} -eq 0 ]; then
log_info "Post-install script completed successfully!"
else
log_warn "Post-install script finished with ${#FAILED_STEPS[@]} failed step(s):"
for step in "${FAILED_STEPS[@]}"; do
log_warn " - $step"
done
fi
log_info "Please restart your shell or run 'source ~/.bashrc' to see the changes."
log_info "----------------------------------------------------"
}
# -----------------------------------------------------------------------------
# Main Execution
# -----------------------------------------------------------------------------
log_info "Starting Post-install script for Fedora..."
sleep 2
# Ensure sudo permissions are available upfront
sudo -v
while true; do sudo -n true; sleep 60; kill -0 "$$" || exit; done 2>/dev/null &
while true; do
show_menu
case $choice in
1)
run_all ask_kernel
break
;;
2)
run_all work_mode
break
;;
3) optimize_dnf ;;
4) install_fonts ;;
5) install_repos ;;
6) install_software ;;
7) install_cachyos ;;
8) install_linuxtoys ;;
9) install_shell_env ;;
10) install_gnome_extensions ;;
11) install_discord ;;
12) install_1password ;;
13) install_PIA ;;
14) install_topgrade ;;
15) install_antigravity ;;
16) install_p03 ;;
0)
log_info "Exiting..."
print_summary
exit 0
;;
*)
log_error "Invalid option. Please try again."
sleep 2
;;
esac
if [ "$choice" != "1" ] && [ "$choice" != "2" ]; then
read -p "Press Enter to return to the main menu..."
fi
done
print_summary