#!/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)."