schon/scripts/lib/utils.sh
fureunoir 42b40627de Features: 1) Introduce CLI utility lessy.py to streamline project management tasks (e.g., install, run, restart, test); 2) Add Unix and Windows script commands for make-messages and compile-messages to improve translation workflow; 3) Include shared utility libraries (utils.sh, utils.ps1) for reusable functions across scripts.
Fixes: 1) Remove obsolete `reboot` scripts for Unix and Windows to prevent redundancy; 2) Update Windows `test.ps1` to handle omitted coverage patterns and improve error feedback.

Extra: 1) Refactor Windows scripts (`make-messages.ps1`, `compile-messages.ps1`, `backup.ps1`) to use shared utilities for better consistency and output formatting; 2) Add spinner-based progress indicators to enhance user experience in interactive environments.
2026-01-04 19:18:27 +03:00

223 lines
5.1 KiB
Bash

#!/usr/bin/env bash
# Shared utilities for Unix scripts
# Provides: colors, progress indicators, interactive detection
# Detect if running in interactive shell
is_interactive() {
[[ -t 0 && -t 1 ]]
}
# Color definitions (only used in interactive mode)
if is_interactive && [[ "${NO_COLOR:-}" != "1" ]]; then
COLOR_RESET='\033[0m'
COLOR_RED='\033[0;31m'
COLOR_GREEN='\033[0;32m'
COLOR_YELLOW='\033[0;33m'
COLOR_BLUE='\033[0;34m'
COLOR_MAGENTA='\033[0;35m'
COLOR_CYAN='\033[0;36m'
COLOR_GRAY='\033[0;90m'
COLOR_BOLD='\033[1m'
else
COLOR_RESET=''
COLOR_RED=''
COLOR_GREEN=''
COLOR_YELLOW=''
COLOR_BLUE=''
COLOR_MAGENTA=''
COLOR_CYAN=''
COLOR_GRAY=''
COLOR_BOLD=''
fi
# Logging functions
log_info() {
echo -e "${COLOR_BLUE}${1}${COLOR_RESET}"
}
log_success() {
echo -e "${COLOR_GREEN}${1}${COLOR_RESET}"
}
log_warning() {
echo -e "${COLOR_YELLOW}${1}${COLOR_RESET}"
}
log_error() {
echo -e "${COLOR_RED}${1}${COLOR_RESET}" >&2
}
log_step() {
echo -e "${COLOR_MAGENTA}${1}${COLOR_RESET}"
}
log_result() {
echo -e "${COLOR_CYAN}${1}${COLOR_RESET}"
}
# Spinner animation (only for interactive shells)
SPINNER_FRAMES=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
SPINNER_PID=""
start_spinner() {
local message="${1:-Processing...}"
if ! is_interactive; then
echo "$message"
return
fi
{
local i=0
while true; do
printf "\r${COLOR_CYAN}${SPINNER_FRAMES[$i]}${COLOR_RESET} %s" "$message"
i=$(( (i + 1) % ${#SPINNER_FRAMES[@]} ))
sleep 0.1
done
} &
SPINNER_PID=$!
# Ensure spinner is cleaned up on script exit
trap "stop_spinner" EXIT INT TERM
}
stop_spinner() {
if [[ -n "$SPINNER_PID" ]] && kill -0 "$SPINNER_PID" 2>/dev/null; then
kill "$SPINNER_PID" 2>/dev/null
wait "$SPINNER_PID" 2>/dev/null
SPINNER_PID=""
fi
if is_interactive; then
printf "\r\033[K" # Clear the spinner line
fi
}
update_spinner_message() {
local message="${1:-Processing...}"
if ! is_interactive; then
echo "$message"
return
fi
if [[ -n "$SPINNER_PID" ]] && kill -0 "$SPINNER_PID" 2>/dev/null; then
stop_spinner
start_spinner "$message"
fi
}
# Execute command with progress indicator
run_with_progress() {
local message="$1"
shift
local cmd=("$@")
if is_interactive; then
start_spinner "$message"
local output
local exit_code
# Capture output and exit code
output=$("${cmd[@]}" 2>&1)
exit_code=$?
stop_spinner
if [[ $exit_code -eq 0 ]]; then
log_success "$message - Done!"
else
log_error "$message - Failed!"
echo "$output"
fi
return $exit_code
else
# Non-interactive: just show message and run
echo "$message"
"${cmd[@]}"
local exit_code=$?
if [[ $exit_code -eq 0 ]]; then
echo "$message - Done!"
else
echo "$message - Failed!"
fi
return $exit_code
fi
}
# Check if command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Validate system requirements
check_system_requirements() {
local min_cpu="${1:-4}"
local min_ram_gb="${2:-6}"
local min_disk_gb="${3:-20}"
log_step "Checking system requirements..."
# Check CPU cores
local cpu_count
cpu_count=$(getconf _NPROCESSORS_ONLN)
if [[ "$cpu_count" -lt "$min_cpu" ]]; then
log_error "Insufficient CPU cores: $cpu_count (minimum: $min_cpu)"
return 1
fi
# Check RAM
local total_mem_gb
if [[ -f /proc/meminfo ]]; then
local mem_kb
mem_kb=$(grep MemTotal /proc/meminfo | awk '{print $2}')
total_mem_gb=$(awk "BEGIN {printf \"%.2f\", $mem_kb/1024/1024}")
else
local total_mem_bytes
total_mem_bytes=$(sysctl -n hw.memsize 2>/dev/null || echo "0")
total_mem_gb=$(awk "BEGIN {printf \"%.2f\", $total_mem_bytes/1024/1024/1024}")
fi
if ! awk "BEGIN {exit !($total_mem_gb >= $min_ram_gb)}"; then
log_error "Insufficient RAM: ${total_mem_gb}GB (minimum: ${min_ram_gb}GB)"
return 1
fi
# Check disk space
local avail_kb free_gb
avail_kb=$(df -k . | tail -1 | awk '{print $4}')
free_gb=$(awk "BEGIN {printf \"%.2f\", $avail_kb/1024/1024}")
if ! awk "BEGIN {exit !($free_gb >= $min_disk_gb)}"; then
log_error "Insufficient disk space: ${free_gb}GB (minimum: ${min_disk_gb}GB)"
return 1
fi
log_success "System requirements met: CPU cores=$cpu_count, RAM=${total_mem_gb}GB, FreeDisk=${free_gb}GB"
return 0
}
# Confirm action (returns 0 for yes, 1 for no)
confirm() {
local prompt="${1:-Are you sure?}"
local response
if ! is_interactive; then
# In non-interactive mode, assume yes
return 0
fi
read -r -p "$prompt [y/N]: " response
case "$response" in
[yY][eE][sS]|[yY])
return 0
;;
*)
return 1
;;
esac
}