156 lines
6.0 KiB
Bash
Executable File
156 lines
6.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# install.sh — bootstrap zsh + oh-my-zsh + powerlevel10k + atuin and link dotfiles.
|
|
# Supports: Debian/Ubuntu (apt), Fedora/RHEL (dnf), Arch (pacman), macOS (brew).
|
|
# Idempotent: safe to re-run.
|
|
#
|
|
# Usage:
|
|
# git clone https://github.com/<you>/dotfiles ~/dotfiles && cd ~/dotfiles && ./install.sh
|
|
# or:
|
|
# curl -fsSL https://raw.githubusercontent.com/<you>/dotfiles/main/install.sh | bash
|
|
# (the curl form will git clone this repo to ~/dotfiles before running.)
|
|
|
|
set -euo pipefail
|
|
|
|
REPO_URL="${DOTFILES_REPO:-https://github.com/<you>/dotfiles}"
|
|
DOTFILES_DIR="${DOTFILES_DIR:-$HOME/dotfiles}"
|
|
|
|
log() { printf '\033[1;34m==>\033[0m %s\n' "$*"; }
|
|
warn() { printf '\033[1;33m!! \033[0m %s\n' "$*" >&2; }
|
|
die() { printf '\033[1;31mxx \033[0m %s\n' "$*" >&2; exit 1; }
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 0. If we're being curl|bashed, the script lives in /dev/stdin and there's no
|
|
# repo on disk. Clone, then re-exec from the checkout so $SCRIPT_DIR works.
|
|
# ---------------------------------------------------------------------------
|
|
if [ ! -t 0 ] && [ ! -f "${BASH_SOURCE[0]:-}" ] || [ "${BASH_SOURCE[0]:-}" = "/dev/stdin" ]; then
|
|
command -v git >/dev/null || die "git is required to clone the dotfiles repo"
|
|
if [ ! -d "$DOTFILES_DIR/.git" ]; then
|
|
log "Cloning $REPO_URL → $DOTFILES_DIR"
|
|
git clone "$REPO_URL" "$DOTFILES_DIR"
|
|
fi
|
|
exec bash "$DOTFILES_DIR/install.sh" "$@"
|
|
fi
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 1. Detect package manager and install prerequisites.
|
|
# ---------------------------------------------------------------------------
|
|
SUDO=""
|
|
if [ "$(id -u)" -ne 0 ] && command -v sudo >/dev/null; then SUDO="sudo"; fi
|
|
|
|
install_pkgs() {
|
|
local pkgs=("$@")
|
|
if command -v apt-get >/dev/null; then
|
|
$SUDO apt-get update -y
|
|
$SUDO DEBIAN_FRONTEND=noninteractive apt-get install -y "${pkgs[@]}"
|
|
elif command -v dnf >/dev/null; then
|
|
$SUDO dnf install -y "${pkgs[@]}"
|
|
elif command -v pacman >/dev/null; then
|
|
$SUDO pacman -Sy --noconfirm --needed "${pkgs[@]}"
|
|
elif command -v brew >/dev/null; then
|
|
brew install "${pkgs[@]}"
|
|
else
|
|
die "No supported package manager found (apt/dnf/pacman/brew)."
|
|
fi
|
|
}
|
|
|
|
log "Installing prerequisites (zsh, git, curl)"
|
|
install_pkgs zsh git curl
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 2. Oh My Zsh.
|
|
# ---------------------------------------------------------------------------
|
|
export ZSH="$HOME/.oh-my-zsh"
|
|
if [ ! -d "$ZSH" ]; then
|
|
log "Installing oh-my-zsh"
|
|
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
|
|
|
|
ZSH_CUSTOM="${ZSH_CUSTOM:-$ZSH/custom}"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 3. Powerlevel10k theme.
|
|
# ---------------------------------------------------------------------------
|
|
P10K_DIR="$ZSH_CUSTOM/themes/powerlevel10k"
|
|
if [ ! -d "$P10K_DIR" ]; then
|
|
log "Installing powerlevel10k"
|
|
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git "$P10K_DIR"
|
|
else
|
|
log "powerlevel10k already installed; pulling latest"
|
|
git -C "$P10K_DIR" pull --ff-only --quiet || warn "p10k pull failed (continuing)"
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 4. zsh-autosuggestions plugin.
|
|
# ---------------------------------------------------------------------------
|
|
AUTOSUG_DIR="$ZSH_CUSTOM/plugins/zsh-autosuggestions"
|
|
if [ ! -d "$AUTOSUG_DIR" ]; then
|
|
log "Installing zsh-autosuggestions"
|
|
git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions "$AUTOSUG_DIR"
|
|
else
|
|
log "zsh-autosuggestions already installed"
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 5. Atuin (shell history sync). Works on bash and zsh.
|
|
# ---------------------------------------------------------------------------
|
|
if ! command -v atuin >/dev/null && [ ! -x "$HOME/.atuin/bin/atuin" ]; then
|
|
log "Installing atuin"
|
|
curl --proto '=https' --tlsv1.2 -LsSf https://setup.atuin.sh | sh
|
|
else
|
|
log "atuin already installed"
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 6. Link dotfiles. Backs up anything already there to *.backup.<timestamp>.
|
|
# ---------------------------------------------------------------------------
|
|
TS="$(date +%Y%m%d-%H%M%S)"
|
|
link_file() {
|
|
local src="$1" dest="$2"
|
|
if [ -e "$dest" ] && [ ! -L "$dest" ]; then
|
|
log "Backing up $dest → $dest.backup.$TS"
|
|
mv "$dest" "$dest.backup.$TS"
|
|
elif [ -L "$dest" ]; then
|
|
rm "$dest"
|
|
fi
|
|
ln -s "$src" "$dest"
|
|
log "Linked $dest → $src"
|
|
}
|
|
|
|
link_file "$SCRIPT_DIR/.zshrc" "$HOME/.zshrc"
|
|
link_file "$SCRIPT_DIR/.p10k.zsh" "$HOME/.p10k.zsh"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 7. Change default shell to zsh (no-op if already zsh).
|
|
# ---------------------------------------------------------------------------
|
|
ZSH_BIN="$(command -v zsh)"
|
|
if [ -n "$ZSH_BIN" ] && [ "${SHELL:-}" != "$ZSH_BIN" ]; then
|
|
if grep -qx "$ZSH_BIN" /etc/shells 2>/dev/null || echo "$ZSH_BIN" | $SUDO tee -a /etc/shells >/dev/null; then
|
|
log "Setting login shell to $ZSH_BIN"
|
|
chsh -s "$ZSH_BIN" "$USER" || warn "chsh failed — run it manually: chsh -s $ZSH_BIN"
|
|
fi
|
|
else
|
|
log "Default shell already zsh"
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 8. Done.
|
|
# ---------------------------------------------------------------------------
|
|
cat <<EOF
|
|
|
|
✔ Dotfiles installed.
|
|
|
|
Next steps:
|
|
• Start a new shell: exec zsh -l
|
|
• For machine-specific overrides (API keys, conda init, nvm, etc.),
|
|
drop them in: ~/.zshrc.local (already sourced by .zshrc, ignored by git)
|
|
• If powerlevel10k icons look wrong, install a Nerd Font:
|
|
https://github.com/romkatv/powerlevel10k#meslo-nerd-font-patched-for-powerlevel10k
|
|
• Atuin sync (optional): atuin register -u <user> -e <email> / atuin login
|
|
|
|
EOF
|