You've already forked Atomcms-edit
feat: enterprise-grade update script with rollback, logging, health checks, notifications, dry-run
This commit is contained in:
+322
-161
@@ -1,59 +1,143 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Strict mode: exit on any error, undefined var, or pipe failure
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# Load .env from the same directory as this script
|
# =============================================================================
|
||||||
|
# EPIC WEB CONTROL — Enterprise Update Script
|
||||||
|
# Compatible with Laravel 13 + Nitro V3 + MariaDB
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
# --- Load .env ---------------------------------------------------------------
|
||||||
if [ -f "$SCRIPT_DIR/.env" ]; then
|
if [ -f "$SCRIPT_DIR/.env" ]; then
|
||||||
set -a
|
set -a
|
||||||
. "$SCRIPT_DIR/.env"
|
. "$SCRIPT_DIR/.env"
|
||||||
set +a
|
set +a
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Use CMS APP_URL as fallback for NITRO_SITE_URL, then prompt if still unset
|
# --- Logging -----------------------------------------------------------------
|
||||||
|
LOG_DIR="${NITRO_LOG_DIR:-$SCRIPT_DIR/storage/logs}"
|
||||||
|
mkdir -p "$LOG_DIR"
|
||||||
|
LOG_FILE="$LOG_DIR/update-$(date +%Y%m%d-%H%M%S).log"
|
||||||
|
exec > >(tee -a "$LOG_FILE") 2>&1
|
||||||
|
|
||||||
|
STEP_NUM=0
|
||||||
|
STEP_TOTAL=8
|
||||||
|
START_TIME=$(date +%s)
|
||||||
|
|
||||||
|
step() {
|
||||||
|
STEP_NUM=$((STEP_NUM + 1))
|
||||||
|
echo ""
|
||||||
|
echo "╔══════════════════════════════════════════════════════════════╗"
|
||||||
|
printf "║ Step %d/%d — %-49s║\n" "$STEP_NUM" "$STEP_TOTAL" "$1"
|
||||||
|
echo "╚══════════════════════════════════════════════════════════════╝"
|
||||||
|
}
|
||||||
|
|
||||||
|
info() { echo " --> $1"; }
|
||||||
|
ok() { echo " [OK] $1"; }
|
||||||
|
warn() { echo " [WARN] $1"; }
|
||||||
|
fail() { echo " [FAIL] $1"; }
|
||||||
|
die() { echo ""; echo "=== ❌ $1 ==="; cleanup_notify_failure "$1"; exit 1; }
|
||||||
|
|
||||||
|
# --- Notifications -----------------------------------------------------------
|
||||||
|
NOTIFY_URL="${NITRO_NOTIFY_URL:-}"
|
||||||
|
NOTIFY_FAILED=false
|
||||||
|
|
||||||
|
notify() {
|
||||||
|
local status="$1"
|
||||||
|
local message="$2"
|
||||||
|
[ -z "$NOTIFY_URL" ] && return 0
|
||||||
|
local elapsed=$(( $(date +%s) - START_TIME ))
|
||||||
|
local elapsed_fmt
|
||||||
|
elapsed_fmt=$(printf '%dm %ds' $((elapsed/60)) $((elapsed%60)))
|
||||||
|
curl -s -o /dev/null -X POST "$NOTIFY_URL" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"text\": \"[Nitro Update] $status\",
|
||||||
|
\"attachments\": [{
|
||||||
|
\"color\": \"$([ "$status" = "SUCCESS" ] && echo \"good\" || echo \"danger\")\",
|
||||||
|
\"fields\": [
|
||||||
|
{\"title\": \"Status\", \"value\": \"$message\", \"short\": true},
|
||||||
|
{\"title\": \"Duration\", \"value\": \"$elapsed_fmt\", \"short\": true},
|
||||||
|
{\"title\": \"Server\", \"value\": \"$(hostname)\", \"short\": true},
|
||||||
|
{\"title\": \"Log\", \"value\": \"$LOG_FILE\", \"short\": false}
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
}" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_notify_failure() {
|
||||||
|
$NOTIFY_FAILED && return
|
||||||
|
NOTIFY_FAILED=true
|
||||||
|
notify "FAILED" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Rollback support --------------------------------------------------------
|
||||||
|
LAST_BACKUP=""
|
||||||
|
ROLLBACK_NEEDED=false
|
||||||
|
|
||||||
|
rollback_db() {
|
||||||
|
[ -z "$LAST_BACKUP" ] && { warn "No backup file known — cannot rollback DB."; return 1; }
|
||||||
|
[ ! -f "$LAST_BACKUP" ] && { warn "Backup file not found: $LAST_BACKUP"; return 1; }
|
||||||
|
info "Rolling back database from: $LAST_BACKUP"
|
||||||
|
mariadb $MYSQL_CRED "$DB_NAME" < "$LAST_BACKUP" && ok "Database restored." || warn "Rollback failed."
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_on_exit() {
|
||||||
|
local exit_code=$?
|
||||||
|
if [ $exit_code -ne 0 ] && [ "$ROLLBACK_NEEDED" = true ]; then
|
||||||
|
echo ""
|
||||||
|
echo "=== ⚠️ Update failed — initiating rollback ==="
|
||||||
|
rollback_db
|
||||||
|
fi
|
||||||
|
[ $exit_code -ne 0 ] && cleanup_notify_failure "Script exited with code $exit_code"
|
||||||
|
}
|
||||||
|
|
||||||
|
trap cleanup_on_exit EXIT
|
||||||
|
trap 'echo ""; die "Interrupted by user"' SIGINT SIGTERM
|
||||||
|
|
||||||
|
# --- Pre-flight: interactive prompts (must be before unbuffer) ---------------
|
||||||
|
|
||||||
|
# Site URL
|
||||||
if [ -z "${NITRO_SITE_URL:-}" ] && [ -n "${APP_URL:-}" ]; then
|
if [ -z "${NITRO_SITE_URL:-}" ] && [ -n "${APP_URL:-}" ]; then
|
||||||
NITRO_SITE_URL="$APP_URL"
|
NITRO_SITE_URL="$APP_URL"
|
||||||
echo "--> Using APP_URL from .env: $NITRO_SITE_URL"
|
info "Using APP_URL from .env: $NITRO_SITE_URL"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "${NITRO_SITE_URL:-}" ]; then
|
if [ -z "${NITRO_SITE_URL:-}" ]; then
|
||||||
read -r -p " Enter your site URL (e.g. https://example.com): " NITRO_SITE_URL
|
read -r -p " Enter your site URL (e.g. https://example.com): " NITRO_SITE_URL
|
||||||
NITRO_SITE_URL="${NITRO_SITE_URL%/}"
|
NITRO_SITE_URL="${NITRO_SITE_URL%/}"
|
||||||
if [ -z "$NITRO_SITE_URL" ]; then
|
[ -z "$NITRO_SITE_URL" ] && die "NITRO_SITE_URL is required"
|
||||||
echo "=== ❌ NITRO_SITE_URL is required. Set it in .env or enter it now. ==="
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
export NITRO_SITE_URL
|
export NITRO_SITE_URL
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Prompt for branch if not set in .env, default to main
|
# Branch
|
||||||
if [ -z "${NITRO_BRANCH:-}" ]; then
|
if [ -z "${NITRO_BRANCH:-}" ]; then
|
||||||
read -r -p " Enter branch (main/dev) [main]: " NITRO_BRANCH
|
read -r -p " Enter branch (main/dev) [main]: " NITRO_BRANCH
|
||||||
NITRO_BRANCH="${NITRO_BRANCH:-main}"
|
NITRO_BRANCH="${NITRO_BRANCH:-main}"
|
||||||
case "$NITRO_BRANCH" in
|
case "$NITRO_BRANCH" in main|dev) ;; *) die "Invalid branch '$NITRO_BRANCH'. Use main or dev." ;; esac
|
||||||
main|dev) ;;
|
|
||||||
*) echo "=== ❌ Invalid branch '$NITRO_BRANCH'. Choose 'main' or 'dev'. ==="; exit 1 ;;
|
|
||||||
esac
|
|
||||||
export NITRO_BRANCH
|
export NITRO_BRANCH
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Real-time output via pseudo-terminal (unbuffer from expect)
|
# Dry-run mode
|
||||||
|
DRY_RUN=false
|
||||||
|
if [ "${1:-}" = "--dry-run" ] || [ "${1:-}" = "-n" ]; then
|
||||||
|
DRY_RUN=true
|
||||||
|
echo ""
|
||||||
|
info "DRY-RUN mode: no changes will be made"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Unbuffer re-exec --------------------------------------------------------
|
||||||
if [ -z "${_UNBUFFERED:-}" ] && command -v unbuffer &> /dev/null; then
|
if [ -z "${_UNBUFFERED:-}" ] && command -v unbuffer &> /dev/null; then
|
||||||
export _UNBUFFERED=1
|
export _UNBUFFERED=1
|
||||||
exec unbuffer bash "$0" "$@"
|
exec unbuffer bash "$0" "$@"
|
||||||
fi
|
fi
|
||||||
exec 2>&1
|
|
||||||
|
|
||||||
# Single-instance lock via flock
|
# --- Single-instance lock ----------------------------------------------------
|
||||||
LOCKFILE="/tmp/$(basename "$0").lock"
|
LOCKFILE="/tmp/$(basename "$0").lock"
|
||||||
exec 200>"$LOCKFILE"
|
exec 200>"$LOCKFILE"
|
||||||
flock -n 200 || { echo "=== ❌ Another instance already running, exiting ==="; exit 1; }
|
flock -n 200 || die "Another instance is already running"
|
||||||
|
|
||||||
# Trap for clean error messages
|
# --- Configuration -----------------------------------------------------------
|
||||||
trap 'echo "=== ❌ ERROR: Update failed at line $LINENO (command: $BASH_COMMAND) ===" >&2; exit 1' ERR
|
|
||||||
|
|
||||||
# --- CONFIGURATION (from env vars, with defaults) ---
|
|
||||||
DB_NAME="${NITRO_DB_NAME:-habbo}"
|
DB_NAME="${NITRO_DB_NAME:-habbo}"
|
||||||
DB_HOST="${NITRO_DB_HOST:-127.0.0.1}"
|
DB_HOST="${NITRO_DB_HOST:-127.0.0.1}"
|
||||||
DB_PORT="${NITRO_DB_PORT:-3306}"
|
DB_PORT="${NITRO_DB_PORT:-3306}"
|
||||||
@@ -68,15 +152,18 @@ BACKUP_DIR="${NITRO_BACKUP_DIR:-$EMULATOR_DIR/Database Updates/backups}"
|
|||||||
NITRO_CLIENT="${NITRO_CLIENT_SRC:-/var/www/Nitro-V3}"
|
NITRO_CLIENT="${NITRO_CLIENT_SRC:-/var/www/Nitro-V3}"
|
||||||
NITRO_RENDERER="${NITRO_RENDERER_SRC:-/var/www/Nitro_Render_V3}"
|
NITRO_RENDERER="${NITRO_RENDERER_SRC:-/var/www/Nitro_Render_V3}"
|
||||||
NITRO_BRANCH="${NITRO_BRANCH:-main}"
|
NITRO_BRANCH="${NITRO_BRANCH:-main}"
|
||||||
|
MIN_DISK_GB="${NITRO_MIN_DISK_GB:-5}"
|
||||||
|
HEALTH_RETRIES="${NITRO_HEALTH_RETRIES:-12}"
|
||||||
|
HEALTH_INTERVAL="${NITRO_HEALTH_INTERVAL:-5}"
|
||||||
|
|
||||||
# Derive ws/wss protocol and domain from site URL
|
# Derive ws/wss protocol and domain
|
||||||
case "$NITRO_SITE_URL" in
|
case "$NITRO_SITE_URL" in
|
||||||
https://*) NITRO_WS_PROTO="wss://" ; NITRO_DOMAIN="${NITRO_SITE_URL#https://}" ;;
|
https://*) NITRO_WS_PROTO="wss://" ; NITRO_DOMAIN="${NITRO_SITE_URL#https://}" ;;
|
||||||
http://*) NITRO_WS_PROTO="ws://" ; NITRO_DOMAIN="${NITRO_SITE_URL#http://}" ;;
|
http://*) NITRO_WS_PROTO="ws://" ; NITRO_DOMAIN="${NITRO_SITE_URL#http://}" ;;
|
||||||
*) NITRO_WS_PROTO="wss://" ; NITRO_DOMAIN="$NITRO_SITE_URL" ;;
|
*) NITRO_WS_PROTO="wss://" ; NITRO_DOMAIN="$NITRO_SITE_URL" ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Critical URLs (override via NITRO_* env vars, auto-derived otherwise)
|
# Critical URLs (override via NITRO_* env vars)
|
||||||
NITRO_IMAGE_LIBRARY_URL="${NITRO_IMAGE_LIBRARY_URL:-$NITRO_SITE_URL/gamedata/c_images/}"
|
NITRO_IMAGE_LIBRARY_URL="${NITRO_IMAGE_LIBRARY_URL:-$NITRO_SITE_URL/gamedata/c_images/}"
|
||||||
NITRO_HOF_FURNITURE_URL="${NITRO_HOF_FURNITURE_URL:-$NITRO_SITE_URL/gamedata/icons}"
|
NITRO_HOF_FURNITURE_URL="${NITRO_HOF_FURNITURE_URL:-$NITRO_SITE_URL/gamedata/icons}"
|
||||||
NITRO_API_URL="${NITRO_API_URL:-$NITRO_SITE_URL}"
|
NITRO_API_URL="${NITRO_API_URL:-$NITRO_SITE_URL}"
|
||||||
@@ -86,13 +173,22 @@ NITRO_GAMEDATA_URL="${NITRO_GAMEDATA_URL:-$NITRO_SITE_URL/gamedata}"
|
|||||||
NITRO_ASSET_URL="${NITRO_ASSET_URL:-$NITRO_SITE_URL/gamedata/bundled}"
|
NITRO_ASSET_URL="${NITRO_ASSET_URL:-$NITRO_SITE_URL/gamedata/bundled}"
|
||||||
NITRO_FURNI_ASSET_ICON_URL="${NITRO_FURNI_ASSET_ICON_URL:-$NITRO_SITE_URL/gamedata/icons/%libname%%param%_icon.png}"
|
NITRO_FURNI_ASSET_ICON_URL="${NITRO_FURNI_ASSET_ICON_URL:-$NITRO_SITE_URL/gamedata/icons/%libname%%param%_icon.png}"
|
||||||
|
|
||||||
# Build MySQL/MariaDB credentials argument (password via MYSQL_PWD — not visible in ps)
|
# MySQL credentials
|
||||||
MYSQL_CRED="-h $DB_HOST -P $DB_PORT -u $DB_USER --ssl-verify-server-cert=OFF"
|
MYSQL_CRED="-h $DB_HOST -P $DB_PORT -u $DB_USER --ssl-verify-server-cert=OFF"
|
||||||
if [ -n "$DB_PASS" ]; then
|
[ -n "$DB_PASS" ] && export MYSQL_PWD="$DB_PASS"
|
||||||
export MYSQL_PWD="$DB_PASS"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Verify all required directories exist before starting
|
# =============================================================================
|
||||||
|
# PRE-FLIGHT CHECKS
|
||||||
|
# =============================================================================
|
||||||
|
step "Pre-flight Checks"
|
||||||
|
|
||||||
|
info "Checking required commands..."
|
||||||
|
for cmd in git mariadb mariadb-dump mvn node python3 yarn; do
|
||||||
|
command -v "$cmd" &>/dev/null || die "Required command not found: $cmd"
|
||||||
|
done
|
||||||
|
ok "All required commands available"
|
||||||
|
|
||||||
|
info "Checking directories..."
|
||||||
REQUIRED_DIRS=(
|
REQUIRED_DIRS=(
|
||||||
"$EMULATOR_DIR/Emulator"
|
"$EMULATOR_DIR/Emulator"
|
||||||
"$NITRO_RENDERER"
|
"$NITRO_RENDERER"
|
||||||
@@ -100,13 +196,40 @@ REQUIRED_DIRS=(
|
|||||||
"$NITRO_SRC_DIR"
|
"$NITRO_SRC_DIR"
|
||||||
)
|
)
|
||||||
for dir in "${REQUIRED_DIRS[@]}"; do
|
for dir in "${REQUIRED_DIRS[@]}"; do
|
||||||
if [ ! -d "$dir" ]; then
|
[ -d "$dir" ] || die "Required directory not found: $dir"
|
||||||
echo "=== ❌ Required directory not found: $dir ==="
|
ok "Found: $dir"
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
|
|
||||||
# Helper: forcefully remove node_modules (with sudo fallback) and restore owner
|
info "Checking disk space..."
|
||||||
|
AVAIL_KB=$(df --output=avail "$EMULATOR_DIR" 2>/dev/null | tail -1)
|
||||||
|
AVAIL_GB=$(( AVAIL_KB / 1024 / 1024 ))
|
||||||
|
[ "$AVAIL_GB" -lt "$MIN_DISK_GB" ] && die "Only ${AVAIL_GB}GB free on $EMULATOR_DIR (min ${MIN_DISK_GB}GB required)"
|
||||||
|
ok "${AVAIL_GB}GB disk space available"
|
||||||
|
|
||||||
|
info "Checking database connection..."
|
||||||
|
mariadb $MYSQL_CRED -e "SELECT 1" "$DB_NAME" &>/dev/null || die "Cannot connect to database $DB_NAME on $DB_HOST:$DB_PORT"
|
||||||
|
ok "Database connection OK"
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = true ]; then
|
||||||
|
echo ""
|
||||||
|
warn "DRY-RUN — skipping actual update"
|
||||||
|
echo " Site: $NITRO_SITE_URL"
|
||||||
|
echo " Branch: $NITRO_BRANCH"
|
||||||
|
echo " Emulator: $EMULATOR_DIR/Emulator"
|
||||||
|
echo " Nitro-V3: $NITRO_CLIENT"
|
||||||
|
echo " Renderer: $NITRO_RENDERER"
|
||||||
|
echo ""
|
||||||
|
info "Dry-run complete. Pass --dry-run or -n to preview."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
info "Site: $NITRO_SITE_URL | Branch: $NITRO_BRANCH"
|
||||||
|
info "Log: $LOG_FILE"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# HELPERS
|
||||||
|
# =============================================================================
|
||||||
clean_node_modules() {
|
clean_node_modules() {
|
||||||
rm -rf node_modules 2>/dev/null || sudo rm -rf node_modules 2>/dev/null || true
|
rm -rf node_modules 2>/dev/null || sudo rm -rf node_modules 2>/dev/null || true
|
||||||
if [ "$(stat -c '%U' .)" != "$(whoami)" ] && command -v sudo &> /dev/null; then
|
if [ "$(stat -c '%U' .)" != "$(whoami)" ] && command -v sudo &> /dev/null; then
|
||||||
@@ -114,7 +237,6 @@ clean_node_modules() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Helper: git stash → checkout → pull → return 0 if new commits, 1 otherwise
|
|
||||||
git_update() {
|
git_update() {
|
||||||
local repo="$1"
|
local repo="$1"
|
||||||
local branch="$2"
|
local branch="$2"
|
||||||
@@ -124,55 +246,60 @@ git_update() {
|
|||||||
old_head=$(git rev-parse HEAD)
|
old_head=$(git rev-parse HEAD)
|
||||||
git checkout "$branch"
|
git checkout "$branch"
|
||||||
git pull
|
git pull
|
||||||
if [ "$(git rev-parse HEAD)" != "$old_head" ]; then
|
[ "$(git rev-parse HEAD)" != "$old_head" ]
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "=== Starting EPIC WEB CONTROL Update ==="
|
|
||||||
echo "--> Site: $NITRO_SITE_URL | Branch: $NITRO_BRANCH"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
HAD_UPDATES=false
|
HAD_UPDATES=false
|
||||||
NITRO_BUILT=false
|
NITRO_BUILT=false
|
||||||
|
|
||||||
# ----------------------------------------
|
# =============================================================================
|
||||||
# 1. Update and Build Emulator
|
# 1. UPDATE & BUILD EMULATOR
|
||||||
# ----------------------------------------
|
# =============================================================================
|
||||||
echo "--> Updating Emulator..."
|
step "Update & Build Emulator"
|
||||||
|
|
||||||
if git_update "$EMULATOR_DIR/Emulator" "$NITRO_BRANCH"; then
|
if git_update "$EMULATOR_DIR/Emulator" "$NITRO_BRANCH"; then
|
||||||
echo "--> New commits detected, building emulator..."
|
info "New commits detected"
|
||||||
HAD_UPDATES=true
|
HAD_UPDATES=true
|
||||||
|
ROLLBACK_NEEDED=true
|
||||||
|
|
||||||
# Automatic Safe Database Backup
|
# Database backup
|
||||||
echo "--> Creating automatic database backup before update..."
|
info "Creating database backup..."
|
||||||
mkdir -p "$BACKUP_DIR"
|
mkdir -p "$BACKUP_DIR"
|
||||||
mariadb-dump $MYSQL_CRED --force --skip-lock-tables "$DB_NAME" > "$BACKUP_DIR/backup_$(date +%Y%m%d_%H%M%S).sql" || echo "--> Backup has missing tables (not critical) — update continues"
|
BACKUP_FILE="$BACKUP_DIR/backup_$(date +%Y%m%d_%H%M%S).sql"
|
||||||
|
if mariadb-dump $MYSQL_CRED --force --skip-lock-tables --routines --events --triggers "$DB_NAME" > "$BACKUP_FILE"; then
|
||||||
# Automatic SQL Import (exclude backup dir)
|
LAST_BACKUP="$BACKUP_FILE"
|
||||||
echo "--> Checking for new SQL files..."
|
BK_SIZE=$(stat -c%s "$BACKUP_FILE" 2>/dev/null || echo 0)
|
||||||
if [ -d "$SQL_DIR" ]; then
|
[ "$BK_SIZE" -lt 1024 ] && { rm -f "$BACKUP_FILE"; die "Backup is too small (${BK_SIZE}B) — possible corruption, aborting"; }
|
||||||
find "$SQL_DIR" -name "*.sql" -mmin -10 -not -path "$BACKUP_DIR/*" -print0 2>/dev/null | while IFS= read -r -d '' sql_file; do
|
ok "Backup saved: $(numfmt --to=iec "$BK_SIZE") — $BACKUP_FILE"
|
||||||
echo "--> Importing new SQL file: $(basename "$sql_file")"
|
|
||||||
mariadb $MYSQL_CRED --force "$DB_NAME" < "$sql_file" || echo "--> Error importing $(basename "$sql_file"), moving to next..."
|
|
||||||
done
|
|
||||||
else
|
else
|
||||||
echo "--> SQL directory not found, skipping SQL import."
|
die "Database backup failed"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# SQL imports
|
||||||
|
info "Checking for new SQL files..."
|
||||||
|
if [ -d "$SQL_DIR" ]; then
|
||||||
|
SQL_COUNT=0
|
||||||
|
while IFS= read -r -d '' sql_file; do
|
||||||
|
info "Importing: $(basename "$sql_file")"
|
||||||
|
mariadb $MYSQL_CRED --force "$DB_NAME" < "$sql_file" || warn "Import failed for $(basename "$sql_file")"
|
||||||
|
SQL_COUNT=$((SQL_COUNT + 1))
|
||||||
|
done < <(find "$SQL_DIR" -name '*.sql' -mmin -10 -not -path "$BACKUP_DIR/*" -print0 2>/dev/null)
|
||||||
|
[ "$SQL_COUNT" -gt 0 ] && ok "$SQL_COUNT SQL file(s) imported" || info "No new SQL files found"
|
||||||
|
else
|
||||||
|
info "SQL directory not found, skipping"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Maven build
|
||||||
|
info "Building emulator (mvn package)..."
|
||||||
cd "$EMULATOR_DIR/Emulator"
|
cd "$EMULATOR_DIR/Emulator"
|
||||||
mvn package
|
mvn package -q || die "Maven build failed"
|
||||||
|
ok "Build complete"
|
||||||
|
|
||||||
JAR_FILE=$(find target -maxdepth 1 -name 'Habbo-*-jar-with-dependencies.jar' -printf '%T@ %p\n' 2>/dev/null | sort -rn | sed -n '1s/^[0-9.]* //p' | xargs basename)
|
JAR_FILE=$(find target -maxdepth 1 -name 'Habbo-*-jar-with-dependencies.jar' -printf '%T@ %p\n' 2>/dev/null | sort -rn | sed -n '1s/^[0-9.]* //p' | xargs basename)
|
||||||
if [ -z "$JAR_FILE" ]; then
|
[ -z "$JAR_FILE" ] && die "No jar file found in target/"
|
||||||
echo "=== ❌ No jar file found with pattern: target/Habbo-*-jar-with-dependencies.jar ==="
|
ok "Jar: $JAR_FILE"
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "--> Found jar file: $JAR_FILE"
|
info "Updating emulator launch script..."
|
||||||
echo "--> Updating emulator launch file..."
|
|
||||||
cd target/
|
cd target/
|
||||||
cat << EOF > emulator
|
cat << EOF > emulator
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
@@ -183,88 +310,86 @@ mv /var/log/emu/emulator.log /var/log/emu/\$file_name
|
|||||||
java -Dfile.encoding=UTF8 -Xmx2G -jar $JAR_FILE
|
java -Dfile.encoding=UTF8 -Xmx2G -jar $JAR_FILE
|
||||||
EOF
|
EOF
|
||||||
chmod +x emulator
|
chmod +x emulator
|
||||||
|
ok "Launch script updated"
|
||||||
|
ROLLBACK_NEEDED=false
|
||||||
else
|
else
|
||||||
echo "--> Emulator already up to date, skipping build."
|
info "Already up to date, skipping"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
# ----------------------------------------
|
# 2. UPDATE NITRO_RENDER_V3
|
||||||
# 2. Update Nitro_Render_V3
|
# =============================================================================
|
||||||
# ----------------------------------------
|
step "Update Nitro_Render_V3"
|
||||||
echo "--> Updating Nitro_Render_V3..."
|
|
||||||
|
|
||||||
if git_update "$NITRO_RENDERER" "$NITRO_BRANCH"; then
|
if git_update "$NITRO_RENDERER" "$NITRO_BRANCH"; then
|
||||||
echo "--> New commits detected, running yarn install for Nitro_Render_V3..."
|
info "New commits detected"
|
||||||
HAD_UPDATES=true
|
HAD_UPDATES=true
|
||||||
yarn install --frozen-lockfile || { echo "--> Retrying with clean node_modules..."; clean_node_modules && yarn install; }
|
yarn install --frozen-lockfile || { info "Retrying with clean node_modules..."; clean_node_modules && yarn install; } || die "yarn install failed for Nitro_Render_V3"
|
||||||
|
ok "Dependencies installed"
|
||||||
else
|
else
|
||||||
echo "--> Nitro_Render_V3 already up to date, skipping."
|
info "Already up to date, skipping"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
# ----------------------------------------
|
# 3. UPDATE & BUILD NITRO-V3
|
||||||
# 3. Update and Build Nitro-V3
|
# =============================================================================
|
||||||
# ----------------------------------------
|
step "Update & Build Nitro-V3"
|
||||||
echo "--> Updating Nitro-V3..."
|
|
||||||
|
|
||||||
if git_update "$NITRO_CLIENT" "$NITRO_BRANCH"; then
|
if git_update "$NITRO_CLIENT" "$NITRO_BRANCH"; then
|
||||||
echo "--> New commits detected, building Nitro-V3..."
|
info "New commits detected"
|
||||||
HAD_UPDATES=true
|
HAD_UPDATES=true
|
||||||
NITRO_BUILT=true
|
NITRO_BUILT=true
|
||||||
yarn install --frozen-lockfile || { echo "--> Retrying with clean node_modules..."; clean_node_modules && yarn install; }
|
yarn install --frozen-lockfile || { info "Retrying with clean node_modules..."; clean_node_modules && yarn install; } || die "yarn install failed for Nitro-V3"
|
||||||
yarn build
|
ok "Dependencies installed"
|
||||||
|
info "Building Nitro-V3 (yarn build)..."
|
||||||
|
yarn build || die "yarn build failed"
|
||||||
|
ok "Build complete"
|
||||||
else
|
else
|
||||||
echo "--> Nitro-V3 already up to date, skipping build."
|
info "Already up to date, skipping build"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "--> Ensuring custom-themes/index.json exists..."
|
# custom-themes/index.json
|
||||||
mkdir -p "$NITRO_CLIENT/dist/custom-themes"
|
mkdir -p "$NITRO_CLIENT/dist/custom-themes"
|
||||||
if [ ! -f "$NITRO_CLIENT/dist/custom-themes/index.json" ]; then
|
if [ ! -f "$NITRO_CLIENT/dist/custom-themes/index.json" ]; then
|
||||||
echo '{"themes":[]}' > "$NITRO_CLIENT/dist/custom-themes/index.json"
|
echo '{"themes":[]}' > "$NITRO_CLIENT/dist/custom-themes/index.json"
|
||||||
echo "--> [OK] Created custom-themes/index.json"
|
ok "Created custom-themes/index.json"
|
||||||
else
|
else
|
||||||
echo "--> [OK] custom-themes/index.json already exists"
|
ok "custom-themes/index.json exists"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 4. SYNC CONFIGS
|
||||||
|
# =============================================================================
|
||||||
|
step "Sync Configurations"
|
||||||
|
|
||||||
# ----------------------------------------
|
|
||||||
# 4. Sync Configs & UITexts (.example logic)
|
|
||||||
# ----------------------------------------
|
|
||||||
echo "--> Synchronizing configurations..."
|
|
||||||
mkdir -p "$GAMEDATA_CONF_DIR"
|
mkdir -p "$GAMEDATA_CONF_DIR"
|
||||||
|
|
||||||
MERGE_SCRIPT="$(dirname "$0")/scripts/merge-config.cjs"
|
MERGE_SCRIPT="$(dirname "$0")/scripts/merge-config.cjs"
|
||||||
NITRO_DIST_CONFIG_DIR="$NITRO_CLIENT/dist/configuration"
|
NITRO_DIST_CONFIG_DIR="$NITRO_CLIENT/dist/configuration"
|
||||||
|
|
||||||
# Temporarily make config dirs writable if owned by www-data (restored in section 6)
|
# Make dirs writable
|
||||||
for dir in "$NITRO_SRC_DIR" "$GAMEDATA_CONF_DIR"; do
|
for dir in "$NITRO_SRC_DIR" "$GAMEDATA_CONF_DIR"; do
|
||||||
if [ -d "$dir" ] && [ ! -w "$dir" ] && command -v sudo &> /dev/null; then
|
if [ -d "$dir" ] && [ ! -w "$dir" ] && command -v sudo &> /dev/null; then
|
||||||
sudo chown -R "$(whoami)":"$(whoami)" "$dir"
|
sudo chown -R "$(whoami)":"$(whoami)" "$dir" 2>/dev/null || true
|
||||||
echo "--> [OK] Made $dir writable (will restore to www-data later)"
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
EXAMPLE_COUNT=0
|
||||||
for example_file in "$NITRO_SRC_DIR"/*.example; do
|
for example_file in "$NITRO_SRC_DIR"/*.example; do
|
||||||
[ -f "$example_file" ] || continue
|
[ -f "$example_file" ] || continue
|
||||||
base=$(basename "$example_file")
|
base=$(basename "$example_file")
|
||||||
target_name="${base%.example}"
|
target_name="${base%.example}"
|
||||||
case "$target_name" in
|
case "$target_name" in *.*) ;; *) target_name="$target_name.json" ;; esac
|
||||||
*.*) ;;
|
node "$MERGE_SCRIPT" "$example_file" "$NITRO_SRC_DIR/$target_name" 2>/dev/null
|
||||||
*) target_name="$target_name.json" ;;
|
node "$MERGE_SCRIPT" "$example_file" "$GAMEDATA_CONF_DIR/$target_name" 2>/dev/null
|
||||||
esac
|
|
||||||
|
|
||||||
echo "--> Merging $base -> $target_name (live)..."
|
|
||||||
node "$MERGE_SCRIPT" "$example_file" "$NITRO_SRC_DIR/$target_name"
|
|
||||||
echo "--> Merging $base -> $target_name (gamedata)..."
|
|
||||||
node "$MERGE_SCRIPT" "$example_file" "$GAMEDATA_CONF_DIR/$target_name"
|
|
||||||
if [ -d "$NITRO_DIST_CONFIG_DIR" ]; then
|
if [ -d "$NITRO_DIST_CONFIG_DIR" ]; then
|
||||||
cp "$NITRO_SRC_DIR/$target_name" "$NITRO_DIST_CONFIG_DIR/$target_name"
|
cp "$NITRO_SRC_DIR/$target_name" "$NITRO_DIST_CONFIG_DIR/$target_name" 2>/dev/null || true
|
||||||
echo "--> [OK] Synced $target_name to dist/configuration/"
|
|
||||||
fi
|
fi
|
||||||
|
EXAMPLE_COUNT=$((EXAMPLE_COUNT + 1))
|
||||||
done
|
done
|
||||||
|
ok "$EXAMPLE_COUNT .example file(s) processed"
|
||||||
|
|
||||||
# Phase 4: Restore critical icon URLs in renderer-config and ui-config
|
# Force critical URLs
|
||||||
echo "--> Ensuring critical catalog icon URLs are correct..."
|
info "Applying critical config URLs..."
|
||||||
FORCE_CONFIG_SCRIPT=$(cat << 'PYEOF'
|
FORCE_CONFIG_SCRIPT=$(cat << 'PYEOF'
|
||||||
import json, sys, os
|
import json, sys, os
|
||||||
|
|
||||||
@@ -296,9 +421,9 @@ for path in paths:
|
|||||||
data['show.google.ads'] = False
|
data['show.google.ads'] = False
|
||||||
with open(path, 'w') as f:
|
with open(path, 'w') as f:
|
||||||
json.dump(data, f, indent=(4 if 'dist' not in path else None), separators=(',', ':') if 'dist' in path else (',', ': '))
|
json.dump(data, f, indent=(4 if 'dist' not in path else None), separators=(',', ':') if 'dist' in path else (',', ': '))
|
||||||
print(f'--> [OK] Fixed: {os.path.basename(path)}')
|
print(f' [OK] Fixed: {os.path.basename(path)}')
|
||||||
|
|
||||||
print('--> [OK] Catalog icon URLs are set correctly')
|
print(' [OK] All config URLs synced')
|
||||||
PYEOF
|
PYEOF
|
||||||
)
|
)
|
||||||
cd "$NITRO_CLIENT" && NITRO_SRC_DIR="$NITRO_SRC_DIR" NITRO_DIST_CONFIG_DIR="$NITRO_DIST_CONFIG_DIR" \
|
cd "$NITRO_CLIENT" && NITRO_SRC_DIR="$NITRO_SRC_DIR" NITRO_DIST_CONFIG_DIR="$NITRO_DIST_CONFIG_DIR" \
|
||||||
@@ -308,108 +433,144 @@ cd "$NITRO_CLIENT" && NITRO_SRC_DIR="$NITRO_SRC_DIR" NITRO_DIST_CONFIG_DIR="$NIT
|
|||||||
NITRO_FURNI_ASSET_ICON_URL="$NITRO_FURNI_ASSET_ICON_URL" \
|
NITRO_FURNI_ASSET_ICON_URL="$NITRO_FURNI_ASSET_ICON_URL" \
|
||||||
python3 -c "$FORCE_CONFIG_SCRIPT"
|
python3 -c "$FORCE_CONFIG_SCRIPT"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 5. CLEANUP
|
||||||
|
# =============================================================================
|
||||||
|
step "Cleanup"
|
||||||
|
|
||||||
# ----------------------------------------
|
info "Removing logs older than 14 days..."
|
||||||
# 5. Automated Cleanup (Logs & Backups)
|
|
||||||
# ----------------------------------------
|
|
||||||
echo "--> Starting automated cleanup..."
|
|
||||||
|
|
||||||
echo "--> Removing emulator logs older than 14 days..."
|
|
||||||
find "$EMULATOR_DIR" -name "*.log" -mtime +14 -exec rm -f {} \; 2>/dev/null || true
|
find "$EMULATOR_DIR" -name "*.log" -mtime +14 -exec rm -f {} \; 2>/dev/null || true
|
||||||
|
|
||||||
echo "--> Managing update backups (keeping max 5)..."
|
info "Managing backups (keeping max 5)..."
|
||||||
if [ -d "$BACKUP_DIR" ]; then
|
if [ -d "$BACKUP_DIR" ]; then
|
||||||
find "$BACKUP_DIR" -maxdepth 1 -name '*.sql' -printf '%T@ %p\n' 2>/dev/null | sort -rn | tail -n +6 | sed 's/^[0-9.]* //' | xargs -r rm -f || true
|
find "$BACKUP_DIR" -maxdepth 1 -name '*.sql' -printf '%T@ %p\n' 2>/dev/null | sort -rn | tail -n +6 | sed 's/^[0-9.]* //' | xargs -r rm -f || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$HAD_UPDATES" = true ]; then
|
if [ "$HAD_UPDATES" = true ]; then
|
||||||
echo "--> Cleaning Yarn cache..."
|
info "Cleaning Yarn cache..."
|
||||||
yarn cache clean 2>/dev/null || true
|
yarn cache clean 2>/dev/null || true
|
||||||
echo "--> Cleaning up old emulator .jar files (keeping the latest)..."
|
info "Removing old .jar files..."
|
||||||
find "$EMULATOR_DIR/Emulator/target" -maxdepth 1 -name 'Habbo-*-jar-with-dependencies.jar' -printf '%T@ %p\n' 2>/dev/null | sort -rn | tail -n +2 | sed 's/^[0-9.]* //' | xargs -r rm -f || true
|
find "$EMULATOR_DIR/Emulator/target" -maxdepth 1 -name 'Habbo-*-jar-with-dependencies.jar' -printf '%T@ %p\n' 2>/dev/null | sort -rn | tail -n +2 | sed 's/^[0-9.]* //' | xargs -r rm -f || true
|
||||||
fi
|
fi
|
||||||
|
ok "Cleanup complete"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 6. PERMISSIONS
|
||||||
|
# =============================================================================
|
||||||
|
step "Set Permissions"
|
||||||
|
|
||||||
# ----------------------------------------
|
|
||||||
# 6. Fix Permissions (www-data)
|
|
||||||
# ----------------------------------------
|
|
||||||
if command -v sudo &> /dev/null; then
|
if command -v sudo &> /dev/null; then
|
||||||
echo "--> Setting permissions to www-data:www-data..."
|
|
||||||
for dir in "$NITRO_CLIENT" "$NITRO_RENDERER" "$EMULATOR_DIR" "$GAMEDATA_CONF_DIR"; do
|
for dir in "$NITRO_CLIENT" "$NITRO_RENDERER" "$EMULATOR_DIR" "$GAMEDATA_CONF_DIR"; do
|
||||||
if [ -d "$dir" ]; then
|
if [ -d "$dir" ]; then
|
||||||
sudo chown -R www-data:www-data "$dir"
|
sudo chown -R www-data:www-data "$dir" 2>/dev/null || warn "Could not chown $dir"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
echo "--> Permissions successfully set to www-data:www-data"
|
ok "Permissions set to www-data:www-data"
|
||||||
else
|
else
|
||||||
echo "--> Sudo not available, skipping chown."
|
warn "sudo not available, skipping chown"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 7. RESTART SERVICES
|
||||||
|
# =============================================================================
|
||||||
|
step "Restart Services"
|
||||||
|
|
||||||
# ----------------------------------------
|
RESTART_OK=false
|
||||||
# 7. Restart the Service (only if updates were applied)
|
|
||||||
# ----------------------------------------
|
|
||||||
if [ "$HAD_UPDATES" = true ]; then
|
if [ "$HAD_UPDATES" = true ]; then
|
||||||
if systemctl cat "$EMULATOR_SERVICE" &>/dev/null; then
|
if systemctl cat "$EMULATOR_SERVICE" &>/dev/null; then
|
||||||
echo "--> Restarting $EMULATOR_SERVICE service..."
|
|
||||||
if command -v sudo &> /dev/null; then
|
if command -v sudo &> /dev/null; then
|
||||||
sudo systemctl restart "$EMULATOR_SERVICE"
|
info "Restarting $EMULATOR_SERVICE..."
|
||||||
sudo systemctl status "$EMULATOR_SERVICE" --no-pager -n 5
|
sudo systemctl restart "$EMULATOR_SERVICE" || die "Failed to restart $EMULATOR_SERVICE"
|
||||||
else
|
RESTART_OK=true
|
||||||
echo "--> Sudo not available. Restart the service manually: sudo systemctl restart $EMULATOR_SERVICE"
|
|
||||||
fi
|
fi
|
||||||
elif command -v pm2 &> /dev/null; then
|
elif command -v pm2 &> /dev/null; then
|
||||||
echo "--> Restarting PM2 processes..."
|
info "Restarting PM2 processes..."
|
||||||
pm2 restart all
|
pm2 restart all || warn "PM2 restart had issues"
|
||||||
|
RESTART_OK=true
|
||||||
else
|
else
|
||||||
echo "--> Warning: Neither systemd nor PM2 found. Restart the emulator manually."
|
warn "No systemd or PM2 found — restart manually"
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$RESTART_OK" = true ]; then
|
||||||
|
ok "Services restarted"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
info "No updates applied, no restart needed"
|
||||||
|
fi
|
||||||
|
|
||||||
# ----------------------------------------
|
# =============================================================================
|
||||||
# 8. Extra Validation — 100% check
|
# 8. HEALTH CHECK & VALIDATION
|
||||||
# ----------------------------------------
|
# =============================================================================
|
||||||
echo "--> Running extra validation..."
|
step "Health Check & Validation"
|
||||||
|
|
||||||
ERRORS=0
|
ERRORS=0
|
||||||
|
|
||||||
|
# Build output check
|
||||||
if [ "$NITRO_BUILT" = true ]; then
|
if [ "$NITRO_BUILT" = true ]; then
|
||||||
if [ -d "$NITRO_CLIENT/dist/assets" ]; then
|
if [ -d "$NITRO_CLIENT/dist/assets" ]; then
|
||||||
echo "--> [OK] Nitro-V3 build assets found"
|
ASSET_COUNT=$(find "$NITRO_CLIENT/dist/assets" -type f 2>/dev/null | wc -l)
|
||||||
|
ok "Nitro-V3 built: $ASSET_COUNT assets in dist/assets"
|
||||||
else
|
else
|
||||||
echo "--> [FAIL] Nitro-V3 build assets missing!"
|
fail "Nitro-V3 build assets missing!"
|
||||||
ERRORS=$((ERRORS + 1))
|
ERRORS=$((ERRORS + 1))
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "--> [SKIP] Nitro-V3 was not rebuilt, skipping build check"
|
info "Skipping build check (no new commits)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Health check with retries for emulator
|
||||||
|
if [ "$HAD_UPDATES" = true ] && systemctl cat "$EMULATOR_SERVICE" &>/dev/null; then
|
||||||
|
info "Waiting for $EMULATOR_SERVICE to become active..."
|
||||||
|
HEALTHY=false
|
||||||
|
for i in $(seq 1 "$HEALTH_RETRIES"); do
|
||||||
|
sleep "$HEALTH_INTERVAL"
|
||||||
|
STATUS=$(systemctl is-active "$EMULATOR_SERVICE" 2>/dev/null || echo "unknown")
|
||||||
|
if [ "$STATUS" = "active" ]; then
|
||||||
|
HEALTHY=true
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
info " Attempt $i/$HEALTH_RETRIES — status: $STATUS"
|
||||||
|
done
|
||||||
|
if [ "$HEALTHY" = true ]; then
|
||||||
|
ok "$EMULATOR_SERVICE is active ($(( i * HEALTH_INTERVAL ))s to start)"
|
||||||
|
else
|
||||||
|
fail "$EMULATOR_SERVICE did not become active after ${HEALTH_RETRIES} retries"
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Permission audit
|
||||||
for dir in "$NITRO_CLIENT" "$NITRO_RENDERER" "$EMULATOR_DIR" "$GAMEDATA_CONF_DIR"; do
|
for dir in "$NITRO_CLIENT" "$NITRO_RENDERER" "$EMULATOR_DIR" "$GAMEDATA_CONF_DIR"; do
|
||||||
if [ -d "$dir" ]; then
|
if [ -d "$dir" ]; then
|
||||||
OWNER=$(stat -c '%U:%G' "$dir" 2>/dev/null || echo "unknown")
|
OWNER=$(stat -c '%U:%G' "$dir" 2>/dev/null || echo "unknown")
|
||||||
if [ "$OWNER" = "www-data:www-data" ] || [ "$(id -u)" -ne 0 ]; then
|
if [ "$OWNER" = "www-data:www-data" ] || [ "$(id -u)" -ne 0 ]; then
|
||||||
echo "--> [OK] $dir ($OWNER)"
|
ok "$(basename "$dir") ($OWNER)"
|
||||||
else
|
else
|
||||||
echo "--> [WARN] $dir has owner $OWNER instead of www-data:www-data"
|
warn "$(basename "$dir") owner is $OWNER (should be www-data:www-data)"
|
||||||
sudo chown -R www-data:www-data "$dir" 2>/dev/null || true
|
sudo chown -R www-data:www-data "$dir" 2>/dev/null || true
|
||||||
echo " Restored to www-data:www-data"
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if systemctl cat "$EMULATOR_SERVICE" &>/dev/null; then
|
# =============================================================================
|
||||||
SERVICE_STATUS=$(systemctl is-active "$EMULATOR_SERVICE" 2>/dev/null || echo "unknown")
|
# SUMMARY
|
||||||
if [ "$SERVICE_STATUS" = "active" ]; then
|
# =============================================================================
|
||||||
echo "--> [OK] $EMULATOR_SERVICE service is $SERVICE_STATUS"
|
ELAPSED=$(( $(date +%s) - START_TIME ))
|
||||||
else
|
ELAPSED_FMT=$(printf '%dm %ds' $((ELAPSED/60)) $((ELAPSED%60)))
|
||||||
echo "--> [WARN] $EMULATOR_SERVICE service is $SERVICE_STATUS (not active, check logs)"
|
|
||||||
ERRORS=$((ERRORS + 1))
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "╔══════════════════════════════════════════════════════════════╗"
|
||||||
if [ "$ERRORS" -eq 0 ]; then
|
if [ "$ERRORS" -eq 0 ]; then
|
||||||
echo "=== ✅ Update 100% successfully completed! ==="
|
echo "║ ✅ UPDATE SUCCESSFULLY COMPLETED ║"
|
||||||
else
|
else
|
||||||
echo "=== ⚠️ Update completed with $ERRORS warning(s) — check output above ==="
|
echo "║ ⚠️ UPDATE COMPLETED WITH $ERRORS WARNING(S) ║"
|
||||||
fi
|
fi
|
||||||
|
echo "╠══════════════════════════════════════════════════════════════╣"
|
||||||
|
printf "║ Duration: %-46s║\n" "$ELAPSED_FMT"
|
||||||
|
printf "║ Updates: %-46s║\n" "$([ "$HAD_UPDATES" = true ] && echo "Yes" || echo "No")"
|
||||||
|
printf "║ Nitro build: %-46s║\n" "$([ "$NITRO_BUILT" = true ] && echo "Yes" || echo "No")"
|
||||||
|
printf "║ Log file: %-46s║\n" "$LOG_FILE"
|
||||||
|
echo "╚══════════════════════════════════════════════════════════════╝"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
notify "SUCCESS" "Completed in $ELAPSED_FMT (${ERRORS} warnings)"
|
||||||
Reference in New Issue
Block a user