skeleton: launcher, entrypoint, distro/log/prompt libs
This commit is contained in:
commit
8057fbac4d
34
install.sh
Executable file
34
install.sh
Executable file
@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# bootstrap launcher — curl <shortener> | bash
|
||||
#
|
||||
# This file is intentionally tiny and stable: its only job is to clone the
|
||||
# bootstrap repo (or update an existing clone) and hand off to setup.sh.
|
||||
# All real logic lives in the repo so you can update it with `git pull`.
|
||||
#
|
||||
# Usage:
|
||||
# curl -fsSL <shortener> | bash
|
||||
# curl -fsSL <shortener> | bash -s -- --yes
|
||||
# curl -fsSL <shortener> | bash -s -- --only packages
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REPO_URL="${BOOTSTRAP_REPO:-https://g.mk.fo/bootstrap/main.git}"
|
||||
CLONE_DIR="${BOOTSTRAP_HOME:-$HOME/.bootstrap}"
|
||||
|
||||
need() { command -v "$1" >/dev/null 2>&1 || { echo "bootstrap: missing required command: $1" >&2; exit 1; }; }
|
||||
need git
|
||||
|
||||
if [[ -d "$CLONE_DIR/.git" ]]; then
|
||||
echo ">> existing bootstrap at $CLONE_DIR — pulling updates"
|
||||
git -C "$CLONE_DIR" pull --ff-only
|
||||
else
|
||||
if [[ -d "$CLONE_DIR" ]]; then
|
||||
mv "$CLONE_DIR" "${CLONE_DIR}.bak.$(date +%Y%m%d-%H%M%S)"
|
||||
echo ">> backed up old $CLONE_DIR"
|
||||
fi
|
||||
echo ">> cloning $REPO_URL -> $CLONE_DIR"
|
||||
git clone --depth 1 "$REPO_URL" "$CLONE_DIR"
|
||||
fi
|
||||
|
||||
exec bash "$CLONE_DIR/setup.sh" "$@"
|
||||
29
lib/detect.sh
Executable file
29
lib/detect.sh
Executable file
@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
# detect.sh — distro + arch detection. Exports DISTRO and ARCH.
|
||||
|
||||
detect_distro() {
|
||||
DISTRO="unknown"
|
||||
ARCH="$(uname -m)"
|
||||
case "$ARCH" in
|
||||
x86_64) ARCH="amd64" ;;
|
||||
aarch64|arm64) ARCH="arm64" ;;
|
||||
esac
|
||||
|
||||
if [[ -f /etc/os-release ]]; then
|
||||
# shellcheck disable=SC1091
|
||||
. /etc/os-release
|
||||
case "${ID:-}" in
|
||||
debian|ubuntu) DISTRO="debian" ;;
|
||||
arch) DISTRO="arch" ;;
|
||||
*)
|
||||
case "${ID_LIKE:-}" in
|
||||
*debian*) DISTRO="debian" ;;
|
||||
*arch*) DISTRO="arch" ;;
|
||||
esac ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
export DISTRO ARCH
|
||||
}
|
||||
|
||||
detect_distro
|
||||
22
lib/log.sh
Executable file
22
lib/log.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
# log.sh — tiny color log helpers.
|
||||
|
||||
log() { printf '\033[1;34m>>\033[0m %s\n' "$*"; }
|
||||
warn() { printf '\033[1;33m!!\033[0m %s\n' "$*" >&2; }
|
||||
err() { printf '\033[1;31mxx\033[0m %s\n' "$*" >&2; }
|
||||
ok() { printf '\033[1;32mok\033[0m %s\n' "$*"; }
|
||||
|
||||
# run a command as root when not already root
|
||||
sudo_() { if (( EUID == 0 )); then "$@"; else sudo "$@"; fi; }
|
||||
|
||||
# run a command AS the invoking (non-root) user — used for AUR builds, etc.
|
||||
# when root: drop to SUDO_USER (or USER) via runuser; when not root: run directly.
|
||||
as_user() {
|
||||
local u="$USER"
|
||||
if (( EUID == 0 )); then
|
||||
u="${SUDO_USER:-$USER}"
|
||||
command -v runuser >/dev/null 2>&1 && runuser -u "$u" -- "$@" || su "$u" -c "$*"
|
||||
else
|
||||
"$@"
|
||||
fi
|
||||
}
|
||||
19
lib/prompt.sh
Executable file
19
lib/prompt.sh
Executable file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
# prompt.sh — plain y/N prompts.
|
||||
|
||||
# ask "prompt?" [default y|n] -> sets REPLY
|
||||
ask() {
|
||||
local p="$1" d="${2:-y}" hint
|
||||
if [[ "$d" == "y" ]]; then hint="[Y/n]"; else hint="[y/N]"; fi
|
||||
read -rp "$p $hint " REPLY
|
||||
[[ -z "$REPLY" ]] && REPLY="$d"
|
||||
}
|
||||
|
||||
# yn "prompt?" [default] -> returns 0 (true) if answer is yes
|
||||
yn() {
|
||||
ask "$1" "${2:-y}"
|
||||
[[ "$REPLY" =~ ^[Yy]$ ]]
|
||||
}
|
||||
|
||||
# confirm_once "prompt?" default -> for destructive single confirm
|
||||
confirm_once() { yn "$1" "${2:-n}"; }
|
||||
92
setup.sh
Executable file
92
setup.sh
Executable file
@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# setup.sh — bootstrap entrypoint.
|
||||
# Detects distro/arch, lists modular steps, asks y/N per step, runs them.
|
||||
#
|
||||
# Flags:
|
||||
# --yes run all steps without prompting
|
||||
# --only NAME run only the step matching NAME
|
||||
# --skip NAME run all steps except NAME (repeatable in future)
|
||||
# -h|--help usage
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
BOOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
source "$BOOT_DIR/lib/detect.sh"
|
||||
source "$BOOT_DIR/lib/log.sh"
|
||||
source "$BOOT_DIR/lib/prompt.sh"
|
||||
|
||||
ALL=0; ONLY=""; SKIP=""
|
||||
while (( $# )); do
|
||||
case "$1" in
|
||||
--yes|-y) ALL=1; shift ;;
|
||||
--only) ONLY="${2:-}"; shift 2 ;;
|
||||
--skip) SKIP="${2:-}"; shift 2 ;;
|
||||
-h|--help)
|
||||
echo "usage: setup.sh [--yes] [--only NAME] [--skip NAME]"
|
||||
exit 0 ;;
|
||||
*) echo "unknown arg: $1" >&2; shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# ---------------------------------------------------------------- collect steps
|
||||
NAMES=(); DESCS=(); RUNS=()
|
||||
for f in "$BOOT_DIR"/modules/*.sh; do
|
||||
step_name=""; step_desc=""; step_run=""
|
||||
# shellcheck disable=SC1090
|
||||
source "$f"
|
||||
[[ -z "$step_name" ]] && continue
|
||||
NAMES+=("$step_name")
|
||||
DESCS+=("$step_desc")
|
||||
RUNS+=("$step_run")
|
||||
done
|
||||
|
||||
# ----------------------------------------------------------------- print plan
|
||||
echo
|
||||
printf 'Detected: \033[1mdistro\033[0m=%s \033[1march\033[0m=%s \033[1muser\033[0m=%s\n' "$DISTRO" "$ARCH" "$USER"
|
||||
echo
|
||||
echo "Steps:"
|
||||
for i in "${!NAMES[@]}"; do
|
||||
printf ' [%02d] %-12s — %s\n' "$((i+1))" "${NAMES[$i]}" "${DESCS[$i]}"
|
||||
done
|
||||
echo
|
||||
|
||||
# ----------------------------------------------------------------- decide run
|
||||
run_step() { # name
|
||||
local n="$1" i
|
||||
for i in "${!NAMES[@]}"; do
|
||||
if [[ "${NAMES[$i]}" == "$n" ]]; then
|
||||
echo; echo "── ${NAMES[$i]} ──────────────────────────────────────────────"
|
||||
# shellcheck disable=SCSC2086
|
||||
"${RUNS[$i]}"
|
||||
return $?
|
||||
fi
|
||||
done
|
||||
err "no step named '$n'"; return 1
|
||||
}
|
||||
|
||||
if [[ -n "$ONLY" ]]; then
|
||||
run_step "$ONLY"
|
||||
elif (( ALL )); then
|
||||
for n in "${NAMES[@]}"; do
|
||||
[[ -n "$SKIP" && "$n" == "$SKIP" ]] && continue
|
||||
run_step "$n"
|
||||
done
|
||||
else
|
||||
for i in "${!NAMES[@]}"; do
|
||||
local_run=1
|
||||
[[ -n "$SKIP" && "${NAMES[$i]}" == "$SKIP" ]] && local_run=0
|
||||
if (( local_run )) && yn "Run step [$(printf %02d $((i+1)))] ${NAMES[$i]}?" y; then
|
||||
run_step "${NAMES[$i]}" || warn "step ${NAMES[$i]} had an error (continuing)"
|
||||
else
|
||||
echo " skip ${NAMES[$i]}"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo
|
||||
ok "bootstrap done."
|
||||
echo " re-run any step: bash $BOOT_DIR/setup.sh --only <name>"
|
||||
echo " run everything: bash $BOOT_DIR/setup.sh --yes"
|
||||
Loading…
Reference in New Issue
Block a user