You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
3.3 KiB
114 lines
3.3 KiB
# lib/common.sh - shared helpers for all shell-inits scripts |
|
# Sourced after the standard entry preamble (which exports SI_BASE_URL/SI_MODE/SI_ROOT). |
|
set -euo pipefail |
|
|
|
# --- logging (logs go to stderr; stdout is reserved for return values) ------- |
|
|
|
si_log() { printf '[shell-inits] %s\n' "$*" >&2; } |
|
si_warn() { printf '[shell-inits][warn] %s\n' "$*" >&2; } |
|
si_die() { printf '[shell-inits][error] %s\n' "$*" >&2; exit 1; } |
|
si_banner() { printf '\n==> %s\n' "$*" >&2; } |
|
|
|
# --- small predicates ------------------------------------------------------ |
|
|
|
si_have_cmd() { command -v "$1" >/dev/null 2>&1; } |
|
si_is_root() { [[ $(id -u) -eq 0 ]]; } |
|
|
|
# --- privileges ------------------------------------------------------------ |
|
|
|
# Run a command with root privileges (packages etc). |
|
si_as_root() { |
|
if si_is_root; then |
|
"$@" |
|
elif si_have_cmd sudo; then |
|
sudo "$@" |
|
elif si_have_cmd doas; then |
|
doas "$@" |
|
else |
|
si_die "root privileges required and no sudo/doas available" |
|
fi |
|
} |
|
|
|
# The user whose environment we configure: |
|
# 1. SHELL_INITS_USER (explicit, e.g. docker builds running as root for a user) |
|
# 2. SUDO_USER (vm user running the script through sudo) |
|
# 3. current user (root login / running as the user directly) |
|
si_target_user() { |
|
if [[ -n ${SHELL_INITS_USER:-} ]]; then |
|
printf '%s' "$SHELL_INITS_USER" |
|
elif [[ -n ${SUDO_USER:-} ]]; then |
|
printf '%s' "$SUDO_USER" |
|
else |
|
id -un |
|
fi |
|
} |
|
|
|
si_target_home() { |
|
local user home |
|
user=$(si_target_user) |
|
home=$(getent passwd "$user" 2>/dev/null | cut -d: -f6 || true) |
|
[[ -n $home ]] || home=$HOME |
|
printf '%s' "$home" |
|
} |
|
|
|
# Run a shell command as the target user (git config, plugin clones, nvim...). |
|
si_as_user() { |
|
local cmd=$1 target |
|
target=$(si_target_user) |
|
if [[ $target == $(id -un) ]]; then |
|
bash -c "$cmd" |
|
elif si_is_root; then |
|
su -s /bin/bash "$target" -c "$cmd" |
|
else |
|
si_die "cannot run as user '$target' without root privileges" |
|
fi |
|
} |
|
|
|
# Fix ownership of files we created as root for another user. |
|
si_chown_target() { |
|
local target group |
|
target=$(si_target_user) |
|
[[ $target == $(id -un) ]] && return 0 |
|
si_is_root || return 0 |
|
group=$(id -gn "$target" 2>/dev/null || true) |
|
[[ -n $group ]] || group=$target |
|
chown -R "$target:$group" "$@" |
|
} |
|
|
|
# Create a directory as the target user (avoids root-owned ~/.local/... when |
|
# provisioning another user's home). |
|
si_user_mkdir() { |
|
local dir=$1 |
|
if [[ $(si_target_user) == $(id -un) ]]; then |
|
mkdir -p "$dir" |
|
else |
|
si_as_user "mkdir -p '$dir'" |
|
fi |
|
} |
|
|
|
# --- component dependencies ------------------------------------------------- |
|
|
|
# Keep a one-time backup of a pre-existing config path. |
|
si_backup_existing() { |
|
local path=$1 bak |
|
[[ -e $path ]] || return 0 |
|
bak="${path}.pre-shell-inits" |
|
[[ -e $bak ]] && bak="${path}.pre-shell-inits.$(date +%s)" |
|
cp -a "$path" "$bak" |
|
si_warn "backed up existing $path -> $bak" |
|
} |
|
|
|
# Ensure another core initializer has run (checks its state marker). |
|
si_ensure_core() { |
|
local component=$1 script |
|
if si_state_has "$component"; then |
|
return 0 |
|
fi |
|
si_log "dependency core/${component}.sh not satisfied yet, running it" |
|
if [[ ${SI_MODE:-local} == local ]]; then |
|
script="$SI_ROOT/core/${component}.sh" |
|
else |
|
script=$(si_fetch_file "core/${component}.sh") |
|
fi |
|
bash "$script" || si_die "dependency component '${component}' failed" |
|
}
|
|
|