#!/usr/bin/env bash # Created by John A. Hoeven with the ethical assistance of Claude AI # --------------------------------------------------------------------------- # ce-common.sh # ~/projects/ceos/alpine-installer/lib/ce-common.sh # Version: v0.0.1 | Status: DEVELOPMENT # Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480) # --------------------------------------------------------------------------- # Shared library: logging, run_test, package helpers, common guards. # Source this file; do not execute directly. # --------------------------------------------------------------------------- # Guard against double-sourcing [[ -n "${CE_COMMON_LOADED:-}" ]] && return 0 CE_COMMON_LOADED=1 # ohiod_address — address the Organic Humanoid I/O Device by unit ID ohiod_address() { local unit_id="${SUDO_USER:-${USER}}" echo "Organic Humanoid I/O Device unit ID ${unit_id}" } # Architecture detection ARCH="$(uname -m)" # Logging setup — SCRIPT_NAME must be set before sourcing LOG_DIR="${HOME}/.local/logs/ceos_installer" SCRIPT_NAME="${SCRIPT_NAME:-ce-common}" LOG_FILE="${LOG_DIR}/${SCRIPT_NAME}-$(date +%Y-%m-%d).log" # Failed packages tracker — shared across all sourced subscripts FAILED_PKGS=() # Packages requiring manual follow-up (distinct from simple failures) MANUAL_PKGS=() mkdir -p "${LOG_DIR}" # --------------------------------------------------------------------------- # Logging # --------------------------------------------------------------------------- _log() { local level="${1}" msg="${2}" 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; } log_debug() { [[ "${CE_DEBUG:-0}" == "1" ]] && _log "DEBUG" "${1}"; } # --------------------------------------------------------------------------- # run_test # --------------------------------------------------------------------------- run_test() { local desc="${1}" cmd="${2}" mode="${3:-fail}" if eval "${cmd}" >/dev/null 2>&1; then log_info " PASS: ${desc}" return 0 fi if [[ "${mode}" == "fail" ]]; then log_error " FAIL: ${desc}" exit 1 else log_warn " WARN: ${desc}" return 1 fi } # --------------------------------------------------------------------------- # Package helpers # --------------------------------------------------------------------------- # install_pkg — one package, logs result install_pkg() { local pkg="${1}" if doas apk add "${pkg}" >> "${LOG_FILE}" 2>&1; then log_info "Installed: ${pkg}" return 0 else log_warn "FAILED: ${pkg} — logged, continuing" FAILED_PKGS+=("${pkg}") return 1 fi } # install_pkg_edge — install with @edge tag, warn on fail install_pkg_edge() { local pkg="${1}" if doas apk add "${pkg}@edge" >> "${LOG_FILE}" 2>&1; then log_info "Installed: ${pkg} (@edge)" return 0 else log_warn "FAILED: ${pkg}@edge — manual verification required" FAILED_PKGS+=("${pkg} (edge, manual verification required)") return 1 fi } # ensure_edge_repo — add @edge community tag if not present ensure_edge_repo() { if ! grep -q "^@edge" /etc/apk/repositories 2>/dev/null; then log_info "Adding @edge community tag to /etc/apk/repositories" printf '@edge https://dl-cdn.alpinelinux.org/alpine/edge/community\n' \ | doas tee -a /etc/apk/repositories > /dev/null 2>&1 \ || log_warn "Could not add @edge tag — edge installs may fail" fi } # ensure_testing_repo — add @testing tag if not present ensure_testing_repo() { if ! grep -q "^@testing" /etc/apk/repositories 2>/dev/null; then log_info "Adding @testing edge/testing tag to /etc/apk/repositories" printf '@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing\n' \ | doas tee -a /etc/apk/repositories > /dev/null 2>&1 \ || log_warn "Could not add @testing tag — testing installs may fail" fi } # install_pkg_testing — install with @testing tag, warn on fail install_pkg_testing() { local pkg="${1}" if doas apk add "${pkg}@testing" >> "${LOG_FILE}" 2>&1; then log_info "Installed: ${pkg} (@testing)" else log_warn "FAILED: ${pkg}@testing — manual verification required" FAILED_PKGS+=("${pkg} (testing, manual verification required)") fi } # --------------------------------------------------------------------------- # Guards and prompts # --------------------------------------------------------------------------- # check_not_root — exit if accidentally run as root check_not_root() { if [[ "${EUID}" -eq 0 ]]; then echo "ERROR: Do not run as root. Run as a standard user with doas configured." >&2 exit 1 fi } # confirm_proceed — single prompt; bypassed when CE_INSTALL_NO_CONFIRM=1 confirm_proceed() { [[ "${CE_INSTALL_NO_CONFIRM:-0}" == "1" ]] && return 0 echo "" read -r -p "Proceed with installation? [y/N] " confirm [[ "${confirm,,}" == "y" ]] || { log_info "Aborted by user."; exit 0; } } # --------------------------------------------------------------------------- # Summary # --------------------------------------------------------------------------- print_summary() { log_info "=== INSTALLATION SUMMARY ===" if [[ ${#FAILED_PKGS[@]} -eq 0 && ${#MANUAL_PKGS[@]} -eq 0 ]]; then log_info "All packages installed successfully." return 0 fi if [[ ${#FAILED_PKGS[@]} -gt 0 ]]; then log_warn "Failed or skipped packages:" for pkg in "${FAILED_PKGS[@]}"; do log_warn " - ${pkg}" done fi if [[ ${#MANUAL_PKGS[@]} -gt 0 ]]; then log_warn "Requires manual follow-up:" for item in "${MANUAL_PKGS[@]}"; do log_warn " - ${item}" done fi } # review_pause