initial commit
This commit is contained in:
Executable
+117
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env bash
|
||||
# Shared helpers for the arch-i3 bootstrap scripts.
|
||||
# Sourced, never executed directly.
|
||||
|
||||
set -Eeuo pipefail
|
||||
|
||||
# --- paths -----------------------------------------------------------------
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
DOTFILES_DIR="$REPO_ROOT/dotfiles"
|
||||
PACKAGES_DIR="$REPO_ROOT/packages"
|
||||
WALLPAPER_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/wallpapers"
|
||||
BACKUP_DIR="$HOME/.config-backup-$(date +%Y%m%d-%H%M%S)"
|
||||
|
||||
# --- flags (exported by install.sh) ---------------------------------------
|
||||
: "${DRY_RUN:=0}"
|
||||
: "${ASSUME_YES:=0}"
|
||||
|
||||
# --- colours ---------------------------------------------------------------
|
||||
if [[ -t 1 ]]; then
|
||||
C_RESET=$'\e[0m'; C_BOLD=$'\e[1m'; C_DIM=$'\e[2m'
|
||||
C_BLUE=$'\e[38;5;111m'; C_GREEN=$'\e[38;5;115m'
|
||||
C_YELLOW=$'\e[38;5;222m'; C_RED=$'\e[38;5;210m'; C_MAUVE=$'\e[38;5;140m'
|
||||
else
|
||||
C_RESET=''; C_BOLD=''; C_DIM=''
|
||||
C_BLUE=''; C_GREEN=''; C_YELLOW=''; C_RED=''; C_MAUVE=''
|
||||
fi
|
||||
|
||||
log() { printf '%s==>%s %s\n' "$C_BLUE$C_BOLD" "$C_RESET" "$*"; }
|
||||
step() { printf '%s ->%s %s\n' "$C_MAUVE" "$C_RESET" "$*"; }
|
||||
ok() { printf '%s ok%s %s\n' "$C_GREEN" "$C_RESET" "$*"; }
|
||||
warn() { printf '%s !!%s %s\n' "$C_YELLOW" "$C_RESET" "$*" >&2; }
|
||||
die() { printf '%serror%s %s\n' "$C_RED$C_BOLD" "$C_RESET" "$*" >&2; exit 1; }
|
||||
skip() { printf '%s --%s %s\n' "$C_DIM" "$C_RESET" "$*"; }
|
||||
|
||||
# Run a command, honouring DRY_RUN.
|
||||
run() {
|
||||
if [[ "$DRY_RUN" == "1" ]]; then
|
||||
printf '%s dry%s %s\n' "$C_DIM" "$C_RESET" "$*"
|
||||
return 0
|
||||
fi
|
||||
"$@"
|
||||
}
|
||||
|
||||
confirm() {
|
||||
[[ "$ASSUME_YES" == "1" ]] && return 0
|
||||
[[ "$DRY_RUN" == "1" ]] && return 0
|
||||
local reply
|
||||
read -rp "$(printf '%s ??%s %s [y/N] ' "$C_YELLOW" "$C_RESET" "$1")" reply
|
||||
[[ "$reply" =~ ^[Yy]$ ]]
|
||||
}
|
||||
|
||||
have() { command -v "$1" >/dev/null 2>&1; }
|
||||
|
||||
# Print a path with $HOME collapsed to '~'. Done as a function because the
|
||||
# obvious ${path/#$HOME/~} keeps a literal backslash in the replacement.
|
||||
tildify() {
|
||||
local p="$1"
|
||||
if [[ "$p" == "$HOME"/* ]]; then
|
||||
printf '~/%s' "${p#"$HOME"/}"
|
||||
elif [[ "$p" == "$HOME" ]]; then
|
||||
printf '~'
|
||||
else
|
||||
printf '%s' "$p"
|
||||
fi
|
||||
}
|
||||
|
||||
# Read a package list file, dropping comments and blanks.
|
||||
read_pkg_list() {
|
||||
local file="$1"
|
||||
[[ -f "$file" ]] || die "package list not found: $file"
|
||||
sed -e 's/#.*$//' -e 's/[[:space:]]\+$//' "$file" | grep -v '^[[:space:]]*$' || true
|
||||
}
|
||||
|
||||
# Guard rails common to every stage.
|
||||
require_arch() {
|
||||
[[ -f /etc/arch-release ]] || die "this bootstrap targets Arch Linux (no /etc/arch-release found)"
|
||||
}
|
||||
|
||||
require_not_root() {
|
||||
[[ "$(id -u)" -ne 0 ]] || die "run this as your normal user, not root — sudo is invoked where needed"
|
||||
}
|
||||
|
||||
require_sudo() {
|
||||
have sudo || die "sudo is not installed; install it and add your user to the wheel group first"
|
||||
if [[ "$DRY_RUN" != "1" ]]; then
|
||||
sudo -v || die "sudo authentication failed"
|
||||
# Keep the sudo timestamp alive for the length of the run.
|
||||
( while true; do sudo -n true; sleep 50; kill -0 "$$" 2>/dev/null || exit; done ) &
|
||||
SUDO_KEEPALIVE_PID=$!
|
||||
trap 'kill "$SUDO_KEEPALIVE_PID" 2>/dev/null || true' EXIT
|
||||
fi
|
||||
}
|
||||
|
||||
# Back up a path (file, dir or symlink) into $BACKUP_DIR, preserving structure.
|
||||
backup_path() {
|
||||
local target="$1"
|
||||
[[ -e "$target" || -L "$target" ]] || return 0
|
||||
local rel="${target#"$HOME"/}"
|
||||
local dest="$BACKUP_DIR/$rel"
|
||||
step "backing up $(tildify "$target") -> $(tildify "$dest")"
|
||||
run mkdir -p "$(dirname "$dest")"
|
||||
run mv "$target" "$dest"
|
||||
}
|
||||
|
||||
# Copy a file from the repo into place, backing up whatever was there.
|
||||
install_file() {
|
||||
local src="$1" dest="$2" mode="${3:-644}"
|
||||
[[ -f "$src" ]] || die "missing source file: $src"
|
||||
if [[ -f "$dest" ]] && cmp -s "$src" "$dest"; then
|
||||
skip "$(tildify "$dest") already up to date"
|
||||
return 0
|
||||
fi
|
||||
backup_path "$dest"
|
||||
run mkdir -p "$(dirname "$dest")"
|
||||
run install -m "$mode" "$src" "$dest"
|
||||
ok "installed $(tildify "$dest")"
|
||||
}
|
||||
Reference in New Issue
Block a user