216 lines
4.4 KiB
Bash
Executable File
216 lines
4.4 KiB
Bash
Executable File
#!/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
|