diff --git a/README.md b/README.md index 81ef7f2..e19b020 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,21 @@ My configuration files that keep me from flipping a table after logging in. ## Setup ``` +sudo pacman -S stow # or your distro's equivalent git clone https://github.com/andwati/dotfiles ~/dev/dotfiles ~/dev/dotfiles/install.sh ``` -Symlinks `zsh/.zshrc`, `zsh/.zshenv`, `zsh/.zprofile`, `zsh/.p10k.zsh`, and -`gnupg/.gnupg/gpg-agent.conf` into `$HOME`, and clones oh-my-zsh plus the -theme/plugins `.zshrc` expects (powerlevel10k, zsh-autosuggestions, -zsh-syntax-highlighting, zsh-history-substring-search, zsh-completions, -you-should-use). +Each top-level directory is a [GNU Stow](https://www.gnu.org/software/stow/) +package mirroring `$HOME` (e.g. `zsh/.zshrc` -> `~/.zshrc`). `install.sh` +clones oh-my-zsh plus the theme/plugins `.zshrc` expects (powerlevel10k, +zsh-autosuggestions, zsh-syntax-highlighting, zsh-history-substring-search, +zsh-completions, you-should-use), then runs `stow zsh gnupg` to link +everything in, backing up any conflicting real files it finds first (e.g. +oh-my-zsh's own freshly-installed `.zshrc`). + +To add a new package: create a top-level dir shaped like `$HOME` (e.g. +`git/.gitconfig`), then add a `stow_package ` call in `install.sh`. `gpg-agent.conf` caches your GPG passphrase for 8 hours (24h hard cap) instead of the 10-minute default, so signed commits don't re-prompt diff --git a/install.sh b/install.sh index 75d1f9c..e8b9627 100755 --- a/install.sh +++ b/install.sh @@ -1,19 +1,16 @@ #!/usr/bin/env bash -# Bootstraps zsh config on a new machine: symlinks dotfiles into $HOME and -# clones oh-my-zsh + the custom theme/plugins referenced by .zshrc. +# Bootstraps dotfiles on a new machine: installs oh-my-zsh + the custom +# theme/plugins .zshrc expects, then symlinks packages into $HOME via +# GNU Stow (each top-level dir is a package mirroring $HOME, e.g. +# zsh/.zshrc -> ~/.zshrc). Add a new package by adding a new top-level dir. set -euo pipefail DOTFILES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}" -link() { - local src="$1" dst="$2" - if [ -e "$dst" ] && [ ! -L "$dst" ]; then - mv "$dst" "$dst.bak.$(date +%s)" - echo "Backed up existing $dst" - fi - ln -sfn "$src" "$dst" - echo "Linked $dst -> $src" +command -v stow >/dev/null || { + echo "GNU Stow is required: sudo pacman -S stow (or your distro's equivalent)" >&2 + exit 1 } clone_if_missing() { @@ -34,14 +31,30 @@ clone_if_missing https://github.com/zsh-users/zsh-history-substring-search "$ZSH clone_if_missing https://github.com/zsh-users/zsh-completions "$ZSH_CUSTOM/plugins/zsh-completions" clone_if_missing https://github.com/MichaelAquilina/zsh-you-should-use "$ZSH_CUSTOM/plugins/you-should-use" -link "$DOTFILES_DIR/zsh/.zshrc" "$HOME/.zshrc" -link "$DOTFILES_DIR/zsh/.zshenv" "$HOME/.zshenv" -link "$DOTFILES_DIR/zsh/.zprofile" "$HOME/.zprofile" -link "$DOTFILES_DIR/zsh/.p10k.zsh" "$HOME/.p10k.zsh" +# Stow refuses to link over a real (non-symlink) file, so move any +# conflicting pre-existing file aside first (e.g. the .zshrc oh-my-zsh's +# own installer just wrote above). +stow_package() { + local pkg="$1" f rel target + while IFS= read -r -d '' f; do + rel="${f#"$DOTFILES_DIR/$pkg/"}" + target="$HOME/$rel" + if [ -L "$target" ]; then + rm "$target" + elif [ -e "$target" ]; then + mkdir -p "$(dirname "$target")" + mv "$target" "$target.bak.$(date +%s)" + echo "Backed up existing $target" + fi + done < <(find "$DOTFILES_DIR/$pkg" -type f -print0) + stow --dir="$DOTFILES_DIR" --target="$HOME" --restow "$pkg" + echo "Stowed $pkg" +} -mkdir -p "$HOME/.gnupg" -chmod 700 "$HOME/.gnupg" -link "$DOTFILES_DIR/gnupg/.gnupg/gpg-agent.conf" "$HOME/.gnupg/gpg-agent.conf" +mkdir -p "$HOME/.gnupg" && chmod 700 "$HOME/.gnupg" + +stow_package zsh +stow_package gnupg gpgconf --kill gpg-agent 2>/dev/null || true cat <<'EOF'