diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100644 index 0000000..176e64d --- /dev/null +++ b/bootstrap.sh @@ -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)."