From c6c8301ea180bbdc3d16d2745c37ee9288f45238 Mon Sep 17 00:00:00 2001 From: Brian Madison Date: Mon, 13 Apr 2026 00:52:41 -0500 Subject: [PATCH] fix(installer): add move() and overwrite support to fs-native MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing move() with cross-device fallback (rename → copy+rm on EXDEV), needed by OfficialModules.createModuleDirectories for directory migrations during upgrades. Honor overwrite/errorOnExist options in copy() to match fs-extra behavior for callers that pass these flags. --- tools/installer/fs-native.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tools/installer/fs-native.js b/tools/installer/fs-native.js index 6adeb1032..b6a4abfa5 100644 --- a/tools/installer/fs-native.js +++ b/tools/installer/fs-native.js @@ -24,11 +24,21 @@ async function remove(p) { async function copy(src, dest, options = {}) { const filterFn = options.filter; + const overwrite = options.overwrite !== false; const srcStat = await fsp.stat(src); if (srcStat.isFile()) { if (filterFn && !(await filterFn(src, dest))) return; await fsp.mkdir(path.dirname(dest), { recursive: true }); + if (!overwrite) { + try { + await fsp.access(dest); + if (options.errorOnExist) throw new Error(`${dest} already exists`); + return; + } catch (error) { + if (error.message.includes('already exists')) throw error; + } + } await fsp.copyFile(src, dest); return; } @@ -43,6 +53,19 @@ async function copy(src, dest, options = {}) { } } +async function move(src, dest) { + try { + await fsp.rename(src, dest); + } catch (error) { + if (error.code === 'EXDEV') { + await copy(src, dest); + await fsp.rm(src, { recursive: true, force: true }); + } else { + throw error; + } + } +} + function readJsonSync(p) { return JSON.parse(fs.readFileSync(p, 'utf8')); } @@ -72,6 +95,7 @@ module.exports = { ensureDir, remove, copy, + move, readJsonSync, writeJson,