install split
This commit is contained in:
149
install-stow.sh
Executable file
149
install-stow.sh
Executable file
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env bash
|
||||
# install-stow.sh: Stow dotfile packages into $HOME with per-package prompts.
|
||||
# Packages that are already fully stowed are skipped automatically.
|
||||
# Run after install-deps.sh.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
DOTFILES_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
ok() { echo " ✓ $*"; }
|
||||
info() { echo " → $*"; }
|
||||
warn() { echo " ⚠ $*"; }
|
||||
header() { echo ""; echo "==> $*"; }
|
||||
|
||||
# Ask yes/no. Returns 0 for yes, 1 for no.
|
||||
ask_yn() {
|
||||
local prompt="$1"
|
||||
while true; do
|
||||
read -r -p "$prompt [y/N] " answer
|
||||
case "${answer,,}" in
|
||||
y|yes) return 0 ;;
|
||||
n|no|"") return 1 ;;
|
||||
*) echo " Please answer y or n." ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Check if a package is already fully stowed
|
||||
# (every file in the package has a correct symlink in $HOME)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
is_stowed() {
|
||||
local pkg="$1"
|
||||
local pkg_dir="$DOTFILES_DIR/$pkg"
|
||||
local all_ok=true
|
||||
|
||||
while IFS= read -r -d '' src; do
|
||||
local rel="${src#$pkg_dir/}"
|
||||
local target="$HOME/$rel"
|
||||
# Must exist as a symlink pointing at this exact source
|
||||
if [[ ! -L "$target" ]] || [[ "$(readlink -f "$target")" != "$(readlink -f "$src")" ]]; then
|
||||
all_ok=false
|
||||
break
|
||||
fi
|
||||
done < <(find "$pkg_dir" -type f -print0 2>/dev/null)
|
||||
|
||||
$all_ok
|
||||
}
|
||||
|
||||
# List any real files (non-symlinks) that would be overwritten by stowing
|
||||
conflicts_for() {
|
||||
local pkg="$1"
|
||||
local pkg_dir="$DOTFILES_DIR/$pkg"
|
||||
local conflicts=()
|
||||
|
||||
while IFS= read -r -d '' src; do
|
||||
local rel="${src#$pkg_dir/}"
|
||||
local target="$HOME/$rel"
|
||||
if [[ -e "$target" ]] && [[ ! -L "$target" ]]; then
|
||||
conflicts+=("$target")
|
||||
fi
|
||||
done < <(find "$pkg_dir" -type f -print0 2>/dev/null)
|
||||
|
||||
printf '%s\n' "${conflicts[@]}"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Collect packages (top-level dirs, skip hidden)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
header "Stowing dotfile packages"
|
||||
|
||||
PACKAGES=()
|
||||
for d in "$DOTFILES_DIR"/*/; do
|
||||
pkg="$(basename "$d")"
|
||||
[[ "$pkg" == .* ]] && continue
|
||||
PACKAGES+=("$pkg")
|
||||
done
|
||||
|
||||
STOWED=()
|
||||
SKIPPED=()
|
||||
|
||||
for pkg in "${PACKAGES[@]}"; do
|
||||
echo ""
|
||||
echo "Package: $pkg"
|
||||
|
||||
if is_stowed "$pkg"; then
|
||||
ok "already stowed — skipping"
|
||||
STOWED+=("$pkg (already)")
|
||||
continue
|
||||
fi
|
||||
|
||||
# Show conflicts, if any
|
||||
mapfile -t conflicts < <(conflicts_for "$pkg")
|
||||
if [[ ${#conflicts[@]} -gt 0 ]]; then
|
||||
warn "Stowing would overwrite these real files:"
|
||||
for f in "${conflicts[@]}"; do
|
||||
echo " $f"
|
||||
done
|
||||
echo " Back them up or delete them first, then re-run."
|
||||
fi
|
||||
|
||||
if ask_yn " Stow '$pkg'?"; then
|
||||
stow --dir="$DOTFILES_DIR" --target="$HOME" --restow "$pkg"
|
||||
ok "stowed"
|
||||
STOWED+=("$pkg")
|
||||
else
|
||||
info "skipped"
|
||||
SKIPPED+=("$pkg")
|
||||
fi
|
||||
done
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Configure shell (after stowing zshrc)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
header "Shell configuration"
|
||||
|
||||
if [[ ! -f "$HOME/.zshrc" ]]; then
|
||||
touch "$HOME/.zshrc"
|
||||
fi
|
||||
|
||||
if ! grep -q 'eval "$(starship init zsh)"' "$HOME/.zshrc"; then
|
||||
echo 'eval "$(starship init zsh)"' >> "$HOME/.zshrc"
|
||||
ok "Added starship init to ~/.zshrc"
|
||||
else
|
||||
ok "Starship already configured in ~/.zshrc"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Summary
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
header "Summary"
|
||||
|
||||
if [[ ${#STOWED[@]} -gt 0 ]]; then
|
||||
echo " Stowed: ${STOWED[*]}"
|
||||
fi
|
||||
if [[ ${#SKIPPED[@]} -gt 0 ]]; then
|
||||
echo " Skipped: ${SKIPPED[*]}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Done."
|
||||
Reference in New Issue
Block a user