#!/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-- — 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."