dev/common.sh

252 lines
6.2 KiB
Bash

#!/usr/bin/env bash
# Script Standards and Common Functions
# Source this file in your scripts for consistent behavior
# ==============================================================================
# STANDARD SCRIPT HEADER
# ==============================================================================
# All scripts should start with:
# #!/usr/bin/env bash
# # NAME: Brief description of what the script does
# # REQUIRES: sudo interactive (if needed)
#
# set -euo pipefail
#
# # Source common functions (adjust path as needed)
# source "$(dirname "$0")/common.sh" 2>/dev/null || true
# ==============================================================================
# CONFIGURATION
# ==============================================================================
readonly SCRIPT_NAME="${0##*/}"
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Colors for output (only if terminal supports it)
if [[ -t 1 ]] && command -v tput >/dev/null 2>&1; then
readonly RED=$(tput setaf 1)
readonly GREEN=$(tput setaf 2)
readonly YELLOW=$(tput setaf 3)
readonly BLUE=$(tput setaf 4)
readonly PURPLE=$(tput setaf 5)
readonly CYAN=$(tput setaf 6)
readonly WHITE=$(tput setaf 7)
readonly BOLD=$(tput bold)
readonly RESET=$(tput sgr0)
else
readonly RED="" GREEN="" YELLOW="" BLUE="" PURPLE="" CYAN="" WHITE="" BOLD="" RESET=""
fi
# ==============================================================================
# LOGGING FUNCTIONS
# ==============================================================================
log_info() {
printf "${GREEN}[INFO]${RESET} %s\n" "$*"
}
log_warn() {
printf "${YELLOW}[WARN]${RESET} %s\n" "$*" >&2
}
log_error() {
printf "${RED}[ERROR]${RESET} %s\n" "$*" >&2
}
log_success() {
printf "${GREEN}[SUCCESS]${RESET} %s\n" "$*"
}
log_debug() {
if [[ "${DEBUG:-0}" == "1" ]]; then
printf "${CYAN}[DEBUG]${RESET} %s\n" "$*" >&2
fi
}
log_sudo() {
printf "${PURPLE}[SUDO]${RESET} %s\n" "$*"
}
# ==============================================================================
# UTILITY FUNCTIONS
# ==============================================================================
command_exists() {
command -v "$1" >/dev/null 2>&1
}
is_root() {
[[ $EUID -eq 0 ]]
}
require_root() {
if ! is_root; then
log_error "This script requires root privileges"
log_info "Run with: sudo $0 $*"
exit 1
fi
}
# Check if running in interactive terminal
is_interactive() {
[[ -t 0 && -t 1 ]]
}
# ==============================================================================
# CONFIRMATION FUNCTIONS
# ==============================================================================
confirm() {
local prompt="${1:-Continue?}"
local default="${2:-n}"
local response
if ! is_interactive; then
log_warn "Non-interactive mode, using default: $default"
[[ "$default" == "y" ]]
return $?
fi
while true; do
if [[ "$default" == "y" ]]; then
printf "%s [Y/n]: " "$prompt"
else
printf "%s [y/N]: " "$prompt"
fi
read -r response
response=${response,,} # Convert to lowercase
case "$response" in
"")
[[ "$default" == "y" ]]
return $?
;;
y | yes)
return 0
;;
n | no)
return 1
;;
*)
log_warn "Please answer 'y' or 'n'"
;;
esac
done
}
# Show changes and confirm
confirm_change() {
local file="$1"
local description="$2"
local temp_file="$3"
log_info "Proposed changes for $description:"
log_info "File: $file"
echo
if command_exists colordiff; then
colordiff -u "$file" "$temp_file" 2>/dev/null || diff -u "$file" "$temp_file" 2>/dev/null || true
else
diff -u "$file" "$temp_file" 2>/dev/null || true
fi
echo
confirm "Apply these changes?"
}
# ==============================================================================
# FILE OPERATIONS
# ==============================================================================
backup_file() {
local file="$1"
local backup_suffix="${2:-$(date +%Y%m%d_%H%M%S)}"
local backup_file="${file}.backup.${backup_suffix}"
if [[ -f "$file" ]]; then
cp "$file" "$backup_file"
log_info "Created backup: $backup_file"
echo "$backup_file"
fi
}
create_temp_file() {
local template="${1:-tmp.XXXXXX}"
mktemp "/tmp/${template}"
}
# ==============================================================================
# PACKAGE MANAGEMENT
# ==============================================================================
install_packages() {
local packages=("$@")
if [[ ${#packages[@]} -eq 0 ]]; then
log_warn "No packages specified"
return 1
fi
log_info "Installing packages: ${packages[*]}"
if command_exists paru; then
paru -S --needed --noconfirm "${packages[@]}"
elif command_exists pacman; then
sudo pacman -S --needed --noconfirm "${packages[@]}"
else
log_error "No supported package manager found"
return 1
fi
}
# ==============================================================================
# SERVICE MANAGEMENT
# ==============================================================================
enable_service() {
local service="$1"
local user_service="${2:-false}"
if [[ "$user_service" == "true" ]]; then
log_info "Enabling user service: $service"
systemctl --user enable --now "$service"
else
log_info "Enabling system service: $service"
sudo systemctl enable --now "$service"
fi
}
# ==============================================================================
# ERROR HANDLING
# ==============================================================================
cleanup() {
local exit_code=$?
# Add any cleanup operations here
exit $exit_code
}
# Set up trap for cleanup
trap cleanup EXIT INT TERM
# ==============================================================================
# SCRIPT INITIALIZATION
# ==============================================================================
init_script() {
log_info "Starting $SCRIPT_NAME"
# Set DEBUG mode if requested
if [[ "${1:-}" == "--debug" ]]; then
export DEBUG=1
log_debug "Debug mode enabled"
shift
fi
}
# ==============================================================================
# SCRIPT COMPLETION
# ==============================================================================
finish_script() {
local exit_code="${1:-0}"
if [[ "$exit_code" -eq 0 ]]; then
log_success "$SCRIPT_NAME completed successfully"
else
log_error "$SCRIPT_NAME failed with exit code $exit_code"
fi
exit "$exit_code"
}