Shell environment initializers and docker containers
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

# 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"
}