diff --git a/packages/bruno-electron/src/app/watcher.js b/packages/bruno-electron/src/app/watcher.js index 1b2e19d4a..43d01153d 100644 --- a/packages/bruno-electron/src/app/watcher.js +++ b/packages/bruno-electron/src/app/watcher.js @@ -44,13 +44,6 @@ const isCollectionRootBruFile = (pathname, collectionPath) => { return dirname === collectionPath && basename === 'collection.bru'; }; -const isPathInside = (childPath, parentPath) => { - const absoluteChildPath = path.resolve(childPath); - const absoluteParentPath = path.resolve(parentPath); - return absoluteChildPath.startsWith(absoluteParentPath); -} - - const hydrateRequestWithUuid = (request, pathname) => { request.uid = getRequestUid(pathname); @@ -396,6 +389,8 @@ const change = async (win, pathname, collectionUid, collectionPath) => { }; const unlink = (win, pathname, collectionUid, collectionPath) => { + console.log(`watcher unlink: ${pathname}`); + if (isBruEnvironmentConfig(pathname, collectionPath)) { return unlinkEnvironmentFile(win, pathname, collectionUid); } @@ -514,29 +509,32 @@ class Watcher { } } - getWatcherForPath(_path) { + getWatcherByItemPath(itemPath) { const paths = Object.keys(this.watchers); - return paths.find(parentFolder => isPathInside(_path, parentFolder)); + + const watcherPath = paths?.find(collectionPath => { + const absCollectionPath = path.resolve(collectionPath); + const absItemPath = path.resolve(itemPath); + + return absItemPath.startsWith(absCollectionPath); + }); + + return watcherPath ? this.watchers[watcherPath] : null; } - - unlink(_path) { - const watcherPath = this.getWatcherForPath(_path); - if (watcherPath) { - const _watcher = this.watchers[watcherPath]; - _watcher.unwatch(_path); + + unlinkItemPathInWatcher(itemPath) { + const watcher = this.getWatcherByItemPath(itemPath); + if (watcher) { + watcher.unwatch(itemPath); } } - add(_path) { - const watcherPath = this.getWatcherForPath(_path); - if (watcherPath) { - const _watcher = this.watchers[watcherPath]; - if (!_watcher?.has?.(_path)) { - _watcher?.add?.(_path); - } + addItemPathInWatcher(itemPath) { + const watcher = this.getWatcherByItemPath(itemPath); + if (watcher && !watcher?.has?.(itemPath)) { + watcher?.add?.(itemPath); } } - } module.exports = Watcher; diff --git a/packages/bruno-electron/src/ipc/collection.js b/packages/bruno-electron/src/ipc/collection.js index 2c4ff3a84..8ca24ebcb 100644 --- a/packages/bruno-electron/src/ipc/collection.js +++ b/packages/bruno-electron/src/ipc/collection.js @@ -22,7 +22,7 @@ const { safeToRename, isWindowsOS, isValidFilename, - hasSubFolders, + hasSubDirectories, } = require('../utils/filesystem'); const { openCollectionDialog } = require('../app/collections'); const { generateUidBasedOnHash, stringifyJson, safeParseJSON, safeStringifyJSON } = require('../utils/common'); @@ -345,6 +345,11 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection // rename item ipcMain.handle('renderer:rename-item', async (event, oldPath, newPath, newName) => { const tempDir = path.join(os.tmpdir(), `temp-folder-${Date.now()}`); + const parentDir = path.dirname(oldPath); + const isWindowsOSAndNotWSLAndItemHasSubDirectories = isWindowsOS() && !isWSLPath(oldPath) && hasSubDirectories(oldPath); + let parentDirUnwatched = false; + let parentDirRewatched = false; + try { // Normalize paths if they are WSL paths oldPath = isWSLPath(oldPath) ? normalizeWslPath(oldPath) : normalizeAndResolvePath(oldPath); @@ -367,10 +372,19 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection moveRequestUid(bruFile, newBruFilePath); } - watcher.unlink(path.dirname(oldPath)); + watcher.unlinkItemPathInWatcher(parentDir); + parentDirUnwatched = true; - if (isWindowsOS() && !isWSLPath(oldPath) && hasSubFolders(oldPath)) { - console.log('Windows OS: Moving folder with subfolders'); + /** + * If it is windows OS + * And it is not WSL path (meaning its not linux running on windows using WSL) + * And it has sub directories + * Only then we need to use the temp dir approach to rename the folder + * + * Windows OS would sometimes throw error when renaming a folder with sub directories + * This is a alternative approach to avoid that error + */ + if (isWindowsOSAndNotWSLAndItemHasSubDirectories) { await fsExtra.copy(oldPath, tempDir); await fsExtra.remove(oldPath); await fsExtra.move(tempDir, newPath, { overwrite: true }); @@ -378,7 +392,9 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection } else { await fs.renameSync(oldPath, newPath); } - watcher.add(path.dirname(newPath)); + watcher.addItemPathInWatcher(parentDir); + parentDirRewatched = true; + return newPath; } @@ -402,11 +418,15 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection return newPath; } catch (error) { - // add path back to watcher in case an error during the rename file operations - // adds unlinked path back to watcher if doesn't exist - watcher.add(path.dirname(oldPath)); - - if (isWindowsOS() && !isWSLPath(oldPath)) { + // in case an error occurs during the rename file operations after unlinking the parent dir + // and the rewatch fails, we need to add it back to watcher + if (parentDirUnwatched && !parentDirRewatched) { + watcher.addItemPathInWatcher(parentDir); + } + + // in case the rename file operations fails, and we see that the temp dir exists + // and the old path does not exist, we need to restore the data from the temp dir to the old path + if (isWindowsOSAndNotWSLAndItemHasSubDirectories) { if (fsExtra.pathExistsSync(tempDir) && !fsExtra.pathExistsSync(oldPath)) { try { await fsExtra.copy(tempDir, oldPath); @@ -416,6 +436,7 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection } } } + return Promise.reject(error); } }); diff --git a/packages/bruno-electron/src/utils/filesystem.js b/packages/bruno-electron/src/utils/filesystem.js index bd4e0aec0..ec393bd51 100644 --- a/packages/bruno-electron/src/utils/filesystem.js +++ b/packages/bruno-electron/src/utils/filesystem.js @@ -38,8 +38,7 @@ const isDirectory = (dirPath) => { } }; -const hasSubFolders = (dir) => { - console.log('Checking for subfolders in:', dir); +const hasSubDirectories = (dir) => { const files = fs.readdirSync(dir); return files.some(file => fs.statSync(path.join(dir, file)).isDirectory()); }; @@ -231,5 +230,5 @@ module.exports = { isWindowsOS, safeToRename, isValidFilename, - hasSubFolders + hasSubDirectories };