From b013c3e33ea453a9355ddfbca62c3fa854c7fbc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Fri, 25 Apr 2025 09:42:10 +0200 Subject: [PATCH] implement rewatching polling strategy --- tools/fs/safe-watcher.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tools/fs/safe-watcher.ts b/tools/fs/safe-watcher.ts index a0b90c6c25..32fe547e88 100644 --- a/tools/fs/safe-watcher.ts +++ b/tools/fs/safe-watcher.ts @@ -204,6 +204,8 @@ function isSymbolicLink(absPath: string, addToRoots = true): boolean { // Add the directory containing the symlink to the symlinkRoots set const symlinkRoot = toPosixPath(absPath); symlinkRoots.add(symlinkRoot); + // Rewatch using polling any existing watchers under this symlink root + rewatchPolling(symlinkRoot); } return true; } @@ -542,6 +544,35 @@ function startPolling(absPath: string, callback: ChangeCallback): SafeWatcher { }; } +/** + * Rewatch entries under a symlink root from native watchers to polling watchers. + * This is called when a new symlink root is discovered. + */ +function rewatchPolling(root: string) { + for (const [watchedPath, entry] of entries) { + // if it lives under the new symlink root... + if (watchedPath === root || + (watchedPath.startsWith(root) && watchedPath.charAt(root.length) === '/')) { + // Skip if entry is null or already closed + if (!entry) continue; + + // Store the callbacks before closing the entry + const callbacks = Array.from(entry.callbacks); + + // Tear down the old native watcher + entry.close(); + + // Remove it from the map + entries.delete(watchedPath); + + // Re-watch via polling for each callback + for (const cb of callbacks) { + startPolling(watchedPath, cb); + } + } + } +} + /** * Fall back to polling. If a critical error occurs, * we disable native watching and close all existing native watchers.