#!/bin/bash # Package List Update Script # Detects the running OS and updates the package index only (no upgrades). set -euo pipefail #============================================================================== # CONFIGURATION #============================================================================== readonly NC='\033[0m' readonly RED='\033[1;31m' readonly GREEN='\033[1;32m' readonly LIGHT_GREEN='\033[1;32m' readonly LIGHT_BLUE='\033[1;34m' readonly LIGHT_GREY='\033[0;37m' readonly YELLOW='\033[1;33m' readonly SCRIPT_NAME="$(basename "$0")" #============================================================================== # UTILITY FUNCTIONS #============================================================================== log_info() { echo -e "${LIGHT_GREY}[i] $1${NC}"; } log_success() { echo -e "${LIGHT_GREEN}[✓] $1${NC}"; } log_warning() { echo -e "${YELLOW}[!] $1${NC}"; } log_error() { echo -e "${RED}[x] $1${NC}" >&2; } log_step() { echo -e "${LIGHT_BLUE}[i] $1${NC}"; } die() { log_error "$1" exit 1 } command_exists() { command -v "$1" >/dev/null 2>&1 } # Detect the running OS and its ID string. # Prints two values: the distro id (lowercase) and the family id (lowercase). detect_os() { local id="" local family="" if [[ -f /etc/os-release ]]; then # shellcheck disable=SC1091 . /etc/os-release id="${ID:-unknown}" family="${ID_LIKE:-}" elif [[ -f /etc/alpine-release ]]; then id="alpine" family="alpine" else # Fall back to package manager detection if command_exists apk; then id="alpine"; family="alpine" elif command_exists pacman; then id="arch"; family="arch" elif command_exists apt-get; then id="debian"; family="debian" elif command_exists dnf; then id="fedora"; family="rhel" elif command_exists yum; then id="centos"; family="rhel" elif command_exists zypper; then id="opensuse"; family="suse" elif command_exists xbps-install; then id="void"; family="void" elif command_exists emerge; then id="gentoo"; family="gentoo" else id="unknown"; family="unknown" fi fi echo "${id} ${family}" } #============================================================================== # OS-SPECIFIC UPDATE FUNCTIONS #============================================================================== update_alpine() { if ! command_exists apk; then log_warning "apk not found on Alpine-type system" return 0 fi log_info "Running apk update..." if apk update 2>&1; then log_success "Alpine package index updated" else log_warning "apk update failed" fi } update_arch() { if ! command_exists pacman; then log_warning "pacman not found on Arch-type system" return 0 fi log_info "Refreshing pacman database (pacman -Sy)..." # -S = sync, -y = refresh local database only (no package installation) if pacman -Sy --noconfirm 2>&1; then log_success "Arch package database refreshed" else log_warning "pacman -Sy failed" fi } update_debian() { if ! command_exists apt-get; then log_warning "apt-get not found on Debian-type system" return 0 fi log_info "Running apt-get update..." if apt-get update 2>&1; then log_success "Debian/Ubuntu package index updated" else log_warning "apt-get update failed" fi } update_rhel() { if command_exists dnf; then log_info "Running dnf makecache..." if dnf makecache 2>&1; then log_success "RHEL/Fedora metadata cache refreshed (dnf)" else log_warning "dnf makecache failed" fi elif command_exists yum; then log_info "Running yum makecache..." if yum makecache fast 2>&1; then log_success "CentOS/RHEL metadata cache refreshed (yum)" else log_warning "yum makecache failed" fi else log_warning "No DNF or YUM found on RHEL-type system" fi } update_suse() { if ! command_exists zypper; then log_warning "zypper not found on openSUSE-type system" return 0 fi log_info "Running zypper refresh..." if zypper --non-interactive refresh 2>&1; then log_success "openSUSE repositories refreshed" else log_warning "zypper refresh failed" fi } update_void() { if ! command_exists xbps-install; then log_warning "xbps-install not found on Void system" return 0 fi log_info "Running xbps-install -S (sync repository index)..." if xbps-install -S 2>&1; then log_success "Void package index synced" else log_warning "xbps-install -S failed" fi } update_gentoo() { if ! command_exists emerge; then log_warning "emerge not found on Gentoo system" return 0 fi log_info "Running emaint sync -a..." if emaint sync -a 2>&1; then log_success "Gentoo Portage tree synced" else log_warning "emaint sync failed" fi } #============================================================================== # MAIN EXECUTION #============================================================================== main() { log_step "Starting package list update (${SCRIPT_NAME})" echo # Detect the OS local distro_info distro_id family_id distro_info="$(detect_os)" distro_id="${distro_info%% *}" family_id="${distro_info##* }" log_info "Detected OS: ${distro_id}" if [[ -n "${family_id}" && "${family_id}" != "${distro_id}" ]]; then log_info "OS family: ${family_id}" fi echo # Dispatch to the correct handler based on distro family # Check distro_id first, then fall back to family_id for aliases case "${distro_id}" in alpine) update_alpine ;; arch|artix|manjaro|garuda) update_arch ;; debian|ubuntu|linuxmint|kali|raspbian|pop) update_debian ;; fedora|rhel|centos|rocky|almalinux|amazon|oracle|clear-linux-os) update_rhel ;; opensuse*|suse|sles) update_suse ;; void) update_void ;; gentoo|funtoo) update_gentoo ;; *) # Try matching on family ID as fallback case "${family_id}" in *alpine*) update_alpine ;; *arch*) update_arch ;; *debian*|*ubuntu*) update_debian ;; *rhel*|*fedora*|*centos*) update_rhel ;; *suse*|*opensuse*) update_suse ;; *void*) update_void ;; *gentoo*) update_gentoo ;; *) die "Unsupported OS: ${distro_id} (${family_id}). Cannot update package index." ;; esac ;; esac echo log_success "Package list update completed!" } main "$@"