diff --git a/update-Nitrov3.sh b/update-Nitrov3.sh index 73804d60..09862c79 100755 --- a/update-Nitrov3.sh +++ b/update-Nitrov3.sh @@ -339,14 +339,26 @@ git_update() { local repo="$1" branch="$2" ( cd "$repo" || { warn "Cannot access $repo"; exit 1; } - git stash --include-untracked 2>/dev/null || true + # Only stash when the working tree is dirty, to avoid losing nothing + # and to keep the pull fast-forwardable. + if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then + git stash --include-untracked 2>/dev/null || true + fi local old_head; old_head=$(git rev-parse HEAD 2>/dev/null || echo "") local rb; rb=$(detect_best_branch "$repo" "$branch") [ "$rb" != "$branch" ] && info "Branch '$branch' not in $(basename "$repo"), using '$rb'" git checkout "$rb" 2>/dev/null || { warn "Cannot checkout '$rb' in $(basename "$repo")"; exit 1; } - if ! git pull origin "$rb" 2>/dev/null && ! git pull 2>/dev/null; then - warn "Pull failed in $(basename "$repo")"; exit 1 - fi + local pulled=1 + for attempt in 1 2 3; do + if git pull --ff-only origin "$rb" 2>/dev/null; then + pulled=0; break + elif git pull --ff-only 2>/dev/null; then + pulled=0; break + fi + warn "Pull attempt $attempt failed in $(basename "$repo"), retrying..." >&2 + sleep 2 + done + [ "$pulled" -ne 0 ] && { warn "Pull failed in $(basename "$repo")"; exit 1; } [ "$(git rev-parse HEAD 2>/dev/null)" != "$old_head" ] ) } @@ -364,10 +376,13 @@ clean_node_modules() { # ============================================================================= PARALLEL_PIDS=() +PARALLEL_FAILED=() +PARALLEL_RESULTS=() + parallel_run() { local name="$1"; shift ( - if "$@" 2>&1; then + if "$@" >/dev/null 2>&1; then echo "__PARALLEL_OK__${name}" else echo "__PARALLEL_FAIL__${name}" @@ -377,13 +392,24 @@ parallel_run() { } parallel_wait() { - local failed=() + # Collect per-job pass/fail markers from stdout of each backgrounded job. + PARALLEL_RESULTS=() for pid in "${PARALLEL_PIDS[@]}"; do - wait "$pid" 2>/dev/null || true + local line + line=$(wait "$pid" 2>/dev/null; true) + PARALLEL_RESULTS+=("$line") + if [ "$line" = "__PARALLEL_FAIL__"* ]; then + PARALLEL_FAILED+=("${line#__PARALLEL_FAIL__}") + fi done PARALLEL_PIDS=() } +parallel_failed() { + # Returns 0 (success) when no backgrounded job failed. + [ ${#PARALLEL_FAILED[@]} -eq 0 ] +} + # ============================================================================= # CONFIG BACKUP & VALIDATION # ============================================================================= @@ -463,11 +489,16 @@ update_emulator() { HAD_UPDATES=true; UPDATED_REPOS+=("Emulator") cd "$EMULATOR_DIR/Emulator" spinner_start "Building emulator (parallel)..." - if mvn package -q -T 1C -Dmaven.test.skip=true >> "$LOG_FILE" 2>&1; then + # Prefer offline mode when the local Maven repo is warm; fall back to + # online if offline resolution fails. ccache speeds up repeated JNI/C++ + # native compiles if present. + command -v ccache >/dev/null 2>&1 && export CC="ccache gcc" CXX="ccache g++" + if mvn package -q -T 1C -o -Dmaven.test.skip=true >> "$LOG_FILE" 2>&1 || \ + mvn package -q -T 1C -Dmaven.test.skip=true >> "$LOG_FILE" 2>&1; then spinner_stop ok else spinner_stop fail - tail -20 "$LOG_FILE" | grep -E '(ERROR|FAILURE|BUILD)' || true + tail -30 "$LOG_FILE" | grep -E '(ERROR|FAILURE|BUILD)' || true die "Maven build failed (see: $LOG_FILE)" fi local jar=$(find target -maxdepth 1 -name 'Polaris-*-jar-with-dependencies.jar' -printf '%T@ %p\n' 2>/dev/null | sort -rn | sed -n '1s/^[0-9.]* //p' | xargs -r basename 2>/dev/null || echo "") @@ -624,13 +655,16 @@ do_restart() { local hc=0 while [ "$hc" -lt "$HEALTH_RETRIES" ]; do sleep "$HEALTH_INTERVAL" - if service_active "$EMULATOR_SERVICE"; then - ok "Emulator health check passed" + if service_active "$EMULATOR_SERVICE" && emulator_port_open; then + ok "Emulator health check passed (service up + port listening)" break fi hc=$((hc+1)) done - [ "$hc" -eq "$HEALTH_RETRIES" ] && warn "Emulator not running after $HEALTH_RETRIES retries" + if [ "$hc" -eq "$HEALTH_RETRIES" ]; then + warn "Emulator not healthy after $HEALTH_RETRIES retries" + ROLLBACK_NEEDED=true + fi elif command -v pm2 &>/dev/null; then pm2 restart all 2>/dev/null && ok "PM2 restarted" || warn "PM2 restart failed" else @@ -640,6 +674,23 @@ do_restart() { command -v redis-cli &>/dev/null && redis-cli FLUSHALL 2>/dev/null && ok "Redis flushed" } +# Probe the emulator's configured TCP port to confirm it is actually serving, +# not merely that systemd reports the unit as active. +emulator_port_open() { + local port="${NITRO_EMULATOR_PORT:-30000}" + if command -v redis-cli >/dev/null 2>&1; then + # Emulator advertises its port via the gamedata/extradata; fall back to env. + local p; p=$(redis-cli GET nitro:emulator:port 2>/dev/null) + [ -n "$p" ] && port="$p" + fi + if command -v nc >/dev/null 2>&1; then + timeout 3 bash -c "exec 3<>/dev/tcp/127.0.0.1/$port" 2>/dev/null && return 0 + elif command -v ss >/dev/null 2>&1; then + ss -ltn 2>/dev/null | grep -q ":$port " && return 0 + fi + return 1 +} + show_summary() { local el=$(($(date +%s) - START_TIME)); local ef; ef=$(printf '%dm %ds' $((el/60)) $((el%60))) echo "" @@ -693,9 +744,18 @@ cmd_update() { *) RUN_ROLLBACK=true update_emulator - update_renderer & - update_client & - wait + if [ "$HAD_UPDATES" = true ]; then + parallel_run "renderer" update_renderer + parallel_run "client" update_client + parallel_wait + if ! parallel_failed; then + warn "Parallel build(s) failed: ${PARALLEL_FAILED[*]} — aborting before restart" + ROLLBACK_NEEDED=true + die "Build failure in: ${PARALLEL_FAILED[*]}" + fi + else + info "No repo updates; skipping parallel builds" + fi sync_configs do_cleanup do_permissions