fix: repair updater and migrate configs to JSONC only

- fix emulator git path (repo root vs Maven submodule) and SQL/backup dirs
- auto-detect branch; track real parallel job exit status
- verify vite presence and clean+full install when node_modules is incomplete
- fix health-check label handling and skip jsonc/example files in JSON scan
- stop hardcoding the Nitro client path in chown
- drop JSON5: sync config URLs to .jsonc, remove legacy .json5 files
- bump to v8.0.2
This commit is contained in:
openhands committed 2026-08-03 17:43:19 +02:00
1 parent 44c34dbae6
commit 613b7502e1
1 file changed
+102 -45
+102 -45
View File
@@ -9,8 +9,8 @@ set -Eeo pipefail
# ============================================================================= # =============================================================================
# CONSTANTS # CONSTANTS
# ============================================================================= # =============================================================================
readonly SCRIPT_VERSION="8.0.0" readonly SCRIPT_VERSION="8.0.2"
readonly SCRIPT_BUILD="20260720" readonly SCRIPT_BUILD="20260803"
readonly SCRIPT_NAME="$(basename "$0")" readonly SCRIPT_NAME="$(basename "$0")"
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly START_TIME=$(date +%s) readonly START_TIME=$(date +%s)
@@ -105,19 +105,24 @@ DB_USER="${NITRO_DB_USER:-${DB_USER:-root}}"
DB_PASS="${NITRO_DB_PASS:-${DB_PASS:-}}" DB_PASS="${NITRO_DB_PASS:-${DB_PASS:-}}"
EMULATOR_SERVICE="${NITRO_EMULATOR_SERVICE:-emulator}" EMULATOR_SERVICE="${NITRO_EMULATOR_SERVICE:-emulator}"
EMULATOR_DIR="${NITRO_EMULATOR_PATH:-/var/www/emulator}" EMULATOR_DIR="${NITRO_EMULATOR_PATH:-/var/www/emulator}"
SQL_DIR="${NITRO_SQL_DIR:-$EMULATOR_DIR/Database Updates}" # Polaris-Emulator: the git repository root is $EMULATOR_DIR itself, while the
# Maven project (pom.xml + target/) lives in the $EMULATOR_DIR/Emulator submodule.
EMULATOR_REPO="${NITRO_EMULATOR_REPO:-$EMULATOR_DIR}"
EMULATOR_MODULE="${NITRO_EMULATOR_MODULE:-$EMULATOR_DIR/Emulator}"
SQL_DIR="${NITRO_SQL_DIR:-$EMULATOR_DIR/Database/Database Updates}"
GAMEDATA_CONF_DIR="${NITRO_GAMEDATA_DIR:-/var/www/Gamedata/config}" GAMEDATA_CONF_DIR="${NITRO_GAMEDATA_DIR:-/var/www/Gamedata/config}"
NITRO_SRC_DIR="${NITRO_CLIENT_DIR:-/var/www/Nitro-V3/public/configuration}" NITRO_SRC_DIR="${NITRO_CLIENT_DIR:-/var/www/Nitro-V3/public/configuration}"
BACKUP_DIR="${NITRO_BACKUP_DIR:-$EMULATOR_DIR/Database Updates/backups}" BACKUP_DIR="${NITRO_BACKUP_DIR:-$EMULATOR_DIR/Database/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:-}"
MIN_DISK_GB="${NITRO_MIN_DISK_GB:-5}" MIN_DISK_GB="${NITRO_MIN_DISK_GB:-5}"
HEALTH_RETRIES="${NITRO_HEALTH_RETRIES:-12}" HEALTH_RETRIES="${NITRO_HEALTH_RETRIES:-12}"
HEALTH_INTERVAL="${NITRO_HEALTH_INTERVAL:-5}" HEALTH_INTERVAL="${NITRO_HEALTH_INTERVAL:-5}"
NITRO_SSL_VERIFY="${NITRO_SSL_VERIFY:-OFF}" NITRO_SSL_VERIFY="${NITRO_SSL_VERIFY:-OFF}"
CONFIG_BACKUP_DIR="${SCRIPT_DIR}/storage/config-backups" CONFIG_BACKUP_DIR="${SCRIPT_DIR}/storage/config-backups"
mkdir -p "$CONFIG_BACKUP_DIR" 2>/dev/null || true mkdir -p "$CONFIG_BACKUP_DIR" 2>/dev/null || true
mkdir -p "$BACKUP_DIR" 2>/dev/null || true
NITRO_LANG="${NITRO_LANG:-en}" NITRO_LANG="${NITRO_LANG:-en}"
MYSQL_CRED="-h $DB_HOST -P $DB_PORT -u $DB_USER --ssl-verify-server-cert=${NITRO_SSL_VERIFY}" MYSQL_CRED="-h $DB_HOST -P $DB_PORT -u $DB_USER --ssl-verify-server-cert=${NITRO_SSL_VERIFY}"
@@ -857,7 +862,7 @@ trap 'release_lock; cursor_show; exit 1' SIGINT SIGTERM
# GIT HELPERS # GIT HELPERS
# ============================================================================= # =============================================================================
detect_branches() { detect_branches() {
local repos=("$EMULATOR_DIR/Emulator" "$NITRO_CLIENT" "$NITRO_RENDERER") local repos=("$EMULATOR_REPO" "$NITRO_CLIENT" "$NITRO_RENDERER")
for repo in "${repos[@]}"; do for repo in "${repos[@]}"; do
[ -d "$repo/.git" ] || continue [ -d "$repo/.git" ] || continue
( (
@@ -876,10 +881,11 @@ detect_best_branch() {
local repo="$1" preferred="$2" local repo="$1" preferred="$2"
( (
cd "$repo" 2>/dev/null || { echo "main"; exit 0; } cd "$repo" 2>/dev/null || { echo "main"; exit 0; }
for v in "$preferred" "${preferred^}" "main" "master"; do local cur; cur=$(git branch --show-current 2>/dev/null || echo "")
git rev-parse --verify "$v" &>/dev/null && { echo "$v"; exit 0; } for v in "$preferred" "${preferred^}" "$cur" "main" "master"; do
[ -n "$v" ] && git rev-parse --verify "$v" &>/dev/null && { echo "$v"; exit 0; }
done done
echo "$(git branch --show-current 2>/dev/null || echo "main")" echo "${cur:-main}"
) )
} }
@@ -924,33 +930,36 @@ clean_node_modules() {
# ============================================================================= # =============================================================================
PARALLEL_PIDS=() PARALLEL_PIDS=()
PARALLEL_NAMES=()
PARALLEL_FAILED=() PARALLEL_FAILED=()
PARALLEL_RESULTS=() PARALLEL_RESULTS=()
parallel_run() { parallel_run() {
local name="$1"; shift local name="$1"; shift
PARALLEL_NAMES+=("$name")
( (
if "$@" >/dev/null 2>&1; then "$@" >/dev/null 2>&1
echo "__PARALLEL_OK__${name}"
else
echo "__PARALLEL_FAIL__${name}"
fi
) & ) &
PARALLEL_PIDS+=($!) PARALLEL_PIDS+=($!)
} }
parallel_wait() { parallel_wait() {
# Collect per-job pass/fail markers from stdout of each backgrounded job. # Collect per-job pass/fail based on the real exit status of each job.
PARALLEL_RESULTS=() PARALLEL_RESULTS=()
PARALLEL_FAILED=()
local i=0
for pid in "${PARALLEL_PIDS[@]}"; do for pid in "${PARALLEL_PIDS[@]}"; do
local line local name="${PARALLEL_NAMES[$i]}"
line=$(wait "$pid" 2>/dev/null; true) if wait "$pid" 2>/dev/null; then
PARALLEL_RESULTS+=("$line") PARALLEL_RESULTS+=("__PARALLEL_OK__${name}")
if [ "$line" = "__PARALLEL_FAIL__"* ]; then else
PARALLEL_FAILED+=("${line#__PARALLEL_FAIL__}") PARALLEL_RESULTS+=("__PARALLEL_FAIL__${name}")
PARALLEL_FAILED+=("$name")
fi fi
i=$((i+1))
done done
PARALLEL_PIDS=() PARALLEL_PIDS=()
PARALLEL_NAMES=()
} }
parallel_failed() { parallel_failed() {
@@ -987,6 +996,9 @@ validate_configs() {
local errors=0 local errors=0
for f in "$dir"/*.json; do for f in "$dir"/*.json; do
[ -f "$f" ] || continue [ -f "$f" ] || continue
case "$(basename "$f")" in
*jsonc*|*.example*) continue ;;
esac
if ! validate_json "$f"; then if ! validate_json "$f"; then
warn "Invalid JSON: %s" "$(basename "$f")" warn "Invalid JSON: %s" "$(basename "$f")"
errors=$((errors + 1)) errors=$((errors + 1))
@@ -1003,7 +1015,7 @@ backup_binaries() {
BINARY_BACKUP_DIR="$CONFIG_BACKUP_DIR/binaries-$(date +%Y%m%d-%H%M%S)" BINARY_BACKUP_DIR="$CONFIG_BACKUP_DIR/binaries-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BINARY_BACKUP_DIR" mkdir -p "$BINARY_BACKUP_DIR"
local jar_dir="$EMULATOR_DIR/Emulator/target" local jar_dir="$EMULATOR_MODULE/target"
if [ -d "$jar_dir" ] && ls "$jar_dir"/Polaris-*-jar-with-dependencies.jar &>/dev/null 2>&1; then if [ -d "$jar_dir" ] && ls "$jar_dir"/Polaris-*-jar-with-dependencies.jar &>/dev/null 2>&1; then
cp "$jar_dir"/Polaris-*-jar-with-dependencies.jar "$BINARY_BACKUP_DIR/" 2>/dev/null || true cp "$jar_dir"/Polaris-*-jar-with-dependencies.jar "$BINARY_BACKUP_DIR/" 2>/dev/null || true
ok "Emulator JAR backed up" ok "Emulator JAR backed up"
@@ -1023,7 +1035,7 @@ restore_binaries() {
echo -e " ${C_BG_RED}${C_WHITE}${C_BOLD} $(_t "RESTORE BINARIES") ${C_RESET}" echo -e " ${C_BG_RED}${C_WHITE}${C_BOLD} $(_t "RESTORE BINARIES") ${C_RESET}"
if ls "$BINARY_BACKUP_DIR"/Polaris-*-jar-with-dependencies.jar &>/dev/null 2>&1; then if ls "$BINARY_BACKUP_DIR"/Polaris-*-jar-with-dependencies.jar &>/dev/null 2>&1; then
local jar_dir="$EMULATOR_DIR/Emulator/target" local jar_dir="$EMULATOR_MODULE/target"
mkdir -p "$jar_dir" mkdir -p "$jar_dir"
cp "$BINARY_BACKUP_DIR"/Polaris-*-jar-with-dependencies.jar "$jar_dir/" 2>/dev/null || true cp "$BINARY_BACKUP_DIR"/Polaris-*-jar-with-dependencies.jar "$jar_dir/" 2>/dev/null || true
ok "Emulator JAR restored" ok "Emulator JAR restored"
@@ -1052,7 +1064,7 @@ preflight_check() {
ok "All commands available" ok "All commands available"
for d in "$EMULATOR_DIR/Emulator" "$NITRO_RENDERER" "$NITRO_CLIENT" "$NITRO_SRC_DIR"; do for d in "$EMULATOR_REPO" "$EMULATOR_MODULE" "$NITRO_RENDERER" "$NITRO_CLIENT" "$NITRO_SRC_DIR"; do
[ -d "$d" ] || die "Missing dir: $d" [ -d "$d" ] || die "Missing dir: $d"
done done
ok "All directories exist" ok "All directories exist"
@@ -1075,9 +1087,9 @@ preflight_check() {
# ============================================================================= # =============================================================================
update_emulator() { update_emulator() {
step 2 8 "Update & Build Emulator" step 2 8 "Update & Build Emulator"
if git_update "$EMULATOR_DIR/Emulator" "$NITRO_BRANCH"; then if git_update "$EMULATOR_REPO" "$NITRO_BRANCH"; then
HAD_UPDATES=true; UPDATED_REPOS+=("Emulator") HAD_UPDATES=true; UPDATED_REPOS+=("Emulator")
cd "$EMULATOR_DIR/Emulator" cd "$EMULATOR_MODULE"
backup_binaries backup_binaries
ROLLBACK_NEEDED=true ROLLBACK_NEEDED=true
spinner_start "Building emulator (parallel)..." spinner_start "Building emulator (parallel)..."
@@ -1118,11 +1130,21 @@ update_renderer() {
HAD_UPDATES=true; UPDATED_REPOS+=("Nitro_Render_V3") HAD_UPDATES=true; UPDATED_REPOS+=("Nitro_Render_V3")
cd "$NITRO_RENDERER" cd "$NITRO_RENDERER"
spinner_start "Installing deps..." spinner_start "Installing deps..."
yarn install --frozen-lockfile --prefer-offline 2>&1 || { clean_node_modules && yarn install 2>&1; } || { spinner_stop fail; die "yarn install failed"; } if ! yarn install --frozen-lockfile --prefer-offline >> "$LOG_FILE" 2>&1; then
warn "Renderer: yarn install failed — cleaning node_modules and retrying"
clean_node_modules
yarn install >> "$LOG_FILE" 2>&1 || { spinner_stop fail; die "yarn install failed (see: %s)" "$LOG_FILE"; }
fi
if [ ! -d node_modules/pixi.js ]; then
warn "Renderer: node_modules incomplete — cleaning and doing full install"
clean_node_modules
yarn install >> "$LOG_FILE" 2>&1 || { spinner_stop fail; die "yarn install failed (see: %s)" "$LOG_FILE"; }
fi
spinner_stop ok; ok "Renderer dependencies installed" spinner_stop ok; ok "Renderer dependencies installed"
else else
info "Renderer: already up to date" info "Renderer: already up to date"
fi fi
return 0
} }
update_client() { update_client() {
@@ -1133,14 +1155,25 @@ update_client() {
backup_binaries backup_binaries
ROLLBACK_NEEDED=true ROLLBACK_NEEDED=true
spinner_start "Installing deps..." spinner_start "Installing deps..."
yarn install --frozen-lockfile --prefer-offline 2>&1 || { clean_node_modules && yarn install 2>&1; } || { spinner_stop fail; die "yarn install failed"; } # yarn 1 can "succeed" while leaving node_modules incomplete, so verify
# that the vite build binary actually exists before attempting a build.
if ! yarn install --frozen-lockfile --prefer-offline >> "$LOG_FILE" 2>&1; then
warn "Nitro-V3: yarn install failed — cleaning node_modules and retrying"
clean_node_modules
yarn install >> "$LOG_FILE" 2>&1 || { spinner_stop fail; die "yarn install failed (see: %s)" "$LOG_FILE"; }
fi
if [ ! -x node_modules/.bin/vite ]; then
warn "Nitro-V3: vite missing after install — cleaning node_modules and doing full install"
clean_node_modules
yarn install >> "$LOG_FILE" 2>&1 || { spinner_stop fail; die "yarn install failed (see: %s)" "$LOG_FILE"; }
fi
spinner_stop ok spinner_stop ok
spinner_start "Building frontend..." spinner_start "Building frontend..."
if yarn build >> "$LOG_FILE" 2>&1; then if yarn build >> "$LOG_FILE" 2>&1; then
spinner_stop ok spinner_stop ok
else else
spinner_stop fail spinner_stop fail
tail -10 "$LOG_FILE" || true tail -30 "$LOG_FILE" || true
die "yarn build failed (see: %s)" "$LOG_FILE" die "yarn build failed (see: %s)" "$LOG_FILE"
fi fi
else else
@@ -1148,6 +1181,7 @@ update_client() {
fi fi
mkdir -p "$NITRO_CLIENT/dist/custom-themes" mkdir -p "$NITRO_CLIENT/dist/custom-themes"
[ ! -f "$NITRO_CLIENT/dist/custom-themes/index.json" ] && echo '{"themes":[]}' > "$NITRO_CLIENT/dist/custom-themes/index.json" [ ! -f "$NITRO_CLIENT/dist/custom-themes/index.json" ] && echo '{"themes":[]}' > "$NITRO_CLIENT/dist/custom-themes/index.json"
return 0
} }
sync_configs() { sync_configs() {
@@ -1178,6 +1212,12 @@ sync_configs() {
# Validate the generated configs # Validate the generated configs
validate_configs "$NITRO_SRC_DIR" validate_configs "$NITRO_SRC_DIR"
# Remove legacy .json5 leftovers — the client only supports JSON/JSONC
for d in "$NITRO_SRC_DIR" "$dcd" "$GAMEDATA_CONF_DIR"; do
[ -d "$d" ] && find "$d" -maxdepth 1 -name '*.json5' -type f -delete 2>/dev/null || true
done
ok "Legacy .json5 files removed"
# Pre-flight: warn if NITRO_IMAGE_LIBRARY_URL looks wrong before applying configs # Pre-flight: warn if NITRO_IMAGE_LIBRARY_URL looks wrong before applying configs
if [ -n "$NITRO_IMAGE_LIBRARY_URL" ]; then if [ -n "$NITRO_IMAGE_LIBRARY_URL" ]; then
case "$NITRO_IMAGE_LIBRARY_URL" in case "$NITRO_IMAGE_LIBRARY_URL" in
@@ -1199,6 +1239,11 @@ sync_configs() {
NITRO_FURNI_ASSET_ICON_URL="$NITRO_FURNI_ASSET_ICON_URL" \ NITRO_FURNI_ASSET_ICON_URL="$NITRO_FURNI_ASSET_ICON_URL" \
python3 -c ' python3 -c '
import json, os import json, os
def to_jsonc(value):
if isinstance(value, dict): return {k: to_jsonc(v) for k, v in value.items()}
if isinstance(value, list): return [to_jsonc(v) for v in value]
if isinstance(value, str): return value.replace(".json5", ".jsonc")
return value
paths = [ paths = [
os.path.join(os.environ.get("NITRO_SRC_DIR", ""), "renderer-config.json"), os.path.join(os.environ.get("NITRO_SRC_DIR", ""), "renderer-config.json"),
os.path.join(os.environ.get("NITRO_DIST_CONFIG_DIR", ""), "renderer-config.json"), os.path.join(os.environ.get("NITRO_DIST_CONFIG_DIR", ""), "renderer-config.json"),
@@ -1208,6 +1253,7 @@ paths = [
for path in paths: for path in paths:
if not os.path.exists(path): continue if not os.path.exists(path): continue
with open(path, "r") as f: data = json.load(f) with open(path, "r") as f: data = json.load(f)
data = to_jsonc(data)
for key in ["image.library.url", "hof.furni.url", "gamedata.url", "asset.url"]: for key in ["image.library.url", "hof.furni.url", "gamedata.url", "asset.url"]:
env_val = os.environ.get(f"NITRO_{key.upper().replace(chr(46), chr(95))}") env_val = os.environ.get(f"NITRO_{key.upper().replace(chr(46), chr(95))}")
if env_val: data[key] = env_val if env_val: data[key] = env_val
@@ -1216,8 +1262,8 @@ for path in paths:
env_val = os.environ.get(f"NITRO_{key.upper().replace(chr(46), chr(95))}") env_val = os.environ.get(f"NITRO_{key.upper().replace(chr(46), chr(95))}")
if env_val: data[key] = env_val if env_val: data[key] = env_val
if "gamedata.url" in data: if "gamedata.url" in data:
data["radio.url"] = data["gamedata.url"] + "/config/radio-stations.json5?t=%timestamp%" data["radio.url"] = data["gamedata.url"] + "/config/radio-stations.jsonc?t=%timestamp%"
data["soundboard.url"] = data["gamedata.url"] + "/config/soundboard-sounds.json5?t=%timestamp%" data["soundboard.url"] = data["gamedata.url"] + "/config/soundboard-sounds.jsonc?t=%timestamp%"
if "show.google.ads" in data: data["show.google.ads"] = False if "show.google.ads" in data: data["show.google.ads"] = False
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 (",", ": ")) 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 (",", ": "))
print(f" [OK] Fixed: {os.path.basename(path)}") print(f" [OK] Fixed: {os.path.basename(path)}")
@@ -1243,7 +1289,7 @@ do_cleanup() {
yarn cache clean 2>/dev/null || true yarn cache clean 2>/dev/null || true
rm -rf /tmp/nitro-* /tmp/epicnext-* 2>/dev/null || true rm -rf /tmp/nitro-* /tmp/epicnext-* 2>/dev/null || true
# Clean old Maven build artifacts (older than 7 days) # Clean old Maven build artifacts (older than 7 days)
find "$EMULATOR_DIR/Emulator" -maxdepth 3 -name '*.jar' -mtime +7 2>/dev/null -exec rm -f {} \; || true find "$EMULATOR_MODULE" -maxdepth 3 -name '*.jar' -mtime +7 2>/dev/null -exec rm -f {} \; || true
ok "Cleanup done (%s logs removed)" "$lc" ok "Cleanup done (%s logs removed)" "$lc"
} }
@@ -1288,7 +1334,7 @@ do_restart() {
emulator_port_open() { emulator_port_open() {
local port="${NITRO_EMULATOR_PORT:-}" local port="${NITRO_EMULATOR_PORT:-}"
if [ -z "$port" ]; then if [ -z "$port" ]; then
port=$(grep -m1 '^game\.port=' "$EMULATOR_DIR/Emulator/target/config.ini" 2>/dev/null | cut -d= -f2) port=$(grep -m1 '^game\.port=' "$EMULATOR_MODULE/target/config.ini" 2>/dev/null | cut -d= -f2)
fi fi
if [ -z "$port" ]; then if [ -z "$port" ]; then
port=30000 port=30000
@@ -1382,7 +1428,7 @@ cmd_update() {
esac esac
show_summary show_summary
sudo chown -R www-data:www-data /var/www/Nitro-V3/ sudo chown -R www-data:www-data "$NITRO_CLIENT/"
release_lock release_lock
} }
@@ -1466,7 +1512,7 @@ cmd_status() {
done; box_bottom 56 done; box_bottom 56
echo "" echo ""
box_top "GIT REPOS" 56 box_top "GIT REPOS" 56
for re in "Emulator:$EMULATOR_DIR/Emulator" "Nitro-V3:$NITRO_CLIENT" "Render:$NITRO_RENDERER"; do for re in "Emulator:$EMULATOR_REPO" "Nitro-V3:$NITRO_CLIENT" "Render:$NITRO_RENDERER"; do
local nm="${re%%:*}" pa="${re##*:}" local nm="${re%%:*}" pa="${re##*:}"
[ -d "$pa/.git" ] || continue [ -d "$pa/.git" ] || continue
local br=$(cd "$pa" && git branch --show-current 2>/dev/null || echo "?") local br=$(cd "$pa" && git branch --show-current 2>/dev/null || echo "?")
@@ -1487,8 +1533,8 @@ cmd_status() {
cmd_health() { cmd_health() {
step 1 1 "Health Check" step 1 1 "Health Check"
local t=0 p=0 f=0 w=0 local t=0 p=0 f=0 w=0
check() { t=$((t+1)); "$@" &>/dev/null && { p=$((p+1)); ok "$(_t "$1")"; } || { f=$((f+1)); fail "$(_t "$1")"; }; } check() { t=$((t+1)); local lbl="$1"; shift; "$@" &>/dev/null && { p=$((p+1)); ok "$(_t "$lbl")"; } || { f=$((f+1)); fail "$(_t "$lbl")"; }; }
checkw() { t=$((t+1)); "$@" &>/dev/null && { p=$((p+1)); ok "$(_t "$1")"; } || { w=$((w+1)); warn "$(_t "$1")"; }; } checkw() { t=$((t+1)); local lbl="$1"; shift; "$@" &>/dev/null && { p=$((p+1)); ok "$(_t "$lbl")"; } || { w=$((w+1)); warn "$(_t "$lbl")"; }; }
echo "" echo ""
echo -e " ${C_BOLD}$(_t "Commands:")${C_RESET}" echo -e " ${C_BOLD}$(_t "Commands:")${C_RESET}"
checkw "Git" command -v git; checkw "Node.js" command -v node; checkw "Yarn" command -v yarn checkw "Git" command -v git; checkw "Node.js" command -v node; checkw "Yarn" command -v yarn
@@ -1503,6 +1549,9 @@ cmd_health() {
local cerr=0 local cerr=0
for cf in "$NITRO_SRC_DIR"/*.json; do for cf in "$NITRO_SRC_DIR"/*.json; do
[ -f "$cf" ] || continue [ -f "$cf" ] || continue
case "$(basename "$cf")" in
*jsonc*|*.example*) continue ;;
esac
python3 -m json.tool "$cf" >/dev/null 2>&1 || cerr=$((cerr+1)) python3 -m json.tool "$cf" >/dev/null 2>&1 || cerr=$((cerr+1))
done done
[ "$cerr" -eq 0 ] && ok "$(_t "All JSON valid")" || warn "$(_t "JSON errors:") $cerr" [ "$cerr" -eq 0 ] && ok "$(_t "All JSON valid")" || warn "$(_t "JSON errors:") $cerr"
@@ -1528,7 +1577,7 @@ cmd_health() {
fi fi
done done
echo -e "\n ${C_BOLD}$(_t "Directories:")${C_RESET}" echo -e "\n ${C_BOLD}$(_t "Directories:")${C_RESET}"
checkw "Emulator" test -d "$EMULATOR_DIR/Emulator"; checkw "Nitro-V3" test -d "$NITRO_CLIENT"; checkw "Renderer" test -d "$NITRO_RENDERER" checkw "Emulator" test -d "$EMULATOR_MODULE"; checkw "Nitro-V3" test -d "$NITRO_CLIENT"; checkw "Renderer" test -d "$NITRO_RENDERER"
checkw "$(_t "Gamedata config")" test -d "$GAMEDATA_CONF_DIR"; checkw "$(_t "Backup dir")" test -d "$BACKUP_DIR" checkw "$(_t "Gamedata config")" test -d "$GAMEDATA_CONF_DIR"; checkw "$(_t "Backup dir")" test -d "$BACKUP_DIR"
echo -e "\n ${C_BOLD}$(_t "Services:")${C_RESET}" echo -e "\n ${C_BOLD}$(_t "Services:")${C_RESET}"
checkw "MariaDB" service_active mariadb; checkw "Nginx" service_active nginx; checkw "Redis" service_active redis-server checkw "MariaDB" service_active mariadb; checkw "Nginx" service_active nginx; checkw "Redis" service_active redis-server
@@ -1583,7 +1632,7 @@ cmd_flyaway_repair() {
step 2 6 "$(_t "Flyaway Repair")" step 2 6 "$(_t "Flyaway Repair")"
local repaired=0 local repaired=0
for repo in "$EMULATOR_DIR/Emulator" "$NITRO_CLIENT" "$NITRO_RENDERER"; do for repo in "$EMULATOR_REPO" "$NITRO_CLIENT" "$NITRO_RENDERER"; do
[ -d "$repo/.git" ] || continue [ -d "$repo/.git" ] || continue
local name; name=$(basename "$repo") local name; name=$(basename "$repo")
info "Checking %s..." "$name" info "Checking %s..." "$name"
@@ -1649,9 +1698,9 @@ cmd_flyaway_repair() {
fi fi
# Rebuild emulator if jar is missing # Rebuild emulator if jar is missing
if [ ! -d "$EMULATOR_DIR/Emulator/target" ] || ! ls "$EMULATOR_DIR/Emulator/target"/Polaris-*-jar-with-dependencies.jar &>/dev/null 2>&1; then if [ ! -d "$EMULATOR_MODULE/target" ] || ! ls "$EMULATOR_MODULE"/target/Polaris-*-jar-with-dependencies.jar &>/dev/null 2>&1; then
step 6 6 "$(_t "Rebuild Emulator")" step 6 6 "$(_t "Rebuild Emulator")"
cd "$EMULATOR_DIR/Emulator" cd "$EMULATOR_MODULE"
backup_binaries backup_binaries
ROLLBACK_NEEDED=true ROLLBACK_NEEDED=true
spinner_start "$(_t "Building emulator (parallel)...")" spinner_start "$(_t "Building emulator (parallel)...")"
@@ -1672,7 +1721,7 @@ cmd_flyaway_repair() {
do_restart do_restart
show_summary show_summary
sudo chown -R www-data:www-data /var/www/Nitro-V3/ sudo chown -R www-data:www-data "$NITRO_CLIENT/"
release_lock release_lock
} }
@@ -1789,7 +1838,7 @@ cmd_clean() {
4) find "$EMULATOR_DIR" -name "*.log" -mtime +14 -exec rm -f {} \; 2>/dev/null; ok "Logs cleaned" ;; 4) find "$EMULATOR_DIR" -name "*.log" -mtime +14 -exec rm -f {} \; 2>/dev/null; ok "Logs cleaned" ;;
5) yarn cache clean 2>/dev/null; find "$EMULATOR_DIR" -name "*.log" -mtime +14 -exec rm -f {} \; 2>/dev/null; rm -rf /tmp/nitro-* /tmp/epicnext-* 2>/dev/null; ok "Full cleanup" ;; 5) yarn cache clean 2>/dev/null; find "$EMULATOR_DIR" -name "*.log" -mtime +14 -exec rm -f {} \; 2>/dev/null; rm -rf /tmp/nitro-* /tmp/epicnext-* 2>/dev/null; ok "Full cleanup" ;;
6) command -v docker &>/dev/null && docker system prune -f 2>/dev/null && ok "Docker pruned" || warn "Docker N/A" ;; 6) command -v docker &>/dev/null && docker system prune -f 2>/dev/null && ok "Docker pruned" || warn "Docker N/A" ;;
7) find "$EMULATOR_DIR/Emulator" -maxdepth 3 -name '*.jar' -mtime +7 -exec rm -f {} \; 2>/dev/null; ok "Old Maven artifacts cleaned" ;; 7) find "$EMULATOR_MODULE" -maxdepth 3 -name '*.jar' -mtime +7 -exec rm -f {} \; 2>/dev/null; ok "Old Maven artifacts cleaned" ;;
esac esac
} }
@@ -1802,7 +1851,7 @@ cmd_gitlog() {
echo -e " ${C_BOLD}1)${C_RESET} $(_t "Emulator") ${C_BOLD}2)${C_RESET} $(_t "Nitro-V3") ${C_BOLD}3)${C_RESET} $(_t "Renderer")" echo -e " ${C_BOLD}1)${C_RESET} $(_t "Emulator") ${C_BOLD}2)${C_RESET} $(_t "Nitro-V3") ${C_BOLD}3)${C_RESET} $(_t "Renderer")"
echo -en "\n $(_t "Select:") "; local c; read -rt 30 c echo -en "\n $(_t "Select:") "; local c; read -rt 30 c
local repo="" local repo=""
case "$c" in 1) repo="$EMULATOR_DIR/Emulator" ;; 2) repo="$NITRO_CLIENT" ;; 3) repo="$NITRO_RENDERER" ;; *) return ;; esac case "$c" in 1) repo="$EMULATOR_REPO" ;; 2) repo="$NITRO_CLIENT" ;; 3) repo="$NITRO_RENDERER" ;; *) return ;; esac
[ ! -d "$repo/.git" ] && { warn "Not a git repo"; return; } [ ! -d "$repo/.git" ] && { warn "Not a git repo"; return; }
echo "" echo ""
local branch local branch
@@ -1832,7 +1881,7 @@ cmd_compare() {
[[ "$ba" =~ ^[0-9]+$ ]] && [[ "$bb" =~ ^[0-9]+$ ]] && [ "$ba" -ge 1 ] && [ "$bb" -ge 1 ] && [ "$ba" -le ${#branches[@]} ] && [ "$bb" -le ${#branches[@]} ] || { warn "Invalid"; return; } [[ "$ba" =~ ^[0-9]+$ ]] && [[ "$bb" =~ ^[0-9]+$ ]] && [ "$ba" -ge 1 ] && [ "$bb" -ge 1 ] && [ "$ba" -le ${#branches[@]} ] && [ "$bb" -le ${#branches[@]} ] || { warn "Invalid"; return; }
local bA="${branches[$((ba-1))]}" bB="${branches[$((bb-1))]}" local bA="${branches[$((ba-1))]}" bB="${branches[$((bb-1))]}"
echo "" echo ""
for repo in "$EMULATOR_DIR/Emulator" "$NITRO_CLIENT" "$NITRO_RENDERER"; do for repo in "$EMULATOR_REPO" "$NITRO_CLIENT" "$NITRO_RENDERER"; do
[ -d "$repo/.git" ] || continue [ -d "$repo/.git" ] || continue
echo -e " ${C_BOLD}$(basename "$repo"):${C_RESET}" echo -e " ${C_BOLD}$(basename "$repo"):${C_RESET}"
cd "$repo" 2>/dev/null || continue cd "$repo" 2>/dev/null || continue
@@ -1873,7 +1922,7 @@ cmd_schedule() {
cmd_stash() { cmd_stash() {
step 1 1 "Git Stashes" step 1 1 "Git Stashes"
local found=false local found=false
for repo in "$EMULATOR_DIR/Emulator" "$NITRO_CLIENT" "$NITRO_RENDERER"; do for repo in "$EMULATOR_REPO" "$NITRO_CLIENT" "$NITRO_RENDERER"; do
[ -d "$repo/.git" ] || continue [ -d "$repo/.git" ] || continue
local list local list
list=$(cd "$repo" && git stash list 2>/dev/null) list=$(cd "$repo" && git stash list 2>/dev/null)
@@ -2103,6 +2152,14 @@ main() {
done done
[ -z "$cmd" ] && cmd="interactive" [ -z "$cmd" ] && cmd="interactive"
# Auto-detect the branch from the emulator repo when none was configured,
# so "Quick Update — current branch" actually updates the current branch.
if [ -z "${NITRO_BRANCH:-}" ]; then
NITRO_BRANCH="$(cd "$EMULATOR_REPO" 2>/dev/null && git branch --show-current 2>/dev/null || echo "main")"
[ -z "$NITRO_BRANCH" ] && NITRO_BRANCH="main"
info "Auto-detected branch: %s" "$NITRO_BRANCH"
fi
if [ -z "${NITRO_SITE_URL:-}" ] && [ -n "${APP_URL:-}" ]; then NITRO_SITE_URL="$APP_URL"; fi if [ -z "${NITRO_SITE_URL:-}" ] && [ -n "${APP_URL:-}" ]; then NITRO_SITE_URL="$APP_URL"; fi
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://}" ;;