#!/bin/bash # # Common Library Functions for Deployment Scripts # Provides unified logging, error handling, and utilities # set -euo pipefail # Colors for output readonly RED='\033[0;31m' readonly GREEN='\033[0;32m' readonly YELLOW='\033[1;33m' readonly BLUE='\033[0;34m' readonly CYAN='\033[0;36m' readonly MAGENTA='\033[0;35m' readonly NC='\033[0m' # No Color # Logging functions log_info() { echo -e "${BLUE}ℹ️ ${1}${NC}" } log_success() { echo -e "${GREEN}✅ ${1}${NC}" } log_warning() { echo -e "${YELLOW}⚠️ ${1}${NC}" } log_error() { echo -e "${RED}❌ ${1}${NC}" } log_debug() { if [[ "${DEBUG:-0}" == "1" ]]; then echo -e "${CYAN}🔍 ${1}${NC}" fi } log_step() { echo -e "${MAGENTA}▶️ ${1}${NC}" } # Error handling die() { log_error "$1" exit "${2:-1}" } # Check if command exists command_exists() { command -v "$1" &> /dev/null } # Validate prerequisites require_command() { local cmd="$1" local install_hint="${2:-}" if ! command_exists "$cmd"; then log_error "Required command not found: $cmd" [[ -n "$install_hint" ]] && log_info "Install with: $install_hint" return 1 fi return 0 } # Run command with retry logic run_with_retry() { local max_attempts="${1}" local delay="${2}" shift 2 local cmd=("$@") local attempt=1 while [[ $attempt -le $max_attempts ]]; do if "${cmd[@]}"; then return 0 fi if [[ $attempt -lt $max_attempts ]]; then log_warning "Command failed (attempt $attempt/$max_attempts). Retrying in ${delay}s..." sleep "$delay" fi ((attempt++)) done log_error "Command failed after $max_attempts attempts" return 1 } # Execute command and capture output execute() { local cmd="$1" log_debug "Executing: $cmd" eval "$cmd" } # Spinner for long-running operations spinner() { local pid=$1 local delay=0.1 local spinstr='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏' while ps -p "$pid" > /dev/null 2>&1; do local temp=${spinstr#?} printf " [%c] " "$spinstr" local spinstr=$temp${spinstr%"$temp"} sleep $delay printf "\b\b\b\b\b\b" done printf " \b\b\b\b" } # Progress bar progress_bar() { local current=$1 local total=$2 local width=50 local percentage=$((current * 100 / total)) local completed=$((width * current / total)) local remaining=$((width - completed)) printf "\r[" printf "%${completed}s" | tr ' ' '█' printf "%${remaining}s" | tr ' ' '░' printf "] %3d%%" "$percentage" if [[ $current -eq $total ]]; then echo "" fi } # Confirm action confirm() { local prompt="${1:-Are you sure?}" local default="${2:-n}" if [[ "$default" == "y" ]]; then prompt="$prompt [Y/n] " else prompt="$prompt [y/N] " fi read -rp "$prompt" response response=${response:-$default} [[ "$response" =~ ^[Yy]$ ]] } # Parse YAML-like config parse_config() { local config_file="$1" local key="$2" if [[ ! -f "$config_file" ]]; then log_error "Config file not found: $config_file" return 1 fi grep "^${key}:" "$config_file" | sed "s/^${key}:[[:space:]]*//" | tr -d '"' } # Timestamp functions timestamp() { date '+%Y-%m-%d %H:%M:%S' } timestamp_file() { date '+%Y%m%d_%H%M%S' } # Duration calculation duration() { local start=$1 local end=${2:-$(date +%s)} local elapsed=$((end - start)) local hours=$((elapsed / 3600)) local minutes=$(((elapsed % 3600) / 60)) local seconds=$((elapsed % 60)) if [[ $hours -gt 0 ]]; then printf "%dh %dm %ds" "$hours" "$minutes" "$seconds" elif [[ $minutes -gt 0 ]]; then printf "%dm %ds" "$minutes" "$seconds" else printf "%ds" "$seconds" fi } # Cleanup handler cleanup_handlers=() register_cleanup() { cleanup_handlers+=("$1") } cleanup() { log_info "Running cleanup handlers..." for handler in "${cleanup_handlers[@]}"; do eval "$handler" || log_warning "Cleanup handler failed: $handler" done } trap cleanup EXIT # Export functions for use in other scripts export -f log_info log_success log_warning log_error log_debug log_step export -f die command_exists require_command run_with_retry execute export -f spinner progress_bar confirm parse_config export -f timestamp timestamp_file duration export -f register_cleanup cleanup