137 lines
No EOL
5.7 KiB
Bash
137 lines
No EOL
5.7 KiB
Bash
#!/usr/bin/env bash
|
|
# Built standing on the shoulders of billions of dwarves
|
|
# Created by John A. Hoeven with the ethical assistance of Claude AI
|
|
# Licence: The Unlicense — https://unlicense.org
|
|
# ---------------------------------------------------------------------------
|
|
# llama-cpp-prune.sh
|
|
# /opt/llama-cpp/scripts/llama-cpp-prune.sh
|
|
# Version: v0.0.1 | Status: DEVELOPMENT
|
|
# Role: Orchestrator
|
|
# ---------------------------------------------------------------------------
|
|
# Purpose: Remove staged llama.cpp releases (and their matching pre-update
|
|
# btrfs snapshots) beyond a configurable retention count. Never
|
|
# removes the release currently pointed at by 'current', and
|
|
# never removes anything without listing it and asking first.
|
|
# Target: BigBoy — AlmaLinux 10.2, @llama-cpp btrfs subvolume
|
|
# Entry: sudo ./llama-cpp-prune.sh [keep-count]
|
|
# e.g. sudo ./llama-cpp-prune.sh (uses default: 6)
|
|
# sudo ./llama-cpp-prune.sh 12 (keep last 12 instead)
|
|
# Depends: btrfs-progs
|
|
# Note: Disk math at 6 releases (~1-1.5GB shallow-clone build each) is
|
|
# roughly 6-9GB against a 499GB OS partition — trivial. Raise
|
|
# KEEP_DEFAULT freely; there is no disk-pressure reason to prune
|
|
# aggressively on this hardware.
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# No 'set -e' — every operation is checked explicitly (CE OS standard §1.8).
|
|
|
|
# ── Configuration ────────────────────────────────────────────────────────
|
|
|
|
LLAMA_ROOT="/opt/llama-cpp"
|
|
RELEASES_DIR="${LLAMA_ROOT}/releases"
|
|
CURRENT_LINK="${LLAMA_ROOT}/current"
|
|
SNAPSHOT_DIR="/opt/.snapshots/llama-cpp"
|
|
KEEP_DEFAULT=6
|
|
LOG_DIR="${HOME}/.local/logs/bigboy-llama-update"
|
|
LOG_FILE="${LOG_DIR}/prune-$(date '+%Y-%m-%d_%H%M%S').log"
|
|
|
|
KEEP_COUNT="${1:-${KEEP_DEFAULT}}"
|
|
|
|
# ── Logging ──────────────────────────────────────────────────────────────
|
|
|
|
mkdir -p "${LOG_DIR}"
|
|
|
|
_log() {
|
|
local level="${1}"
|
|
local msg="${2}"
|
|
local ts
|
|
ts="$(date '+%Y-%m-%d %H:%M:%S')"
|
|
printf '[%s] [%s] %s\n' "${ts}" "${level}" "${msg}" | tee -a "${LOG_FILE}"
|
|
}
|
|
log_info() { _log "INFO " "${1}"; }
|
|
log_warn() { _log "WARN " "${1}" >&2; }
|
|
log_error() { _log "ERROR" "${1}" >&2; }
|
|
|
|
# ── Pre-flight checks ────────────────────────────────────────────────────
|
|
|
|
if [[ "${EUID}" -eq 0 ]]; then
|
|
log_error "Do not run this script directly as root — it invokes sudo"
|
|
log_error "only for the specific steps that need it."
|
|
exit 1
|
|
fi
|
|
|
|
if ! [[ "${KEEP_COUNT}" =~ ^[0-9]+$ ]] || [[ "${KEEP_COUNT}" -lt 1 ]]; then
|
|
log_error "keep-count must be a positive integer. Got: ${KEEP_COUNT}"
|
|
exit 1
|
|
fi
|
|
|
|
CURRENT_TAG=""
|
|
if [[ -L "${CURRENT_LINK}" ]]; then
|
|
CURRENT_TAG="$(basename "$(readlink -f "${CURRENT_LINK}")")"
|
|
fi
|
|
|
|
# ── Build the candidate list (oldest first, by directory mtime) ─────────
|
|
|
|
mapfile -t ALL_RELEASES < <(ls -1t "${RELEASES_DIR}" 2>/dev/null | tac)
|
|
TOTAL="${#ALL_RELEASES[@]}"
|
|
|
|
if [[ "${TOTAL}" -le "${KEEP_COUNT}" ]]; then
|
|
log_info "Only ${TOTAL} release(s) present, keep-count is ${KEEP_COUNT} — nothing to prune."
|
|
exit 0
|
|
fi
|
|
|
|
PRUNE_COUNT=$((TOTAL - KEEP_COUNT))
|
|
TO_PRUNE=("${ALL_RELEASES[@]:0:${PRUNE_COUNT}}")
|
|
|
|
# Never prune the currently live release, even if it's old — pull it out
|
|
# of the candidate list and log that it's being kept for that reason.
|
|
FILTERED_PRUNE=()
|
|
for tag in "${TO_PRUNE[@]}"; do
|
|
if [[ "${tag}" == "${CURRENT_TAG}" ]]; then
|
|
log_warn "Skipping ${tag} — it is the currently live release."
|
|
continue
|
|
fi
|
|
FILTERED_PRUNE+=("${tag}")
|
|
done
|
|
|
|
if [[ "${#FILTERED_PRUNE[@]}" -eq 0 ]]; then
|
|
log_info "Nothing eligible to prune after excluding the live release."
|
|
exit 0
|
|
fi
|
|
|
|
# ── Confirmation ─────────────────────────────────────────────────────────
|
|
|
|
printf '\nCurrently live release: %s (never pruned)\n' "${CURRENT_TAG:-none}"
|
|
printf 'Keeping the %d most recent releases.\n' "${KEEP_COUNT}"
|
|
printf '\nThe following %d release(s) and their matching snapshots will be removed:\n' \
|
|
"${#FILTERED_PRUNE[@]}"
|
|
for tag in "${FILTERED_PRUNE[@]}"; do
|
|
printf ' - %s\n' "${tag}"
|
|
done
|
|
printf '\nProceed? [y/N] '
|
|
read -r response
|
|
case "${response}" in
|
|
[yY]|[yY][eE][sS]) ;;
|
|
*) log_info "Aborted by user."; exit 0 ;;
|
|
esac
|
|
|
|
# ── Prune ────────────────────────────────────────────────────────────────
|
|
|
|
for tag in "${FILTERED_PRUNE[@]}"; do
|
|
log_info "Removing release directory: ${RELEASES_DIR}/${tag}"
|
|
if ! sudo rm -rf "${RELEASES_DIR:?}/${tag}" >>"${LOG_FILE}" 2>&1; then
|
|
log_error "Failed to remove ${RELEASES_DIR}/${tag} — leaving it in place."
|
|
continue
|
|
fi
|
|
|
|
# Snapshots are named pre-<tag>-<date> — match by tag prefix.
|
|
for snap in "${SNAPSHOT_DIR}"/pre-"${tag}"-*; do
|
|
[[ -e "${snap}" ]] || continue
|
|
log_info "Removing matching snapshot: ${snap}"
|
|
if ! sudo btrfs subvolume delete "${snap}" >>"${LOG_FILE}" 2>&1; then
|
|
log_error "Failed to remove snapshot ${snap} — leaving it in place."
|
|
fi
|
|
done
|
|
done
|
|
|
|
log_info "Prune complete. Kept ${KEEP_COUNT} most recent release(s) plus the live one if older." |