Initial commit: linux-provision repo

Distribution-agnostic provisioning script that sets up a new Linux machine
(Detected via lib/distro.sh - supports Debian/Ubuntu/Pop and Fedora families).

13 stages covering:
- System packages, external repos, toolchains (nvm, uv, Python)
- Shell config (zsh, oh-my-zsh, p10k), git, SSH
- Custom uv tools from ~40 git repos
- Desktop config (keybindings, hotkeys, ghostty, fonts)
- Docker, system tweaks, browser/app installs
- Custom systemd user services (porridge, swayidle, mempi-sync, etc.)
- API keys loaded from Bitwarden at shell startup
This commit is contained in:
2026-06-05 21:21:46 +10:00
commit 180c5838ea
36 changed files with 4176 additions and 0 deletions

101
stages/04-shell.sh Normal file
View File

@@ -0,0 +1,101 @@
#!/usr/bin/env bash
# ===========================================================================
# Stage 04: Shell Configuration (zsh, oh-my-zsh, powerlevel10k)
# Deploys .zshrc, .p10k.zsh, and .zshrc.local (from config/shell/).
# ===========================================================================
# On the Pop machine, Julian uses:
# - zsh as default shell
# - oh-my-zsh with powerlevel10k theme (lean style, 1 line)
# - Plugin: git, zsh-autosuggestions
# - Custom aliases: bt-reset (Bluetooth)
# - 17 environment variables (API keys)
# - NVM integration
# - Ctrl+Backspace → backward-kill-word
#
# API keys go into ~/.zshrc.local (NOT tracked in this repo).
# See config/shell/zshrc.local.example for the template.
# ===========================================================================
# ---- Install zsh ----
info "Installing zsh..."
if command -v zsh &>/dev/null; then
ok "zsh already installed: $(zsh --version | head -1)"
else
pkg_install zsh 2>/dev/null
fi
# ---- Install oh-my-zsh ----
info "Installing Oh My Zsh..."
if [ -d "$HOME/.oh-my-zsh" ]; then
ok "Oh My Zsh already installed."
else
# Non-interactive install (no chsh prompt)
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended 2>/dev/null || {
warn "Oh My Zsh install failed; trying without unattended flag."
# Fallback: set ZSH and clone directly
export ZSH="$HOME/.oh-my-zsh"
git clone --depth=1 https://github.com/ohmyzsh/ohmyzsh.git "$ZSH" 2>/dev/null || true
}
ok "Oh My Zsh installed."
fi
# ---- Install Powerlevel10k theme ----
info "Installing Powerlevel10k theme..."
if [ -d "${ZSH:-$HOME/.oh-my-zsh}/custom/themes/powerlevel10k" ]; then
ok "Powerlevel10k already installed."
else
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git \
"${ZSH:-$HOME/.oh-my-zsh}/custom/themes/powerlevel10k" 2>/dev/null || warn "p10k clone failed."
fi
# ---- Install zsh-autosuggestions plugin ----
info "Installing zsh-autosuggestions plugin..."
if [ -d "${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-autosuggestions" ]; then
ok "zsh-autosuggestions already installed."
else
git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions \
"${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-autosuggestions" 2>/dev/null || warn "clone failed."
fi
# ---- Deploy .zshrc ----
info "Deploying .zshrc..."
CONFIG_DIR="${SCRIPT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}/config"
if [ -f "$HOME/.zshrc" ]; then
# Backup existing
cp "$HOME/.zshrc" "$HOME/.zshrc.bak.$(date +%Y%m%d)" 2>/dev/null
warn "Backed up existing .zshrc to .zshrc.bak.$(date +%Y%m%d)"
fi
cp "${CONFIG_DIR}/shell/zshrc" "$HOME/.zshrc"
ok ".zshrc deployed."
# ---- Deploy .p10k.zsh ----
info "Deploying .p10k.zsh..."
if [ -f "$HOME/.p10k.zsh" ]; then
cp "$HOME/.p10k.zsh" "$HOME/.p10k.zsh.bak.$(date +%Y%m%d)" 2>/dev/null
warn "Backed up existing .p10k.zsh"
fi
cp "${CONFIG_DIR}/shell/p10k.zsh" "$HOME/.p10k.zsh"
ok ".p10k.zsh deployed."
# ---- Deploy .zshrc.local (secrets template) ----
# This file should contain your API keys. The example file has placeholders.
# It is NOT sourced by default. To enable, uncomment the "source ~/.zshrc.local"
# line in your deployed .zshrc.
info "Installing .zshrc.local example..."
if [ ! -f "$HOME/.zshrc.local" ]; then
cp "${CONFIG_DIR}/shell/zshrc.local.example" "$HOME/.zshrc.local"
warn "Created ~/.zshrc.local from example. EDIT IT with your API keys."
else
ok ".zshrc.local already exists (keeping existing)."
fi
# ---- Change default shell to zsh ----
info "Setting zsh as default shell..."
if [ "$SHELL" != "$(which zsh)" ]; then
chsh -s "$(which zsh)" 2>/dev/null || warn "Could not change shell (chsh)."
ok "Default shell set to zsh. Log out and back in to activate."
else
ok "zsh is already the default shell."
fi
ok "Stage 04 complete: shell configured."