add bootstrap.sh

This commit is contained in:
2026-03-05 15:39:04 -05:00
parent 91530ee83b
commit 0f8a7a8d22

188
bootstrap.sh Normal file
View File

@@ -0,0 +1,188 @@
#!/usr/bin/env bash
set -euo pipefail
# ====== CONFIG ======
DOTFILES_DIR="${DOTFILES_DIR:-$HOME/repos/dotfiles}"
DOTFILES_GIT_URL="${DOTFILES_GIT_URL:-}" # ex: git@github.com:TON_USER/dotfiles.git
STOW_PACKAGES_DEFAULT=("zsh" "tmux" "nvim" "hypr" "hypridle" "waybar" "alacritty")
INSTALL_FONTS="${INSTALL_FONTS:-1}" # 1 = install nerd font, 0 = skip
SET_DEFAULT_SHELL="${SET_DEFAULT_SHELL:-1}" # 1 = chsh to zsh, 0 = skip
# ====== HELPERS ======
log() { printf "\n\033[1m==>\033[0m %s\n" "$*"; }
warn() { printf "\033[33mWARN:\033[0m %s\n" "$*" >&2; }
die() { printf "\033[31mERR:\033[0m %s\n" "$*" >&2; exit 1; }
have() { command -v "$1" >/dev/null 2>&1; }
require_sudo() {
if [ "${EUID:-$(id -u)}" -ne 0 ]; then
if ! have sudo; then die "sudo is required"; fi
fi
}
sudo_run() {
if [ "${EUID:-$(id -u)}" -eq 0 ]; then
"$@"
else
sudo "$@"
fi
}
# ====== OS CHECK ======
if [ ! -f /etc/os-release ]; then
die "Unsupported OS (no /etc/os-release). This script targets Debian/Ubuntu."
fi
. /etc/os-release
case "${ID:-}" in
debian|ubuntu|linuxmint|pop)
;;
*)
warn "OS ID=${ID:-unknown}. Script is written for Debian/Ubuntu; proceeding anyway."
;;
esac
# ====== APT PACKAGES ======
log "Installing base packages (git, stow, zsh, tmux, neovim, etc.)"
require_sudo
sudo_run apt update
sudo_run apt install -y \
git curl ca-certificates stow \
zsh tmux neovim \
ripgrep fd-find \
unzip zip tar \
fontconfig
# Optional: tools often needed by nvim plugins (treesitter, etc.)
sudo_run apt install -y build-essential || true
# Hypr ecosystem (availability depends on distro/repo)
# We try, but do not fail if packages aren't found.
log "Trying to install Hyprland ecosystem packages (best effort)"
sudo_run apt install -y hyprland hypridle waybar alacritty 2>/dev/null || true
# ====== DOTFILES CLONE (OPTIONAL) ======
if [ ! -d "$DOTFILES_DIR/.git" ]; then
if [ -n "$DOTFILES_GIT_URL" ]; then
log "Cloning dotfiles repo into: $DOTFILES_DIR"
mkdir -p "$(dirname "$DOTFILES_DIR")"
git clone "$DOTFILES_GIT_URL" "$DOTFILES_DIR"
else
warn "DOTFILES_DIR has no .git and DOTFILES_GIT_URL is empty."
warn "Skipping clone. (Set DOTFILES_GIT_URL env var to auto-clone.)"
fi
else
log "Dotfiles repo already present: $DOTFILES_DIR"
fi
# ====== OH-MY-ZSH ======
if [ ! -d "$HOME/.oh-my-zsh" ]; then
log "Installing Oh My Zsh"
# Unattended install: does not launch zsh at end
RUNZSH=no CHSH=no KEEP_ZSHRC=yes \
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
else
log "Oh My Zsh already installed"
fi
# ====== POWERLEVEL10K + PLUGINS ======
ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}"
log "Installing Powerlevel10k theme + useful plugins"
mkdir -p "$ZSH_CUSTOM/themes" "$ZSH_CUSTOM/plugins"
if [ ! -d "$ZSH_CUSTOM/themes/powerlevel10k" ]; then
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git \
"$ZSH_CUSTOM/themes/powerlevel10k"
else
log "powerlevel10k already present"
fi
if [ ! -d "$ZSH_CUSTOM/plugins/zsh-autosuggestions" ]; then
git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions \
"$ZSH_CUSTOM/plugins/zsh-autosuggestions"
else
log "zsh-autosuggestions already present"
fi
if [ ! -d "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting" ]; then
git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting \
"$ZSH_CUSTOM/plugins/zsh-syntax-highlighting"
else
log "zsh-syntax-highlighting already present"
fi
# ====== NERD FONT (FOR P10K) ======
if [ "$INSTALL_FONTS" = "1" ]; then
log "Installing Meslo Nerd Font (for Powerlevel10k) (best effort)"
FONT_DIR="$HOME/.local/share/fonts"
mkdir -p "$FONT_DIR"
# Meslo Nerd Font (p10k recommended) - download 4 variants
# If this fails (no internet), it won't abort the script.
curl -fsSL -o "$FONT_DIR/MesloLGS NF Regular.ttf" \
"https://github.com/ryanoasis/nerd-fonts/raw/master/patched-fonts/Meslo/L/Regular/MesloLGSNerdFont-Regular.ttf" || true
curl -fsSL -o "$FONT_DIR/MesloLGS NF Bold.ttf" \
"https://github.com/ryanoasis/nerd-fonts/raw/master/patched-fonts/Meslo/L/Bold/MesloLGSNerdFont-Bold.ttf" || true
curl -fsSL -o "$FONT_DIR/MesloLGS NF Italic.ttf" \
"https://github.com/ryanoasis/nerd-fonts/raw/master/patched-fonts/Meslo/L/Italic/MesloLGSNerdFont-Italic.ttf" || true
curl -fsSL -o "$FONT_DIR/MesloLGS NF Bold Italic.ttf" \
"https://github.com/ryanoasis/nerd-fonts/raw/master/patched-fonts/Meslo/L/Bold-Italic/MesloLGSNerdFont-BoldItalic.ttf" || true
if have fc-cache; then
fc-cache -f >/dev/null 2>&1 || true
fi
else
log "Skipping font installation (INSTALL_FONTS=0)"
fi
# ====== STOW APPLY ======
if [ -d "$DOTFILES_DIR" ]; then
log "Applying stow packages into \$HOME (target=~)"
cd "$DOTFILES_DIR"
# Only stow packages that exist as directories
stow_args=()
for pkg in "${STOW_PACKAGES_DEFAULT[@]}"; do
if [ -d "$pkg" ]; then
stow_args+=("$pkg")
else
warn "Package dir missing, skipping: $pkg"
fi
done
if [ "${#stow_args[@]}" -eq 0 ]; then
warn "No stow package dirs found in $DOTFILES_DIR. Nothing to apply."
else
# Use verbose so you see what happened
stow -v -t "$HOME" "${stow_args[@]}"
fi
else
warn "DOTFILES_DIR not found: $DOTFILES_DIR (skipping stow apply)"
fi
# ====== DEFAULT SHELL ======
if [ "$SET_DEFAULT_SHELL" = "1" ]; then
if have zsh; then
log "Setting default shell to zsh (may prompt for password)"
# Ensure zsh is in /etc/shells
if ! grep -q "$(command -v zsh)" /etc/shells 2>/dev/null; then
warn "zsh not listed in /etc/shells; attempting to add (requires sudo)"
require_sudo
echo "$(command -v zsh)" | sudo_run tee -a /etc/shells >/dev/null
fi
chsh -s "$(command -v zsh)" "$USER" || true
else
warn "zsh not found; cannot set default shell"
fi
else
log "Skipping default shell change (SET_DEFAULT_SHELL=0)"
fi
log "Bootstrap complete."
log "Next steps:"
echo " - Open a new terminal (or log out/in) to use zsh."
echo " - If p10k prompts, run: p10k configure"
echo " - If Hypr/Waybar are missing, you may need distro-specific repos (not always in apt)."