fix: use jsonc-parser in config merge and make updater reliably restart all services
merge-config.cjs loaded json5 (not installed, and unable to parse JSONC comments), so sync_configs crashed mid-update and do_restart never ran — leaving the emulator running the old JAR. - merge-config.cjs: switch from json5 to jsonc-parser (already a dependency) to parse .jsonc configs including comments - update-Nitrov3.sh: always run renderer/client parallel builds instead of gating them on the emulator's update status - update-Nitrov3.sh: isolate each repo's yarn cache (--cache-folder) so parallel installs can't corrupt a shared cache and silently drop vite/pixi.js; replace invalid --no-cache flag with per-repo cache reset - update-Nitrov3.sh: fix misleading [DRY-RUN] label on real updates
This commit is contained in:
1 parent
abc06e438c
commit
9e453666e5
2 files changed
+104
-46
No files matched your search
+31
-12
@@ -1,5 +1,5 @@
|
||||
const fs = require("node:fs");
|
||||
const JSON5 = require("json5");
|
||||
const { parse, printParseErrorCode } = require("jsonc-parser");
|
||||
|
||||
const exampleFile = process.argv[2];
|
||||
const targetFile = process.argv[3];
|
||||
@@ -26,28 +26,47 @@ function deepMerge(target, source) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function parseJsonc(file) {
|
||||
if (!fs.existsSync(file)) {
|
||||
return undefined;
|
||||
}
|
||||
const content = fs.readFileSync(file, "utf-8");
|
||||
const errors = [];
|
||||
const value = parse(content, errors, {
|
||||
allowTrailingComma: true,
|
||||
allowEmptyContent: true,
|
||||
});
|
||||
if (errors.length > 0) {
|
||||
console.error(
|
||||
`[merge-config] parse error in ${file}: ${errors
|
||||
.map((e) => printParseErrorCode(e.error))
|
||||
.join(", ")}`,
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
let example;
|
||||
try {
|
||||
const content = fs.readFileSync(exampleFile, "utf-8");
|
||||
example = JSON5.parse(content);
|
||||
example = parseJsonc(exampleFile);
|
||||
} catch {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (example === undefined) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let current = {};
|
||||
try {
|
||||
if (fs.existsSync(targetFile)) {
|
||||
const content = fs.readFileSync(targetFile, "utf-8");
|
||||
current = JSON5.parse(content);
|
||||
const parsed = parseJsonc(targetFile);
|
||||
if (parsed !== undefined && parsed !== null) {
|
||||
current = parsed;
|
||||
}
|
||||
} catch {
|
||||
current = {};
|
||||
}
|
||||
|
||||
const merged = deepMerge(current, example);
|
||||
|
||||
const isJson5 = targetFile.endsWith(".json5");
|
||||
const output = isJson5
|
||||
? JSON5.stringify(merged, null, 4)
|
||||
: JSON.stringify(merged, null, 4);
|
||||
fs.writeFileSync(targetFile, `${output}\n`);
|
||||
fs.writeFileSync(targetFile, `${JSON.stringify(merged, null, 4)}\n`);
|
||||
+73
-34
@@ -116,6 +116,13 @@ BACKUP_DIR="${NITRO_BACKUP_DIR:-$EMULATOR_DIR/Database/Database Updates/backups}
|
||||
NITRO_CLIENT="${NITRO_CLIENT_SRC:-/var/www/Nitro-V3}"
|
||||
NITRO_RENDERER="${NITRO_RENDERER_SRC:-/var/www/Nitro_Render_V3}"
|
||||
NITRO_BRANCH="${NITRO_BRANCH:-}"
|
||||
# Dedicated per-repo yarn cache folders. The renderer + client installs run in
|
||||
# parallel and yarn 1.22 has no cache locking, so a single shared cache gets
|
||||
# corrupted and node_modules is left incomplete (vite/pixi.js missing) while
|
||||
# yarn still exits 0. Isolating each repo's cache via --cache-folder prevents
|
||||
# that race entirely.
|
||||
YARN_CACHE_DIR="${NITRO_YARN_CACHE_DIR:-/var/www/.yarn-cache}"
|
||||
mkdir -p "$YARN_CACHE_DIR" 2>/dev/null || true
|
||||
MIN_DISK_GB="${NITRO_MIN_DISK_GB:-5}"
|
||||
HEALTH_RETRIES="${NITRO_HEALTH_RETRIES:-12}"
|
||||
HEALTH_INTERVAL="${NITRO_HEALTH_INTERVAL:-5}"
|
||||
@@ -925,6 +932,30 @@ clean_node_modules() {
|
||||
rm -rf "node_modules" 2>/dev/null || sudo rm -rf "$(pwd)/node_modules" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# yarn install scoped to a per-repo cache folder. Parallel installs (renderer +
|
||||
# client) must never share a cache — yarn 1 corrupts the shared cache, leaving
|
||||
# node_modules incomplete (vite/pixi.js missing) while still exiting 0.
|
||||
# $1 = repo dir; remaining args forwarded to yarn. Runs inside the repo and
|
||||
# always returns the caller to SCRIPT_DIR so cwd never leaks between repos.
|
||||
yarn_install_repo() {
|
||||
local repo="$1"; shift
|
||||
local cache_dir="$YARN_CACHE_DIR/$(basename "$repo")"
|
||||
mkdir -p "$cache_dir" 2>/dev/null || true
|
||||
cd "$repo" 2>/dev/null || { warn "Cannot cd into %s" "$repo"; return 1; }
|
||||
yarn install --cache-folder "$cache_dir" "$@" >> "$LOG_FILE" 2>&1
|
||||
local rc=$?
|
||||
cd "$SCRIPT_DIR" 2>/dev/null || true
|
||||
return $rc
|
||||
}
|
||||
|
||||
# Nuke a repo's own yarn cache and node_modules for a truly clean reinstall.
|
||||
# Parallel installs may have corrupted the cache, so it must be discarded too.
|
||||
yarn_reset_repo() {
|
||||
local repo="$1"
|
||||
rm -rf "$repo/node_modules" "$YARN_CACHE_DIR/$(basename "$repo")" 2>/dev/null || true
|
||||
mkdir -p "$YARN_CACHE_DIR/$(basename "$repo")" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# PARALLEL HELPERS
|
||||
# =============================================================================
|
||||
@@ -1130,17 +1161,18 @@ update_renderer() {
|
||||
HAD_UPDATES=true; UPDATED_REPOS+=("Nitro_Render_V3")
|
||||
cd "$NITRO_RENDERER"
|
||||
spinner_start "Installing deps..."
|
||||
if ! yarn install --frozen-lockfile --prefer-offline >> "$LOG_FILE" 2>&1; then
|
||||
if ! yarn_install_repo "$NITRO_RENDERER" --frozen-lockfile --prefer-offline; 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"; }
|
||||
yarn_reset_repo "$NITRO_RENDERER"
|
||||
yarn_install_repo "$NITRO_RENDERER" || { spinner_stop fail; die "yarn install failed (see: %s)" "$LOG_FILE"; }
|
||||
fi
|
||||
cd "$NITRO_RENDERER"
|
||||
if [ ! -d node_modules/pixi.js ]; then
|
||||
warn "Renderer: node_modules incomplete — cleaning and doing full install"
|
||||
clean_node_modules
|
||||
# Parallel yarn installs (renderer + client) can corrupt the shared
|
||||
# yarn cache, so force a clean fetch with --no-cache as a last resort.
|
||||
yarn install --no-cache >> "$LOG_FILE" 2>&1 || { spinner_stop fail; die "yarn install failed (see: %s)" "$LOG_FILE"; }
|
||||
warn "Renderer: node_modules incomplete — resetting repo cache and doing full install"
|
||||
# Parallel yarn installs can corrupt a shared cache; resetting the
|
||||
# repo's own cache folder guarantees a clean fetch from the registry.
|
||||
yarn_reset_repo "$NITRO_RENDERER"
|
||||
yarn_install_repo "$NITRO_RENDERER" || { spinner_stop fail; die "yarn install failed (see: %s)" "$LOG_FILE"; }
|
||||
fi
|
||||
spinner_stop ok; ok "Renderer dependencies installed"
|
||||
else
|
||||
@@ -1160,17 +1192,19 @@ update_client() {
|
||||
spinner_start "Installing deps..."
|
||||
# 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
|
||||
if ! yarn_install_repo "$NITRO_CLIENT" --frozen-lockfile --prefer-offline; 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"; }
|
||||
yarn_reset_repo "$NITRO_CLIENT"
|
||||
yarn_install_repo "$NITRO_CLIENT" || { spinner_stop fail; die "yarn install failed (see: %s)" "$LOG_FILE"; }
|
||||
fi
|
||||
cd "$NITRO_CLIENT"
|
||||
if [ ! -x node_modules/.bin/vite ]; then
|
||||
warn "Nitro-V3: vite missing after install — cleaning node_modules and doing full install"
|
||||
clean_node_modules
|
||||
# Parallel yarn installs (renderer + client) can corrupt the shared
|
||||
# yarn cache, so force a clean fetch with --no-cache as a last resort.
|
||||
yarn install --no-cache >> "$LOG_FILE" 2>&1 || { spinner_stop fail; die "yarn install failed (see: %s)" "$LOG_FILE"; }
|
||||
warn "Nitro-V3: vite missing after install — resetting repo cache and doing full install"
|
||||
# Parallel yarn installs can corrupt a shared cache; resetting the
|
||||
# repo's own cache folder guarantees a clean fetch from the registry.
|
||||
yarn_reset_repo "$NITRO_CLIENT"
|
||||
yarn_install_repo "$NITRO_CLIENT" || { spinner_stop fail; die "yarn install failed (see: %s)" "$LOG_FILE"; }
|
||||
cd "$NITRO_CLIENT"
|
||||
fi
|
||||
spinner_stop ok
|
||||
spinner_start "Building frontend..."
|
||||
@@ -1293,7 +1327,10 @@ do_cleanup() {
|
||||
ok "Old config backups pruned"
|
||||
fi
|
||||
[ -d "$BACKUP_DIR" ] && 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
|
||||
# Clean both the global yarn cache and the per-repo caches used by the
|
||||
# parallel renderer/client installs.
|
||||
yarn cache clean 2>/dev/null || true
|
||||
rm -rf "$YARN_CACHE_DIR" 2>/dev/null || true
|
||||
rm -rf /tmp/nitro-* /tmp/epicnext-* 2>/dev/null || true
|
||||
# Clean old Maven build artifacts (older than 7 days)
|
||||
find "$EMULATOR_MODULE" -maxdepth 3 -name '*.jar' -mtime +7 2>/dev/null -exec rm -f {} \; || true
|
||||
@@ -1459,7 +1496,9 @@ cmd_update() {
|
||||
echo ""
|
||||
acquire_lock
|
||||
DRY_RUN=${DRY_RUN:-false}
|
||||
info "Site: %s | Branch: %s | Mode: %s" "${NITRO_SITE_URL:-?}" "$NITRO_BRANCH" "${SELECTIVE_UPDATE:-full}${DRY_RUN:+ [DRY-RUN]}"
|
||||
local mode_label="${SELECTIVE_UPDATE:-full}"
|
||||
[ "$DRY_RUN" = true ] && mode_label="$mode_label [DRY-RUN]"
|
||||
info "Site: %s | Branch: %s | Mode: %s" "${NITRO_SITE_URL:-?}" "$NITRO_BRANCH" "$mode_label"
|
||||
info "Log: %s" "$LOG_FILE"
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
info "Dry-run: would update repos, run DB backups, build, sync configs, cleanup, restart services"
|
||||
@@ -1485,17 +1524,17 @@ cmd_update() {
|
||||
*)
|
||||
RUN_ROLLBACK=true
|
||||
update_emulator
|
||||
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: %s — aborting before restart" "${PARALLEL_FAILED[*]}"
|
||||
ROLLBACK_NEEDED=true
|
||||
die "Build failure in: %s" "${PARALLEL_FAILED[*]}"
|
||||
fi
|
||||
else
|
||||
info "No repo updates; skipping parallel builds"
|
||||
# Always attempt the renderer + client builds in parallel. Each
|
||||
# update_* function runs git_update itself and skips when its repo
|
||||
# is already up to date, so gating these on the emulator's update
|
||||
# status would wrongly skip them when only client/renderer changed.
|
||||
parallel_run "renderer" update_renderer
|
||||
parallel_run "client" update_client
|
||||
parallel_wait
|
||||
if ! parallel_failed; then
|
||||
warn "Parallel build(s) failed: %s — aborting before restart" "${PARALLEL_FAILED[*]}"
|
||||
ROLLBACK_NEEDED=true
|
||||
die "Build failure in: %s" "${PARALLEL_FAILED[*]}"
|
||||
fi
|
||||
sync_configs
|
||||
do_cleanup
|
||||
@@ -1735,14 +1774,14 @@ cmd_flyaway_repair() {
|
||||
# Reinstall dependencies if package.json exists
|
||||
if [ -f "$repo/package.json" ]; then
|
||||
spinner_start "Installing deps for %s..." "$name"
|
||||
if yarn install --frozen-lockfile --prefer-offline 2>/dev/null; then
|
||||
if yarn_install_repo "$repo" --frozen-lockfile --prefer-offline 2>/dev/null; then
|
||||
spinner_stop ok
|
||||
ok "Deps reinstalled for %s" "$name"
|
||||
else
|
||||
spinner_stop fail
|
||||
warn "yarn install failed for %s — cleaning node_modules and retrying" "$name"
|
||||
rm -rf "$repo/node_modules" 2>/dev/null || true
|
||||
yarn install --frozen-lockfile --prefer-offline 2>/dev/null || warn "yarn install still failed for %s" "$name"
|
||||
warn "yarn install failed for %s — resetting repo and retrying" "$name"
|
||||
yarn_reset_repo "$repo"
|
||||
yarn_install_repo "$repo" --frozen-lockfile --prefer-offline 2>/dev/null || warn "yarn install still failed for %s" "$name"
|
||||
fi
|
||||
fi
|
||||
repaired=$((repaired + 1))
|
||||
@@ -1917,11 +1956,11 @@ cmd_clean() {
|
||||
echo -e " ${C_BOLD}7)${C_RESET} $(_t "Maven") ${C_BOLD}0)${C_RESET} $(_t "Return")"
|
||||
echo -en "\n $(_t "Select:") "; local c; read -rt 30 c
|
||||
case "$c" in
|
||||
1) yarn cache clean 2>/dev/null && ok "Yarn cleaned" ;;
|
||||
1) yarn cache clean 2>/dev/null; rm -rf "$YARN_CACHE_DIR" 2>/dev/null; ok "Yarn cleaned" ;;
|
||||
2) cd "$SCRIPT_DIR" && rm -rf .next 2>/dev/null && ok "Next.js cache cleared" ;;
|
||||
3) redis-cli FLUSHALL 2>/dev/null && ok "Redis flushed" || warn "Redis N/A" ;;
|
||||
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; rm -rf "$YARN_CACHE_DIR" 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" ;;
|
||||
7) find "$EMULATOR_MODULE" -maxdepth 3 -name '*.jar' -mtime +7 -exec rm -f {} \; 2>/dev/null; ok "Old Maven artifacts cleaned" ;;
|
||||
esac
|
||||
|
||||
Reference in new issue
Block a user