From bf179ef0b1e1ca339bf3fe436494d0d4928b64b1 Mon Sep 17 00:00:00 2001 From: Vuong Hoang Date: Fri, 26 Jun 2026 07:55:16 -0700 Subject: [PATCH] feat(installers): consolidate app installers into host-aware install-apps Fold macinstaller + install-apt-pkgs + install-tools + install-zellij into a single host-aware lk-installers/install-apps (macOS->Homebrew, bootstrapping Homebrew if absent; Linux->apt + upstream installers). Installs the tools the configs assume (bat, fd, fzf, zoxide, zellij, nvim, btop, htop, tldr) plus the fzf-git.sh helper and fzf shell integration; idempotent. link-dotfiles gains --apps to install then link in one shot. .zshrc drops the redundant brew/system zsh-autosuggestions source (zinit already loads it), fixing the missing-file error on a fresh box. README documents the new flow. --- README.md | 20 ++++++- home_root/.zshrc | 7 ++- link-dotfiles | 10 +++- lk-installers/install-apps | 99 ++++++++++++++++++++++++++++++++++ lk-installers/install-apt-pkgs | 3 -- lk-installers/install-tools | 8 --- lk-installers/install-zellij | 7 --- lk-installers/macinstaller | 35 ------------ 8 files changed, 130 insertions(+), 59 deletions(-) create mode 100755 lk-installers/install-apps delete mode 100755 lk-installers/install-apt-pkgs delete mode 100755 lk-installers/install-tools delete mode 100755 lk-installers/install-zellij delete mode 100755 lk-installers/macinstaller diff --git a/README.md b/README.md index 0dd7024..4a72d7d 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ Personal dotfiles. Configs are organized by where they get linked: One-shot, host-aware: ```bash -./link-dotfiles +./link-dotfiles # link only (installs stow if missing) +./link-dotfiles --apps # fresh box: install all CLI tools, then link ``` It detects the host (macOS vs Linux), installs [`stow`](https://www.gnu.org/software/stow/) @@ -22,6 +23,23 @@ if missing (Homebrew on macOS; apt/dnf/pacman on Linux), then runs `stow home_root` and `stow --target=$HOME/.config home_config`. Re-running is safe — stow is idempotent. +### Installing the tools + +The configs assume a handful of CLI tools (`bat`, `fd`, `fzf`, `zoxide`, +`zellij`, `nvim`, `btop`, `htop`, `tldr`, plus the `fzf-git.sh` helper). One +host-aware installer covers them: + +```bash +./lk-installers/install-apps # macOS -> Homebrew; Linux -> apt + upstream +``` + +On macOS it bootstraps Homebrew if absent. It's idempotent — re-running only +fills gaps. `./link-dotfiles --apps` just runs this first, then links. + +The zsh prompt and plugins (zinit, Powerlevel10k, autosuggestions, +syntax-highlighting, completions, vi-mode, fzf-tab) **self-install** from +`.zshrc` on first shell start, so they're not part of `install-apps`. + ## Windows (PowerShell) `stow` doesn't run natively on Windows, so use the PowerShell equivalent. It diff --git a/home_root/.zshrc b/home_root/.zshrc index 9702c1c..c933994 100644 --- a/home_root/.zshrc +++ b/home_root/.zshrc @@ -107,10 +107,9 @@ alias cd='z' zinit light Aloxaf/fzf-tab -if [[ $(uname) == "Darwin" ]]; then - source $(brew --prefix)/share/zsh-autosuggestions/zsh-autosuggestions.zsh -elif [[ $(uname) == "Linux" ]]; then - source /usr/share/zsh-autosuggestions/zsh-autosuggestions.zsh +# zsh-autosuggestions is already loaded via zinit above; on Linux, also wire +# the terminfo arrow keys to history search. +if [[ $(uname) == "Linux" ]]; then bindkey "${terminfo[kcuu1]}" history-search-backward bindkey "${terminfo[kcud1]}" history-search-forward fi diff --git a/link-dotfiles b/link-dotfiles index a27e3cb..576b59f 100755 --- a/link-dotfiles +++ b/link-dotfiles @@ -15,6 +15,14 @@ set -euo pipefail repo="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$repo" +# `--apps`: install all host CLI tools first, then link. Without it, this only +# links (fast + idempotent). App install is delegated to the host-aware +# lk-installers/install-apps. +if [ "${1:-}" = "--apps" ]; then + echo "Installing apps first (--apps)…" + "$repo/lk-installers/install-apps" +fi + ensure_stow() { command -v stow >/dev/null 2>&1 && return @@ -22,7 +30,7 @@ ensure_stow() { case "$(uname -s)" in Darwin) if ! command -v brew >/dev/null 2>&1; then - echo "error: Homebrew is required on macOS. Run ./lk-installers/macinstaller first." >&2 + echo "error: Homebrew is required on macOS. Run ./lk-installers/install-apps (or ./link-dotfiles --apps) first." >&2 exit 1 fi brew install stow diff --git a/lk-installers/install-apps b/lk-installers/install-apps new file mode 100755 index 0000000..c9c3404 --- /dev/null +++ b/lk-installers/install-apps @@ -0,0 +1,99 @@ +#!/usr/bin/env bash +# Host-aware installer for every CLI tool the dotfiles assume at runtime. +# +# macOS -> Homebrew (bootstraps Homebrew itself if missing) +# Linux -> apt (Debian/Ubuntu) + upstream installers for tools not in apt +# +# zinit and all zsh plugins (powerlevel10k, zsh-autosuggestions, +# zsh-syntax-highlighting, zsh-completions, zsh-vi-mode, fzf-tab) bootstrap +# themselves from ~/.zshrc on first shell start — they are NOT installed here. +# +# Idempotent: re-running only fills gaps. Pairs with ./link-dotfiles, or run +# `./link-dotfiles --apps` to install then link in one shot. +# +# Consolidates the former macinstaller / install-apt-pkgs / install-tools / +# install-zellij scripts. +set -euo pipefail + +# fzf-git.sh is a sourced helper (not a package) — same on every platform. +clone_fzf_git() { + if [ -d "$HOME/fzf-git.sh" ]; then + echo "fzf-git.sh already cloned — skipping" + else + git clone --depth 1 https://github.com/junegunn/fzf-git.sh.git "$HOME/fzf-git.sh" + fi +} + +install_macos() { + if ! command -v brew >/dev/null 2>&1; then + echo "Homebrew not found — installing…" + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + if [ -x /opt/homebrew/bin/brew ]; then eval "$(/opt/homebrew/bin/brew shellenv)" + elif [ -x /usr/local/bin/brew ]; then eval "$(/usr/local/bin/brew shellenv)" + fi + fi + + echo "Installing CLI tools via Homebrew…" + brew install \ + zsh git curl wget stow \ + bat fd fzf zoxide \ + zellij neovim btop htop + # tldr and neofetch are deprecated/disabled upstream — best-effort so a dead + # formula can't abort the run. tlrc is the maintained `tldr` client. + brew install tlrc || brew install tldr || echo "tldr unavailable — skipping" + brew install neofetch || echo "neofetch unavailable — skipping" + + # fzf key-bindings + completion -> ~/.fzf.zsh (sourced by .zshrc). These flags + # make it non-interactive; --no-update-rc stops it editing .zshrc (the repo + # owns that file). + "$(brew --prefix)/opt/fzf/install" --key-bindings --completion --no-update-rc >/dev/null + + clone_fzf_git +} + +install_linux() { + if ! command -v apt >/dev/null 2>&1; then + echo "error: Linux app install targets Debian/Ubuntu (apt). Install the tools manually on this distro." >&2 + exit 1 + fi + + echo "Installing base packages via apt…" + sudo apt update + sudo apt install -y --no-install-recommends \ + neovim vim-nox btop htop neofetch curl wget tldr git zip unzip stow zsh cargo \ + zsh-autosuggestions zsh-syntax-highlighting + sudo apt install -y --no-install-recommends rar unrar || true + + # fzf (vendored under ~/.cache/lk-tools/fzf; .zshrc adds its bin to PATH) + if [ ! -d "$HOME/.cache/lk-tools/fzf" ]; then + git clone --depth 1 https://github.com/junegunn/fzf.git "$HOME/.cache/lk-tools/fzf" + "$HOME/.cache/lk-tools/fzf/install" --key-bindings --completion --no-update-rc + fi + clone_fzf_git + + # zoxide (upstream installer -> ~/.local/bin, already on PATH) + command -v zoxide >/dev/null 2>&1 || \ + curl -sS https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | sh + + # bat + fd: upstream .deb so the binaries are named `bat`/`fd` (Debian ships + # them as `batcat`/`fdfind`). amd64 assumed — adjust the URLs on arm64 boxes. + if ! command -v bat >/dev/null 2>&1; then + wget -qO /tmp/bat.deb https://github.com/sharkdp/bat/releases/download/v0.24.0/bat_0.24.0_amd64.deb + sudo apt install -y /tmp/bat.deb + fi + if ! command -v fd >/dev/null 2>&1; then + wget -qO /tmp/fd.deb https://github.com/sharkdp/fd/releases/download/v10.1.0/fd_10.1.0_amd64.deb + sudo apt install -y /tmp/fd.deb + fi + + # zellij: cargo build, fall back to apt + command -v zellij >/dev/null 2>&1 || cargo install zellij || sudo apt install -y zellij +} + +case "$(uname -s)" in + Darwin) install_macos ;; + Linux) install_linux ;; + *) echo "error: unsupported OS '$(uname -s)'." >&2; exit 1 ;; +esac + +echo "Done. Open a new shell (or 'exec zsh') to pick everything up." diff --git a/lk-installers/install-apt-pkgs b/lk-installers/install-apt-pkgs deleted file mode 100755 index 7f4e9be..0000000 --- a/lk-installers/install-apt-pkgs +++ /dev/null @@ -1,3 +0,0 @@ -sudo apt update -sudo apt install neovim vim-nox btop htop neofetch curl wget tldr git zip unzip stow zsh zsh-autosuggestions zsh-syntax-highlighting cargo --no-install-recommends -sudo apt install rar unrar --no-install-recommends diff --git a/lk-installers/install-tools b/lk-installers/install-tools deleted file mode 100755 index ac2cec2..0000000 --- a/lk-installers/install-tools +++ /dev/null @@ -1,8 +0,0 @@ -git clone --depth 1 https://github.com/junegunn/fzf.git ~/.cache/lk-tools/fzf -~/.cache/lk-tools/fzf/install -git clone https://github.com/junegunn/fzf-git.sh.git ~/fzf-git.sh -curl -sS https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | sh -wget -O /tmp/bat.deb https://github.com/sharkdp/bat/releases/download/v0.24.0/bat_0.24.0_amd64.deb -sudo apt install /tmp/bat.deb -wget -O /tmp/fdfind.deb https://github.com/sharkdp/fd/releases/download/v10.1.0/fd_10.1.0_amd64.deb -sudo apt install /tmp/fdfind.deb diff --git a/lk-installers/install-zellij b/lk-installers/install-zellij deleted file mode 100755 index 1047423..0000000 --- a/lk-installers/install-zellij +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -echo "Installing Zellij via cargo..." -cargo install zellij || { - echo "Cargo failed - trying apt instead" - sudo apt update && sudo apt install -y zellij -} diff --git a/lk-installers/macinstaller b/lk-installers/macinstaller deleted file mode 100755 index f57777b..0000000 --- a/lk-installers/macinstaller +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash -# filepath: /Users/vhpfi/dotfiles/lk-installers/macinstaller - -# Check if Homebrew is installed -if command -v brew >/dev/null 2>&1; then - echo "Homebrew is already installed. Updating..." - brew update -else - echo "Homebrew not found. Installing Homebrew..." - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - - # Add Homebrew to PATH for the current session - if [[ -f /opt/homebrew/bin/brew ]]; then - # For Apple Silicon Macs - eval "$(/opt/homebrew/bin/brew shellenv)" - echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile - echo "Homebrew has been installed and added to your PATH." - elif [[ -f /usr/local/bin/brew ]]; then - # For Intel Macs - eval "$(/usr/local/bin/brew shellenv)" - echo 'eval "$(/usr/local/bin/brew shellenv)"' >> ~/.zprofile - echo "Homebrew has been installed and added to your PATH." - else - echo "Error: Couldn't find the Homebrew binary after installation." - exit 1 - fi -fi - -echo "Installing packages with Homebrew..." -brew install neovim btop htop neofetch curl wget git zip unzip zsh tldr -brew install zsh-autosuggestions zsh-syntax-highlighting -brew install rustup-init -rustup-init -y - -echo "Installation complete!" \ No newline at end of file