perf: install env checks

This commit is contained in:
2025-12-23 20:53:55 +02:00
parent a286817ce3
commit 891ae505f8
30 changed files with 492 additions and 490 deletions

3
.gitignore vendored
View File

@@ -15,6 +15,3 @@ temp
**/autoload **/autoload
**/pypoetry **/pypoetry
# darwin
.DS_Store

View File

@@ -7,3 +7,9 @@ alias reload-cache='rm -rf "${XDG_CACHE_HOME:-$HOME/.cache}/dots" ~/.zcompdump*
alias zen='curl -s https://api.github.com/zen && echo' alias zen='curl -s https://api.github.com/zen && echo'
alias la='ls -la' alias la='ls -la'
alias colby='copilot --allow-all-tools --allow-all-paths --banner' alias colby='copilot --allow-all-tools --allow-all-paths --banner'
alias gs='git s'
alias gd='git d'
alias gdc='git dc'
alias gc='git c'
alias gl='git ld'

View File

@@ -19,8 +19,6 @@
[core] [core]
autocrlf = input autocrlf = input
editor = vim
pager = less -FRX
[color] [color]
ui = auto ui = auto

View File

@@ -26,52 +26,24 @@ else
fi fi
# Log functions # Log functions
log_info() { log_info() { echo -e "${BLUE}[INFO]${NC} $*"; }
echo -e "${BLUE}[INFO]${NC} $*" log_pass() { echo -e "${GREEN}[PASS]${NC} $*"; }
} log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
log_error() { echo -e "${RED}[FAIL]${NC} $*"; }
log_debug() { echo -e "${CYAN}$*${NC}"; }
log_pass() { # Export log functions
echo -e "${GREEN}[PASS]${NC} $*" export -f log_info log_pass log_warn log_error log_debug
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $*"
}
log_error() {
echo -e "${RED}[FAIL]${NC} $*"
}
log_debug() {
echo -e "${CYAN}$*${NC}"
}
# Export log functions so they're available in sourced scripts
export -f log_info
export -f log_pass
export -f log_warn
export -f log_error
export -f log_debug
printf "\n\t${CYAN} <<< ${CYAN_BOLD}dots${CYAN} >>> ${NC}\n" printf "\n\t${CYAN} <<< ${CYAN_BOLD}dots${CYAN} >>> ${NC}\n"
printf "\t${GREY}==============${NC}\n\n" printf "\t${GREY}==============${NC}\n\n"
# High-resolution time helpers # High-resolution time helpers
# now_ns prints current time in nanoseconds using GNU date if available. if date +%s%N 2>/dev/null | grep -qE '^[0-9]+$'; then
# On systems where %N isn't supported (e.g., BSD date), it falls back to now_ns() { date +%s%N; }
# seconds precision multiplied to nanoseconds. This avoids external deps like bc. else
now_ns() { now_ns() { echo $(( $(date +%s) * 1000000000 )); }
local ns fi
ns=$(date +%s%N 2>/dev/null || true)
if [[ "$ns" =~ ^[0-9]+$ ]]; then
echo "$ns"
else
# Fallback: seconds precision
local s
s=$(date +%s)
echo $(( s * 1000000000 ))
fi
}
# Prevent running as root # Prevent running as root
if [[ $EUID -eq 0 && -z "$SKIP_SUDO_CHECK" ]]; then if [[ $EUID -eq 0 && -z "$SKIP_SUDO_CHECK" ]]; then
@@ -85,6 +57,27 @@ if [[ -z "$SKIP_SUDO_CHECK" ]]; then
sudo -v sudo -v
fi fi
# Set up environment
export DOTS_OS=""
export DOTS_PKG=""
export DOTS_ENV=""
if [[ -n "${CODESPACES:-}" ]]; then
DOTS_ENV="codespaces"
fi
case "$OSTYPE" in
darwin*) DOTS_OS="macos"; DOTS_PKG="brew" ;;
linux*)
DOTS_OS="linux"
if command -v apt-get &>/dev/null; then
DOTS_PKG="apt"
elif command -v pacman &>/dev/null; then
DOTS_PKG="pacman"
elif command -v dnf &>/dev/null; then
DOTS_PKG="dnf"
fi
;;
esac
# Set up directory variables # Set up directory variables
if [ -L "$0" ]; then if [ -L "$0" ]; then
dir=$(dirname $(readlink -f "$0")) dir=$(dirname $(readlink -f "$0"))
@@ -128,7 +121,8 @@ run() {
echo -e "Running all install targets" echo -e "Running all install targets"
fi fi
for script in $install_dir/*.sh; do scripts=("$install_dir"/*.sh)
for script in "${scripts[@]}"; do
if [[ -n "$targets" ]]; then if [[ -n "$targets" ]]; then
script_name=$(basename "$script" .sh) script_name=$(basename "$script" .sh)
script_name=${script_name#*-} script_name=${script_name#*-}

View File

@@ -5,14 +5,16 @@
# Print operating system information and hint which installer path will run. # Print operating system information and hint which installer path will run.
# #
if [[ "$OSTYPE" == "darwin"* ]]; then log_info "Environment: DOTS_OS=$DOTS_OS, DOTS_PKG=$DOTS_PKG, DOTS_ENV=$DOTS_ENV"
if [[ "$DOTS_OS" == "macos" ]]; then
# macOS info # macOS info
sw_vers sw_vers
log_info "Detected macOS (OSTYPE=$OSTYPE)" log_info "Detected macOS (OSTYPE=$OSTYPE)"
log_info "Package manager: Homebrew (brew)" log_info "Package manager: Homebrew (brew)"
log_info "Code path: macOS-only brew scripts will run; Linux package scripts are skipped." log_info "Code path: macOS-only brew scripts will run; Linux package scripts are skipped."
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then elif [[ "$DOTS_OS" == "linux" ]]; then
# Linux info # Linux info
if [[ -r /etc/os-release ]]; then if [[ -r /etc/os-release ]]; then
cat /etc/os-release cat /etc/os-release
@@ -21,17 +23,16 @@ elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
fi fi
log_info "Detected Linux (OSTYPE=$OSTYPE, ID=${ID:-unknown}, ID_LIKE=${ID_LIKE:-n/a}, NAME=${NAME:-n/a}, VERSION_ID=${VERSION_ID:-n/a})" log_info "Detected Linux (OSTYPE=$OSTYPE, ID=${ID:-unknown}, ID_LIKE=${ID_LIKE:-n/a}, NAME=${NAME:-n/a}, VERSION_ID=${VERSION_ID:-n/a})"
log_info "Package manager detected: ${DOTS_PKG:-none}"
if command -v apt-get >/dev/null 2>&1; then if [[ -z "$DOTS_PKG" ]]; then
log_info "Package manager detected: apt-get" log_warn "No known package manager (apt-get/pacman/dnf) found on Linux."
export DOTS_PKG_MGR=apt
elif command -v pacman >/dev/null 2>&1; then
log_info "Package manager detected: pacman"
export DOTS_PKG_MGR=pacman
else
log_warn "No known package manager (apt-get/pacman) found on Linux."
fi fi
else else
log_error "Unknown OS: $OSTYPE" log_error "Unknown OS: $OSTYPE"
fi fi
if [[ "$DOTS_ENV" == "codespaces" ]]; then
log_info "Running in GitHub Codespaces"
fi

View File

@@ -5,29 +5,24 @@
# Print SSH key. # Print SSH key.
# #
# skip if CODESPACES is set # Skip in Codespaces
if [ -n "$CODESPACES" ]; then [[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; }
log_warn "Running in a GitHub Codespace"
export SKIP_SSH_CONFIG=1 # Skip if explicitly disabled
[[ -n "$SKIP_SSH_CONFIG" ]] && { log_warn "Skipping SSH configuration"; return 0; }
ssh_method="ed25519"
ssh_target="${HOME}/.ssh"
ssh_key="${ssh_target}/id_${ssh_method}"
ssh_pub="${ssh_key}.pub"
if [ ! -f "$ssh_key" ]; then
ssh-keygen \
-t "$ssh_method" \
-f "$ssh_key" \
-C "$(whoami)@$(hostname)-$(date -I)"
fi fi
# skip if SKIP_SSH_CONFIG is set cat "$ssh_pub"
if [ -z "$SKIP_SSH_CONFIG" ]; then
ssh_method="ed25519"
ssh_target="${HOME}/.ssh" unset ssh_method ssh_target ssh_key ssh_pub
ssh_key="${ssh_target}/id_${ssh_method}"
ssh_pub="${ssh_key}.pub"
if [ ! -f "$ssh_key" ]; then
ssh-keygen \
-t "$ssh_method" \
-f "$ssh_key" \
-C "$(whoami)@$(hostname)-$(date -I)"
fi
cat "$ssh_pub"
unset ssh_method ssh_target ssh_key ssh_pub
else
log_warn "Skipping SSH configuration"
fi

View File

@@ -5,24 +5,23 @@
# (macOS only) Install homebrew. # (macOS only) Install homebrew.
# #
if [[ "$OSTYPE" == "darwin"* ]]; then # macOS only
if [ -d "/opt/homebrew/bin" ]; then [[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; }
export PATH="/opt/homebrew/bin:$PATH"
fi if [ -d "/opt/homebrew/bin" ]; then
export NONINTERACTIVE=1 export PATH="/opt/homebrew/bin:$PATH"
export HOMEBREW_NO_ANALYTICS=1
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
export HOMEBREW_NO_ENV_HINTS=1
export HOMEBREW_NO_AUTO_UPDATE=1
export HOMEBREW_NO_INSTALL_CLEANUP=1
if ! command -v brew &> /dev/null; then
echo "Installing Homebrew..."
bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
eval "$(/opt/homebrew/bin/brew shellenv)"
else
echo "Homebrew is already installed."
fi
brew --version
else
log_warn "Skipping: Not macOS"
fi fi
export NONINTERACTIVE=1
export HOMEBREW_NO_ANALYTICS=1
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
export HOMEBREW_NO_ENV_HINTS=1
export HOMEBREW_NO_AUTO_UPDATE=1
export HOMEBREW_NO_INSTALL_CLEANUP=1
if ! command -v brew &> /dev/null; then
echo "Installing Homebrew..."
bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
eval "$(/opt/homebrew/bin/brew shellenv)"
else
echo "Homebrew is already installed."
fi
brew --version

View File

@@ -5,21 +5,20 @@
# (distros with apt only) Install core apt packages. # (distros with apt only) Install core apt packages.
# #
if command -v apt-get &> /dev/null; then # apt only
apt_packages=( [[ "$DOTS_PKG" != "apt" ]] && { log_warn "Skipping: Not using apt"; return 0; }
ca-certificates
curl
gnupg
gnupg2
wget
)
sudo apt-get update -qq apt_packages=(
sudo apt-get install -qq "${apt_packages[@]}" ca-certificates
curl
gnupg
gnupg2
wget
)
unset apt_packages sudo apt-get update -qq
sudo apt-get install -qq "${apt_packages[@]}"
apt --version unset apt_packages
else
log_warn "Skipping: apt-get not found" apt --version
fi

View File

@@ -5,21 +5,20 @@
# (distros with pacman only) Install core pacman packages. # (distros with pacman only) Install core pacman packages.
# #
if command -v pacman &> /dev/null; then # pacman only
pacman_packages=( [[ "$DOTS_PKG" != "pacman" ]] && { log_warn "Skipping: Not using pacman"; return 0; }
ca-certificates
curl
gnupg
wget
base-devel
)
sudo pacman -Sy --noconfirm pacman_packages=(
sudo pacman -S --noconfirm --needed "${pacman_packages[@]}" ca-certificates
curl
gnupg
wget
base-devel
)
unset pacman_packages sudo pacman -Sy --noconfirm
sudo pacman -S --noconfirm --needed "${pacman_packages[@]}"
pacman --version unset pacman_packages
else
log_warn "Skipping: pacman not found" pacman --version
fi

View File

@@ -6,17 +6,21 @@
# #
if ! command -v git &> /dev/null; then if ! command -v git &> /dev/null; then
if [[ "$OSTYPE" == "linux-gnu"* ]]; then case "$DOTS_PKG" in
if command -v apt-get >/dev/null 2>&1; then apt)
sudo apt-get install -qq git sudo apt-get install -qq git
elif command -v pacman >/dev/null 2>&1; then ;;
pacman)
sudo pacman -S --noconfirm git sudo pacman -S --noconfirm git
else ;;
brew)
brew install git
;;
*)
log_warn "Skipping git install: no supported package manager found" log_warn "Skipping git install: no supported package manager found"
fi return 0
elif [[ "$OSTYPE" == "darwin"* ]]; then ;;
brew install git esac
fi
fi fi
git --version git --version

View File

@@ -7,17 +7,21 @@
# install zsh # install zsh
if ! command -v zsh &> /dev/null; then if ! command -v zsh &> /dev/null; then
if [[ "$OSTYPE" == "linux-gnu"* ]]; then case "$DOTS_PKG" in
if command -v apt-get >/dev/null 2>&1; then apt)
sudo apt-get install -qq zsh sudo apt-get install -qq zsh
elif command -v pacman >/dev/null 2>&1; then ;;
pacman)
sudo pacman -S --noconfirm zsh sudo pacman -S --noconfirm zsh
else ;;
brew)
brew install zsh
;;
*)
log_warn "Skipping zsh install: no supported package manager found" log_warn "Skipping zsh install: no supported package manager found"
fi return 0
elif [[ "$OSTYPE" == "darwin"* ]]; then ;;
brew install zsh esac
fi
fi fi
zsh --version zsh --version

View File

@@ -6,17 +6,21 @@
# #
if ! command -v stow &> /dev/null; then if ! command -v stow &> /dev/null; then
if [[ "$OSTYPE" == "linux-gnu"* ]]; then case "$DOTS_PKG" in
if command -v apt-get >/dev/null 2>&1; then apt)
sudo apt-get install -qq stow sudo apt-get install -qq stow
elif command -v pacman >/dev/null 2>&1; then ;;
pacman)
sudo pacman -S --noconfirm stow sudo pacman -S --noconfirm stow
else ;;
brew)
brew install stow
;;
*)
log_warn "Skipping stow install: no supported package manager found" log_warn "Skipping stow install: no supported package manager found"
fi return 0
elif [[ "$OSTYPE" == "darwin"* ]]; then ;;
brew install stow esac
fi
fi fi
stow --version stow --version

View File

@@ -10,8 +10,8 @@ if ! echo "$PATH" | grep -q "$PYENV_ROOT"; then
export PATH="$PYENV_ROOT/bin:$PATH" export PATH="$PYENV_ROOT/bin:$PATH"
fi fi
if ! command -v pyenv &>/dev/null; then if ! command -v pyenv &>/dev/null; then
if [[ "$OSTYPE" == "linux-gnu"* ]]; then case "$DOTS_PKG" in
if command -v apt-get >/dev/null 2>&1; then apt)
# https://github.com/pyenv/pyenv/wiki#suggested-build-environment # https://github.com/pyenv/pyenv/wiki#suggested-build-environment
sudo apt-get install -qq build-essential libssl-dev zlib1g-dev \ sudo apt-get install -qq build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev curl \ libbz2-dev libreadline-dev libsqlite3-dev curl \
@@ -19,7 +19,8 @@ if ! command -v pyenv &>/dev/null; then
# see https://github.com/pyenv/pyenv-installer # see https://github.com/pyenv/pyenv-installer
bash -c "$(curl -fsSL https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer)" bash -c "$(curl -fsSL https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer)"
elif command -v pacman >/dev/null 2>&1; then ;;
pacman)
# Prefer native packages if available; otherwise install build deps then use installer # Prefer native packages if available; otherwise install build deps then use installer
if ! sudo pacman -Qi pyenv >/dev/null 2>&1; then if ! sudo pacman -Qi pyenv >/dev/null 2>&1; then
sudo pacman -S --noconfirm --needed base-devel openssl zlib-ng-compat bzip2 readline sqlite xz tk libffi curl sudo pacman -S --noconfirm --needed base-devel openssl zlib-ng-compat bzip2 readline sqlite xz tk libffi curl
@@ -27,16 +28,18 @@ if ! command -v pyenv &>/dev/null; then
else else
sudo pacman -S --noconfirm --needed pyenv pyenv-virtualenv sudo pacman -S --noconfirm --needed pyenv pyenv-virtualenv
fi fi
else ;;
brew)
brew install pyenv
brew install pyenv-virtualenv
;;
*)
log_warn "Skipping pyenv install: no supported package manager found" log_warn "Skipping pyenv install: no supported package manager found"
fi ;;
elif [[ "$OSTYPE" == "darwin"* ]]; then esac
brew install pyenv
brew install pyenv-virtualenv
fi
fi fi
if [[ "$OSTYPE" == "linux-gnu"* ]]; then if [[ "$DOTS_OS" == "linux" ]]; then
virtualenv_path="$(pyenv root)/plugins/pyenv-virtualenv" virtualenv_path="$(pyenv root)/plugins/pyenv-virtualenv"
if [ ! -d "$virtualenv_path" ]; then if [ ! -d "$virtualenv_path" ]; then
git clone \ git clone \

View File

@@ -41,17 +41,20 @@ mkdir -p ~/.local/bin
unset local_bin_path unset local_bin_path
if ! command -v pipx &>/dev/null; then if ! command -v pipx &>/dev/null; then
if [[ "$OSTYPE" == "linux-gnu"* ]]; then case "$DOTS_PKG" in
if command -v apt-get >/dev/null 2>&1; then apt)
sudo apt-get install -qq pipx sudo apt-get install -qq pipx
elif command -v pacman >/dev/null 2>&1; then ;;
pacman)
sudo pacman -S --noconfirm python-pipx sudo pacman -S --noconfirm python-pipx
else ;;
log_warn "Skipping pipx install: no apt-get or pacman found" brew)
fi brew install pipx
elif [[ "$OSTYPE" == "darwin"* ]]; then ;;
brew install pipx *)
fi log_warn "Skipping pipx install: no supported package manager found"
;;
esac
fi fi
echo "pipx $(pipx --version)" echo "pipx $(pipx --version)"

View File

@@ -8,60 +8,49 @@
# skip if in WSL # skip if in WSL
if [[ -n "$WSL_DISTRO_NAME" ]]; then if [[ -n "$WSL_DISTRO_NAME" ]]; then
log_warn "Running in WSL" log_warn "Skipping: Running in WSL"
export SKIP_DOCKER_CONFIG=1 return 0
fi fi
# skip if in CODESPACES # skip if in Codespaces
if [[ -n "$CODESPACES" ]]; then [[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; }
log_warn "Running in GitHub Codespaces"
export SKIP_DOCKER_CONFIG=1 # skip on macOS
[[ "$DOTS_OS" == "macos" ]] && { log_warn "Skipping: macOS"; return 0; }
if ! command -v docker &> /dev/null; then
case "$DOTS_PKG" in
apt)
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
;;
pacman)
sudo pacman -S --noconfirm --needed docker docker-buildx docker-compose
;;
*)
log_warn "Skipping Docker install: no supported package manager found"
;;
esac
fi fi
# skip on mac readonly docker_group="docker"
if [[ "$OSTYPE" == "darwin"* ]]; then if ! grep -q "$docker_group" /etc/group; then
log_warn "Running on macOS" log_info "Adding docker group"
export SKIP_DOCKER_CONFIG=1 sudo groupadd "$docker_group"
fi fi
if [[ -z "$SKIP_DOCKER_CONFIG" ]]; then if ! groups "$USER" | grep -q "\b$docker_group\b"; then
if [[ "$OSTYPE" == "linux-gnu"* ]]; then log_info "Adding user to docker group"
if ! command -v docker &> /dev/null; then sudo usermod -aG docker "$USER"
if command -v apt-get >/dev/null 2>&1; then
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
elif command -v pacman >/dev/null 2>&1; then
sudo pacman -S --noconfirm --needed docker docker-buildx docker-compose
else
log_warn "Skipping Docker install: no supported package manager found"
fi
fi
readonly docker_group="docker"
if ! grep -q "$docker_group" /etc/group; then
log_info "Adding docker group"
sudo groupadd "$docker_group"
fi
if ! groups "$USER" | grep -q "\b$docker_group\b"; then
log_info "Adding user to docker group"
sudo usermod -aG docker "$USER"
fi
elif [[ "$OSTYPE" == "darwin"* ]]; then
if ! command -v docker &> /dev/null; then
brew install --cask docker
fi
fi
docker --version
else
log_warn "Skipping Docker configuration"
fi fi
docker --version

View File

@@ -6,18 +6,21 @@
# #
if ! command -v az &>/dev/null; then if ! command -v az &>/dev/null; then
if [[ "$OSTYPE" == "linux-gnu"* ]]; then case "$DOTS_PKG" in
if command -v apt-get >/dev/null 2>&1; then apt)
# https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-linux?pivots=apt # https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-linux?pivots=apt
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
elif command -v pacman >/dev/null 2>&1; then ;;
pacman)
sudo pacman -S --noconfirm azure-cli &>/dev/null sudo pacman -S --noconfirm azure-cli &>/dev/null
else ;;
brew)
brew install azure-cli
;;
*)
log_warn "Skipping Azure CLI install: no supported package manager found" log_warn "Skipping Azure CLI install: no supported package manager found"
fi ;;
elif [[ "$OSTYPE" == "darwin"* ]]; then esac
brew install azure-cli
fi
fi fi
az --version az --version

View File

@@ -6,22 +6,25 @@
# #
if ! command -v gh &>/dev/null; then if ! command -v gh &>/dev/null; then
if [[ "$OSTYPE" == "linux-gnu"* ]]; then case "$DOTS_PKG" in
if command -v apt-get >/dev/null 2>&1; then apt)
# https://github.com/cli/cli/blob/trunk/docs/install_linux.md#debian-ubuntu-linux-raspberry-pi-os-apt # https://github.com/cli/cli/blob/trunk/docs/install_linux.md#debian-ubuntu-linux-raspberry-pi-os-apt
sudo mkdir -p -m 755 /etc/apt/keyrings && wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg >/dev/null && sudo mkdir -p -m 755 /etc/apt/keyrings && wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg >/dev/null &&
sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg && sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg &&
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list >/dev/null && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list >/dev/null &&
sudo apt-get update -qq && sudo apt-get update -qq &&
sudo apt-get install -qq gh sudo apt-get install -qq gh
elif command -v pacman >/dev/null 2>&1; then ;;
pacman)
sudo pacman -S --noconfirm github-cli sudo pacman -S --noconfirm github-cli
else ;;
brew)
brew install gh
;;
*)
log_warn "Skipping GitHub CLI install: no supported package manager found" log_warn "Skipping GitHub CLI install: no supported package manager found"
fi ;;
elif [[ "$OSTYPE" == "darwin"* ]]; then esac
brew install gh
fi
fi fi
gh --version gh --version

View File

@@ -6,8 +6,8 @@
# #
if ! command -v terraform &>/dev/null; then if ! command -v terraform &>/dev/null; then
if [[ "$OSTYPE" == "linux-gnu"* ]]; then case "$DOTS_PKG" in
if command -v apt-get >/dev/null 2>&1; then apt)
terraform_keyring_path="/usr/share/keyrings/hashicorp-archive-keyring.gpg" terraform_keyring_path="/usr/share/keyrings/hashicorp-archive-keyring.gpg"
if [[ ! -f "$terraform_keyring_path" ]]; then if [[ ! -f "$terraform_keyring_path" ]]; then
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o "$terraform_keyring_path" curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o "$terraform_keyring_path"
@@ -17,15 +17,18 @@ if ! command -v terraform &>/dev/null; then
sudo tee /etc/apt/sources.list.d/hashicorp.list sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt-get update -qq && sudo apt-get update -qq &&
sudo apt-get install -qq terraform sudo apt-get install -qq terraform
elif command -v pacman >/dev/null 2>&1; then ;;
pacman)
sudo pacman -S --noconfirm terraform sudo pacman -S --noconfirm terraform
else ;;
brew)
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
;;
*)
log_warn "Skipping Terraform install: no supported package manager found" log_warn "Skipping Terraform install: no supported package manager found"
fi ;;
elif [[ "$OSTYPE" == "darwin"* ]]; then esac
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
fi
fi fi
terraform --version terraform --version

View File

@@ -5,11 +5,10 @@
# (macOS only) Install iTerm2. # (macOS only) Install iTerm2.
# #
if [[ "$OSTYPE" == "darwin"* ]]; then # macOS only
if ! brew list --cask iterm2 &>/dev/null; then [[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; }
brew install --cask iterm2
fi if ! brew list --cask iterm2 &>/dev/null; then
log_pass "iTerm2 installed successfully!" brew install --cask iterm2
else
log_warn "Skipping: Not macOS"
fi fi
log_pass "iTerm2 installed successfully!"

View File

@@ -5,20 +5,19 @@
# (macOS only) Install nerdfonts. # (macOS only) Install nerdfonts.
# #
if [[ "$OSTYPE" == "darwin"* ]]; then # macOS only
fonts_list=( [[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; }
font-fira-mono-nerd-font
font-fira-code-nerd-font
)
if ! brew list "${fonts_list[@]}" &> /dev/null; then fonts_list=(
brew tap homebrew/cask-fonts font-fira-mono-nerd-font
for font in "${fonts_list[@]}"; do font-fira-code-nerd-font
brew install --cask "$font" )
done
fi
unset fonts_list if ! brew list "${fonts_list[@]}" &> /dev/null; then
else brew tap homebrew/cask-fonts
log_warn "Skipping: Not macOS" for font in "${fonts_list[@]}"; do
brew install --cask "$font"
done
fi fi
unset fonts_list

View File

@@ -6,8 +6,8 @@
# #
if ! command -v redis-cli &>/dev/null; then if ! command -v redis-cli &>/dev/null; then
if [[ "$OSTYPE" == "linux-gnu"* ]]; then case "$DOTS_PKG" in
if command -v apt-get >/dev/null 2>&1; then apt)
redis_keyring_path="/usr/share/keyrings/redis-archive-keyring.gpg" redis_keyring_path="/usr/share/keyrings/redis-archive-keyring.gpg"
if [[ ! -f "$redis_keyring_path" ]]; then if [[ ! -f "$redis_keyring_path" ]]; then
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o "$redis_keyring_path" curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o "$redis_keyring_path"
@@ -15,14 +15,17 @@ if ! command -v redis-cli &>/dev/null; then
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" \ echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" \
| sudo tee /etc/apt/sources.list.d/redis.list > /dev/null | sudo tee /etc/apt/sources.list.d/redis.list > /dev/null
sudo apt-get install -qq redis sudo apt-get install -qq redis
elif command -v pacman >/dev/null 2>&1; then ;;
pacman)
sudo pacman -S --noconfirm redis sudo pacman -S --noconfirm redis
else ;;
brew)
brew install redis
;;
*)
log_warn "Skipping Redis install: no supported package manager found" log_warn "Skipping Redis install: no supported package manager found"
fi ;;
elif [[ "$OSTYPE" == "darwin"* ]]; then esac
brew install redis
fi
fi fi
redis-cli --version redis-cli --version

View File

@@ -5,12 +5,11 @@
# (macOS only) Install Colour Contrast Analyser (CCA). # (macOS only) Install Colour Contrast Analyser (CCA).
# #
if [[ "$OSTYPE" == "darwin"* ]]; then # macOS only
if ! brew list --cask colour-contrast-analyser &> /dev/null; then [[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; }
brew install --cask colour-contrast-analyser
else if ! brew list --cask colour-contrast-analyser &> /dev/null; then
echo "Colour Contrast Analyser (CCA) is already installed." brew install --cask colour-contrast-analyser
fi
else else
log_warn "Skipping: Not macOS" echo "Colour Contrast Analyser (CCA) is already installed."
fi fi

View File

@@ -5,12 +5,11 @@
# (macOS only) Install Rectangle. # (macOS only) Install Rectangle.
# #
if [[ "$OSTYPE" == "darwin"* ]]; then # macOS only
if ! brew list --cask rectangle &> /dev/null; then [[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; }
brew install --cask rectangle
else if ! brew list --cask rectangle &> /dev/null; then
echo "Rectangle is already installed." brew install --cask rectangle
fi
else else
log_warn "Skipping: Not macOS" echo "Rectangle is already installed."
fi fi

View File

@@ -5,12 +5,11 @@
# (macOS only) Install MeetingBar. # (macOS only) Install MeetingBar.
# #
if [[ "$OSTYPE" == "darwin"* ]]; then # macOS only
if ! brew list --cask meetingbar &> /dev/null; then [[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; }
brew install --cask meetingbar
else if ! brew list --cask meetingbar &> /dev/null; then
echo "MeetingBar is already installed." brew install --cask meetingbar
fi
else else
log_warn "Skipping: Not macOS" echo "MeetingBar is already installed."
fi fi

View File

@@ -5,12 +5,11 @@
# (macOS only) Install BetterDisplay. # (macOS only) Install BetterDisplay.
# #
if [[ "$OSTYPE" == "darwin"* ]]; then # macOS only
if ! brew list --cask betterdisplay &> /dev/null; then [[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; }
brew install --cask betterdisplay
else if ! brew list --cask betterdisplay &> /dev/null; then
echo "BetterDisplay is already installed." brew install --cask betterdisplay
fi
else else
log_warn "Skipping: Not macOS" echo "BetterDisplay is already installed."
fi fi

View File

@@ -5,12 +5,11 @@
# (macOS only) Install dockutil. # (macOS only) Install dockutil.
# #
if [[ "$OSTYPE" == "darwin"* ]]; then # macOS only
if ! brew list dockutil &> /dev/null; then [[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; }
brew install dockutil
else if ! brew list dockutil &> /dev/null; then
echo "dockutil is already installed." brew install dockutil
fi
else else
log_warn "Skipping: Not macOS" echo "dockutil is already installed."
fi fi

View File

@@ -6,17 +6,20 @@
# #
if ! command -v neofetch &>/dev/null; then if ! command -v neofetch &>/dev/null; then
if [[ "$OSTYPE" == "linux-gnu"* ]]; then case "$DOTS_PKG" in
if command -v apt-get >/dev/null 2>&1; then apt)
sudo apt-get install -qq neofetch &>/dev/null sudo apt-get install -qq neofetch &>/dev/null
elif command -v pacman >/dev/null 2>&1; then ;;
pacman)
yay -S --noconfirm neofetch &>/dev/null yay -S --noconfirm neofetch &>/dev/null
else ;;
brew)
brew install neofetch
;;
*)
log_warn "Skipping neofetch install: no supported package manager found" log_warn "Skipping neofetch install: no supported package manager found"
fi ;;
elif [[ "$OSTYPE" == "darwin"* ]]; then esac
brew install neofetch
fi
fi fi
echo "$(neofetch --version)" echo "$(neofetch --version)"

View File

@@ -5,27 +5,23 @@
# Install cmatrix. # Install cmatrix.
# #
# skip if in CODESPACES # skip if in Codespaces
if [[ -n "$CODESPACES" ]]; then [[ "$DOTS_ENV" == "codespaces" ]] && { log_pass "Skipping in Codespaces"; return 0; }
log_warn "Running in GitHub Codespaces"
export SKIP_CMATRIX_CONFIG=1
fi
if [[ -z "$SKIP_CMATRIX_CONFIG" ]]; then if ! command -v cmatrix &> /dev/null; then
if ! command -v cmatrix &> /dev/null; then case "$DOTS_PKG" in
if [[ "$OSTYPE" == "linux-gnu"* ]]; then apt)
if command -v apt-get >/dev/null 2>&1; then sudo apt-get install -qq cmatrix &>/dev/null
sudo apt-get install -qq cmatrix &>/dev/null ;;
elif command -v pacman >/dev/null 2>&1; then pacman)
sudo pacman -S --noconfirm cmatrix &>/dev/null sudo pacman -S --noconfirm cmatrix &>/dev/null
else ;;
log_warn "Skipping cmatrix install: no supported package manager found" brew)
fi
elif [[ "$OSTYPE" == "darwin"* ]]; then
brew install cmatrix brew install cmatrix
fi ;;
fi *)
log_pass "cmatrix installed successfully!" log_warn "Skipping cmatrix install: no supported package manager found"
else ;;
log_warn "Skipping cmatrix configuration" esac
fi fi
log_pass "cmatrix installed successfully!"

View File

@@ -5,185 +5,184 @@
# (macOS only) Configure defaults # (macOS only) Configure defaults
# #
if [[ "$OSTYPE" == "darwin"* ]]; then # macOS only
# Keyboard [[ "$DOTS_OS" != "macos" ]] && { log_warn "Skipping: Not macOS"; return 0; }
# --------
# off -- Keyboard: Capitalize words automatically
defaults write -globalDomain NSAutomaticCapitalizationEnabled -bool false
# off -- Keyboard: Add period with double-space # Keyboard
defaults write -globalDomain NSAutomaticPeriodSubstitutionEnabled -bool false # --------
# off -- Keyboard: Capitalize words automatically
defaults write -globalDomain NSAutomaticCapitalizationEnabled -bool false
# off -- Keyboard: Quote substitution # off -- Keyboard: Add period with double-space
defaults write -globalDomain NSAutomaticQuoteSubstitutionEnabled -bool false defaults write -globalDomain NSAutomaticPeriodSubstitutionEnabled -bool false
# off -- Keyboard: Dash substitution # off -- Keyboard: Quote substitution
defaults write NSGlobalDomain NSAutomaticDashSubstitutionEnabled -bool false defaults write -globalDomain NSAutomaticQuoteSubstitutionEnabled -bool false
# off -- Keyboard: Auto-correct # off -- Keyboard: Dash substitution
defaults write NSGlobalDomain NSAutomaticSpellingCorrectionEnabled -bool false defaults write NSGlobalDomain NSAutomaticDashSubstitutionEnabled -bool false
defaults write NSGlobalDomain WebAutomaticSpellingCorrectionEnabled -bool false
# Appearance # off -- Keyboard: Auto-correct
# ---------- defaults write NSGlobalDomain NSAutomaticSpellingCorrectionEnabled -bool false
# Graphite -- Appearance (prevent top-left window colours) defaults write NSGlobalDomain WebAutomaticSpellingCorrectionEnabled -bool false
defaults write -globalDomain AppleAquaColorVariant -int 6
# on -- Appearance: Dark mode # Appearance
defaults write -globalDomain AppleInterfaceStyle -string "Dark" # ----------
# Graphite -- Appearance (prevent top-left window colours)
defaults write -globalDomain AppleAquaColorVariant -int 6
# #2CB494 -- Highlight color # on -- Appearance: Dark mode
defaults write -globalDomain AppleHighlightColor -string "0.172549 0.705882 0.580392" defaults write -globalDomain AppleInterfaceStyle -string "Dark"
killall SystemUIServer 2>/dev/null || true # #2CB494 -- Highlight color
defaults write -globalDomain AppleHighlightColor -string "0.172549 0.705882 0.580392"
# Control Center killall SystemUIServer 2>/dev/null || true
# --------------
# off -- Control Center: Show Bluetooth icon in menu bar
defaults write \
~/Library/Preferences/ByHost/com.apple.controlcenter.plist \
Bluetooth \
-int 24
# off -- Control Center: Show Wi-Fi icon in menu bar # Control Center
defaults write \ # --------------
~/Library/Preferences/ByHost/com.apple.controlcenter.plist \ # off -- Control Center: Show Bluetooth icon in menu bar
WiFi \ defaults write \
-int 24 ~/Library/Preferences/ByHost/com.apple.controlcenter.plist \
Bluetooth \
-int 24
# off -- Control Center: Show Now Playing icon in menu bar # off -- Control Center: Show Wi-Fi icon in menu bar
defaults write \ defaults write \
~/Library/Preferences/ByHost/com.apple.controlcenter.plist \ ~/Library/Preferences/ByHost/com.apple.controlcenter.plist \
NowPlaying \ WiFi \
-int 24 -int 24
# off -- Control Center: Show Battery icon in menu bar # off -- Control Center: Show Now Playing icon in menu bar
defaults write \ defaults write \
~/Library/Preferences/ByHost/com.apple.controlcenter.plist \ ~/Library/Preferences/ByHost/com.apple.controlcenter.plist \
Battery \ NowPlaying \
-int 24 -int 24
killall ControlCenter 2>/dev/null || true # off -- Control Center: Show Battery icon in menu bar
defaults write \
~/Library/Preferences/ByHost/com.apple.controlcenter.plist \
Battery \
-int 24
# Finder killall ControlCenter 2>/dev/null || true
# ------
# on -- Finder: Add quit option
defaults write com.apple.finder QuitMenuItem -bool true
# on -- Finder: Show hidden files # Finder
defaults write com.apple.finder AppleShowAllFiles -bool true # ------
# on -- Finder: Add quit option
defaults write com.apple.finder QuitMenuItem -bool true
# on -- Finder: Show all filename extensions # on -- Finder: Show hidden files
defaults write NSGlobalDomain AppleShowAllExtensions -bool true defaults write com.apple.finder AppleShowAllFiles -bool true
# off -- Finder: Show warning before changing an extension # on -- Finder: Show all filename extensions
defaults write com.apple.finder FXEnableExtensionChangeWarning -bool false defaults write NSGlobalDomain AppleShowAllExtensions -bool true
# on -- Finder: Show path bar # off -- Finder: Show warning before changing an extension
defaults write com.apple.finder ShowPathbar -bool true defaults write com.apple.finder FXEnableExtensionChangeWarning -bool false
# on -- Finder: Show status bar # on -- Finder: Show path bar
defaults write com.apple.finder ShowStatusBar -bool true defaults write com.apple.finder ShowPathbar -bool true
# on -- Finder: Keep folders on top # on -- Finder: Show status bar
defaults write com.apple.finder _FXSortFoldersFirst -bool true defaults write com.apple.finder ShowStatusBar -bool true
# off -- Finder: Use macOS Crash Reporter # on -- Finder: Keep folders on top
defaults write com.apple.CrashReporter DialogType -string "none" defaults write com.apple.finder _FXSortFoldersFirst -bool true
# off -- Finder: Enable dashboard widgets # off -- Finder: Use macOS Crash Reporter
defaults write com.apple.dashboard mcx-disabled -bool true defaults write com.apple.CrashReporter DialogType -string "none"
# on -- Finder: Show hard drives on desktop # off -- Finder: Enable dashboard widgets
defaults write com.apple.finder ShowHardDrivesOnDesktop -bool true defaults write com.apple.dashboard mcx-disabled -bool true
# on -- Finder: Show external hard drives on desktop # on -- Finder: Show hard drives on desktop
defaults write com.apple.finder ShowExternalHardDrivesOnDesktop -bool true defaults write com.apple.finder ShowHardDrivesOnDesktop -bool true
# on -- Finder: Show removable media on desktop # on -- Finder: Show external hard drives on desktop
defaults write com.apple.finder ShowRemovableMediaOnDesktop -bool true defaults write com.apple.finder ShowExternalHardDrivesOnDesktop -bool true
# on -- Finder: Show mounted servers on desktop # on -- Finder: Show removable media on desktop
defaults write com.apple.finder ShowMountedServersOnDesktop -bool true defaults write com.apple.finder ShowRemovableMediaOnDesktop -bool true
# off -- Finder: Show recent tags # on -- Finder: Show mounted servers on desktop
defaults write com.apple.finder ShowRecentTags -bool false defaults write com.apple.finder ShowMountedServersOnDesktop -bool true
# off -- Finder: Create .DS_Store files # off -- Finder: Show recent tags
defaults write com.apple.desktopservices DSDontWriteUSBStores -bool true defaults write com.apple.finder ShowRecentTags -bool false
defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true
# home -- Finder: New Finder windows show # off -- Finder: Create .DS_Store files
defaults write com.apple.finder NewWindowTargetPath -string "file://${HOME}/" defaults write com.apple.desktopservices DSDontWriteUSBStores -bool true
defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true
# list -- Finder: Preferred view style # home -- Finder: New Finder windows show
defaults write com.apple.finder FXPreferredViewStyle -string "nlsv" defaults write com.apple.finder NewWindowTargetPath -string "file://${HOME}/"
killall Finder 2>/dev/null || true # list -- Finder: Preferred view style
defaults write com.apple.finder FXPreferredViewStyle -string "nlsv"
# Spotlight killall Finder 2>/dev/null || true
# ---------
# on -- Spotlight: Hide menu bar icon
defaults write com.apple.Spotlight MenuItemHidden -int 1
killall Spotlight 2>/dev/null || true # Spotlight
# ---------
# on -- Spotlight: Hide menu bar icon
defaults write com.apple.Spotlight MenuItemHidden -int 1
# Dock killall Spotlight 2>/dev/null || true
# ----
# off -- Dock: Show recent applications
defaults write com.apple.dock show-recents -bool false
# on -- Dock: Use scroll gestures # Dock
defaults write com.apple.dock scroll-to-open -bool true # ----
# off -- Dock: Show recent applications
defaults write com.apple.dock show-recents -bool false
# Remove default apps from the dock # on -- Dock: Use scroll gestures
default_apps=( defaults write com.apple.dock scroll-to-open -bool true
"Messages"
"Mail"
"Maps"
"Photos"
"FaceTime"
"Calendar"
"Contacts"
"Reminders"
"Freeform"
"TV"
"Music"
"News"
"Keynote"
"Numbers"
"Pages"
)
for default_app in default_apps; do
dockutil --remove "$default_app" --no-restart 1>/dev/null 2>&1 || true
done
# Set up apps in the dock # Remove default apps from the dock
dock_order=( default_apps=(
"/System/Library/CoreServices/Finder.app" # Cannot be moved "Messages"
"/System/Applications/App Store.app" "Mail"
"/System/Applications/Apps.app" "Maps"
"/System/Applications/System Settings.app" "Photos"
"/System/Applications/Utilities/Activity Monitor.app" "FaceTime"
"/Applications/iTerm.app" "Calendar"
) "Contacts"
dock_state=$(defaults read com.apple.dock persistent-apps) "Reminders"
for i in "${!dock_order[@]}"; do "Freeform"
if [[ $i -ne 0 ]]; then "TV"
path="${dock_order[$i]}" "Music"
name=$(basename "$path" | sed 's/\.app$//') "News"
if [[ $dock_state == *"$name"* ]]; then "Keynote"
dockutil --move "${path}" --position "$i" --no-restart "Numbers"
else "Pages"
dockutil --add "${path}" --position "$i" --no-restart )
fi for default_app in default_apps; do
dockutil --remove "$default_app" --no-restart 1>/dev/null 2>&1 || true
done
# Set up apps in the dock
dock_order=(
"/System/Library/CoreServices/Finder.app" # Cannot be moved
"/System/Applications/App Store.app"
"/System/Applications/Apps.app"
"/System/Applications/System Settings.app"
"/System/Applications/Utilities/Activity Monitor.app"
"/Applications/iTerm.app"
)
dock_state=$(defaults read com.apple.dock persistent-apps)
for i in "${!dock_order[@]}"; do
if [[ $i -ne 0 ]]; then
path="${dock_order[$i]}"
name=$(basename "$path" | sed 's/\.app$//')
if [[ $dock_state == *"$name"* ]]; then
dockutil --move "${path}" --position "$i" --no-restart
else
dockutil --add "${path}" --position "$i" --no-restart
fi fi
done
if [[ ! $dock_state == *"spacer"* ]]; then
dockutil --add '' --type spacer --section apps --position "${#dock_order[@]}" --no-restart
fi fi
done
killall Dock 2>/dev/null || true if [[ ! $dock_state == *"spacer"* ]]; then
else dockutil --add '' --type spacer --section apps --position "${#dock_order[@]}" --no-restart
log_warn "Skipping: Not macOS"
fi fi
killall Dock 2>/dev/null || true

View File

@@ -5,22 +5,26 @@
# Clean up after installation. # Clean up after installation.
# #
if [[ "$OSTYPE" == "darwin"* ]]; then case "$DOTS_PKG" in
brew cleanup brew)
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then brew cleanup
if command -v apt-get >/dev/null 2>&1; then ;;
apt)
sudo apt-get autoremove -qq sudo apt-get autoremove -qq
sudo apt-get clean -qq sudo apt-get clean -qq
elif command -v pacman >/dev/null 2>&1; then ;;
pacman)
# Remove orphans if any (ignore error if none) # Remove orphans if any (ignore error if none)
if pacman -Qtdq >/dev/null 2>&1; then if pacman -Qtdq >/dev/null 2>&1; then
sudo pacman -Rns --noconfirm $(pacman -Qtdq) || true sudo pacman -Rns --noconfirm $(pacman -Qtdq) || true
fi fi
# Clear package cache without interactive prompt # Clear package cache without interactive prompt
yes | sudo pacman -Scc >/dev/null 2>&1 || true yes | sudo pacman -Scc >/dev/null 2>&1 || true
else ;;
*)
log_warn "Skipping cleanup: no supported package manager found" log_warn "Skipping cleanup: no supported package manager found"
fi return 0
fi ;;
esac
log_pass "Cleanup completed successfully!" log_pass "Cleanup completed successfully!"