From 19e5859e111dd7a7177e0f03895fcc12a104134a Mon Sep 17 00:00:00 2001 From: Gergo Magyar Date: Tue, 9 Jun 2026 13:12:17 +0000 Subject: [PATCH] fix(install): preserve the backup and warn loudly on a failed materialize rollback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If renameSync(partial, dest) failed AND the rollback renameSync(backup, dest) also failed, the grammar was left unmaterialized (node_modules/ missing) with only a generic "could not materialize" warning — the recoverable backup at .materialize-bak was unmentioned. Emit a CRITICAL warning naming the backup path and the recovery command on that double-failure, and document that the fail-soft catch removes only the scratch `partial`, never the `backup` (which may be the sole recoverable copy). Never-throw / exit-0 contract intact. --- gitnexus/scripts/materialize-vendor-grammars.cjs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/gitnexus/scripts/materialize-vendor-grammars.cjs b/gitnexus/scripts/materialize-vendor-grammars.cjs index b94df815d..fc9a15919 100644 --- a/gitnexus/scripts/materialize-vendor-grammars.cjs +++ b/gitnexus/scripts/materialize-vendor-grammars.cjs @@ -63,20 +63,31 @@ for (const name of VENDORED_GRAMMARS) { fs.renameSync(partial, dest); } catch (renameErr) { // Best-effort rollback: restore the previous dest from backup. + let restored = false; if (fs.existsSync(backup)) { try { fs.renameSync(backup, dest); + restored = true; } catch { - // If rollback also fails, the prior backup directory still exists on - // disk — the catch block below surfaces both errors via the warning. + // Rollback also failed — dest is now missing. Leave the backup in + // place (the catch below will NOT remove it) and surface where it is. } } + if (!restored && fs.existsSync(backup)) { + console.warn( + `[gitnexus] CRITICAL: could not materialize vendor/${name} AND could not restore the ` + + `previous node_modules/${name}. A recoverable copy remains at ${backup} — ` + + `restore it (e.g. \`mv ${backup} ${dest}\`) or reinstall to recover ${name}.`, + ); + } throw renameErr; } fs.rmSync(backup, { recursive: true, force: true }); } catch (err) { // Fail-soft: a single locked/inaccessible file (common on Windows) must not // abort the whole gitnexus install. Matches build-tree-sitter-*.cjs pattern. + // Only remove the scratch `partial`; never the `backup` (it may be the sole + // recoverable copy after a failed rollback above). fs.rmSync(partial, { recursive: true, force: true }); console.warn(`[gitnexus] Could not materialize vendor/${name}: ${err.message}`); console.warn(