#!/bin/bash # Post install script for openSUSE # Author: Jacob Schantli # Version: 1.0 # ----------------------------------------------------------------------------- # Global Configuration # ----------------------------------------------------------------------------- ZYPPER_PACKAGES=( "gnome-tweaks" "steam" "lutris" "btop" "fastfetch" "jstest-gtk" "distrobox" "python3-pipx" "bash-completion" "tar" "bat" "tree" "unzip" "git" "fzf" "syncthing" "mpv" "fuse" "fuse3" "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.martchus.syncthingtray" "io.github.kolunmi.Bazaar" "com.fastmail.Fastmail" ) GNOME_EXTENSIONS=( "dash-to-dock@micxgx.gmail.com" "app-grid-wizard@mirzadeh.pro" "appindicatorsupport@rgcjonas.gmail.com" "blur-my-shell@aunetx" "caffeine@patapon.info" "dynamic-music-pill@andbal" "gnome-fuzzy-app-search@gnome-shell-extensions.Czarlie.gitlab.com" "IP-Finder@linxgem33.com" "lan-ip-address@mrhuber.com" "update-extension@purejava.org" "user-theme@gnome-shell-extensions.gcampax.github.com" "gnome-wallpaper-engine@gjs.com.zip" ) # ----------------------------------------------------------------------------- # 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() { if [ $? -eq 0 ]; then log_info "$1 successful." else log_error "$1 failed." # 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_zypper() { log_info "----------------------------------------------------" log_info "Modifying /etc/zypp/zypp.conf for faster downloads." log_info "----------------------------------------------------" ZYPP_CONF="/etc/zypp/zypp.conf" if [ -f "$ZYPP_CONF" ]; then if grep -q "^# download.max_concurrent_connections" "$ZYPP_CONF" || ! grep -q "download.max_concurrent_connections = 10" "$ZYPP_CONF"; then sudo sed -i 's/^# download.max_concurrent_connections.*/download.max_concurrent_connections = 10/' "$ZYPP_CONF" log_info "Enabled max concurrent connections." fi else log_warn "$ZYPP_CONF not found!" fi sleep 1 } install_fonts() { log_info "----------------------------------------------------" log_info "Installing Microsoft Core Fonts and Meslo Nerd Font." log_info "----------------------------------------------------" log_info "Updating system and installing prerequisites..." sudo zypper refresh sudo zypper --non-interactive update check_status "System upgrade" "critical" sudo zypper install -y curl cabextract fontconfig wget fetchmsttfonts check_status "Prerequisites installation" "critical" log_info "Installing Meslo Nerd Font..." FONT_NAME="MesloLGS Nerd Font Mono" if fc-list :family | grep -iq "$FONT_NAME"; 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 -O "$TEMP_DIR/$FONT_NAME.zip" "$FONT_URL" unzip "$TEMP_DIR/$FONT_NAME.zip" -d "$TEMP_DIR" mkdir -p "$FONT_DIR/$FONT_NAME" mv "$TEMP_DIR"/*.ttf "$FONT_DIR/$FONT_NAME/" fc-cache -fv rm -rf "$TEMP_DIR" check_status "Meslo Nerd Font installation" "non-critical" fi } install_repos() { log_info "----------------------------------------------------" log_info "Adding Packman repository." log_info "----------------------------------------------------" sudo zypper addrepo -cfp 90 'https://ftp.gwdg.de/pub/linux/misc/packman/suse/openSUSE_Tumbleweed/' packman sudo zypper refresh sudo zypper --non-interactive dist-upgrade --from packman --allow-vendor-change check_status "Packman repository installation" "non-critical" } install_software() { log_info "----------------------------------------------------" log_info "Installing most used software." log_info "----------------------------------------------------" log_info "Installing Zypper packages..." sudo zypper install -y "${ZYPPER_PACKAGES[@]}" check_status "Zypper packages installation" "non-critical" # Ensure flatpak is set up if ! command -v flatpak &> /dev/null; then log_info "Flatpak not found. Installing..." sudo zypper install -y flatpak fi log_info "Adding Flathub remote..." flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo check_status "Flathub remote add" "non-critical" log_info "Installing Flatpak packages..." for app in "${FLATPAK_PACKAGES[@]}"; do log_info "Installing $app..." flatpak install flathub -y "$app" check_status "Flatpak $app" "non-critical" done log_info "----------------------------------------------------" log_info "Installing Homebrew and Gemini CLI" log_info "----------------------------------------------------" # Install Homebrew if command_exists brew; then log_info "Homebrew already installed." else log_info "Installing Homebrew..." # Using NONINTERACTIVE=1 to avoid prompts during brew install NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" # 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 check_status "Homebrew installation" "non-critical" fi # Install Gemini CLI log_info "Installing gemini-cli via Homebrew..." brew install gemini-cli check_status "gemini-cli installation" "non-critical" } 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 zypper 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 rpm --import https://downloads.1password.com/linux/keys/1password.asc sudo zypper addrepo https://downloads.1password.com/linux/rpm/stable/x86_64 1password sudo zypper install -y 1password check_status "1Password installation" "non-critical" fi } install_Windscribe() { log_info "----------------------------------------------------" log_info "Installing Windscribe" log_info "----------------------------------------------------" if rpm -q windscribe-cli > /dev/null 2>&1 || command_exists windscribe; then log_info "Windscribe already installed." else log_info "Downloading and installing Windscribe..." sudo zypper install -y https://windscribe.com/install/desktop/linux_rpm_x64 check_status "Windscribe installation" "non-critical" fi } 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..." curl -sSL https://starship.rs/install.sh | sudo sh check_status "Starship installation" "non-critical" fi # Install FZF (Fallback if not installed via Zypper) 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 "----------------------------------------------------" sudo zypper 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 zypper install -y python3-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..." log_info "NOTE: A popup may appear asking you to confirm installation for each extension." log_info "If the extension is already installed, no popup will appear." for extension in "${GNOME_EXTENSIONS[@]}"; do log_info "Processing $extension..." # Install (using the direct binary path) "$EXTENSION_TOOL" install "$extension" # Attempt to enable the extension (in case it's installed but disabled) log_info "Ensuring $extension is enabled..." gnome-extensions enable "$extension" # Prompt user to press Enter to continue read -p "Press Enter to continue (if a popup appeared, confirm it first)..." check_status "GNOME Extension $extension" "non-critical" done } # ----------------------------------------------------------------------------- # Main Menu # ----------------------------------------------------------------------------- show_menu() { clear echo "====================================================" echo " openSUSE Post-Install Script - Main Menu" echo "====================================================" echo "1. Install Everything (Recommended)" echo "2. Optimize Zypper" echo "3. Install Fonts" echo "4. Add Repositories (Packman)" echo "5. Install Software (Zypper & Flatpak)" echo "6. Install LinuxToys" echo "7. Install Shell Environment (Starship, MyBash)" echo "8. Install GNOME Extensions" echo "9. Install Discord" echo "10. Install 1Password" echo "11. Install Windscribe" echo "12. Install Topgrade" echo "0. Exit" echo "====================================================" read -p "Enter your choice [0-12]: " choice } # ----------------------------------------------------------------------------- # Main Execution # ----------------------------------------------------------------------------- log_info "Starting Post-install script for openSUSE..." 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) optimize_zypper install_fonts install_repos install_software install_discord install_1password install_Windscribe install_topgrade install_linuxtoys install_shell_env install_gnome_extensions log_info "All tasks completed successfully!" break ;; 2) optimize_zypper ;; 3) install_fonts ;; 4) install_repos ;; 5) install_software ;; 6) install_linuxtoys ;; 7) install_shell_env ;; 8) install_gnome_extensions ;; 9) install_discord ;; 10) install_1password ;; 11) install_Windscribe ;; 12) install_topgrade ;; 0) log_info "Exiting..." exit 0 ;; *) log_error "Invalid option. Please try again." sleep 2 ;; esac if [ "$choice" != "1" ]; then read -p "Press Enter to return to the main menu..." fi done log_info "----------------------------------------------------" log_info "Post-install script completed successfully!" log_info "Please restart your shell or run 'source ~/.bashrc' to see the changes." log_info "----------------------------------------------------"