From e293232f6a4d17cce56e4903dbcae21f1a0722db Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 1 Aug 2019 10:40:03 -0700 Subject: [PATCH 1/6] Change to missing file watcher on linux and darwin explicitly to avoid watching deleted inode --- src/compiler/sys.ts | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 583aaad3cdb..ac710e6992b 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -730,6 +730,7 @@ namespace ts { const nodeVersion = getNodeMajorVersion(); const isNode4OrLater = nodeVersion! >= 4; + const isLinuxOrMacOs = process.platform === "linux" || process.platform === "darwin"; const platform: string = _os.platform(); const useCaseSensitiveFileNames = isFileSystemCaseSensitive(); @@ -1029,6 +1030,12 @@ namespace ts { function fsWatch(fileOrDirectory: string, entryKind: FileSystemEntryKind.File | FileSystemEntryKind.Directory, callback: FsWatchCallback, recursive: boolean, fallbackPollingWatchFile: HostWatchFile, pollingInterval?: number): FileWatcher { let options: any; + const lastDirectoryPartWithDirectorySeparator = isLinuxOrMacOs ? + fileOrDirectory.substr(fileOrDirectory.lastIndexOf(directorySeparator)) : + undefined; + const lastDirectoryPart = isLinuxOrMacOs ? + lastDirectoryPartWithDirectorySeparator!.slice(directorySeparator.length) : + undefined; /** Watcher for the file system entry depending on whether it is missing or present */ let watcher = !fileSystemEntryExists(fileOrDirectory, entryKind) ? watchMissingFileSystemEntry() : @@ -1072,11 +1079,12 @@ namespace ts { } } try { - const presentWatcher = _fs.watch( fileOrDirectory, options, - callback + isLinuxOrMacOs ? + callbackChangingToMissingFileSystemEntry : + callback ); // Watch the missing file or directory or error presentWatcher.on("error", () => invokeCallbackAndUpdateWatcher(watchMissingFileSystemEntry)); @@ -1090,6 +1098,18 @@ namespace ts { } } + function callbackChangingToMissingFileSystemEntry(event: "rename" | "change", relativeName: string | undefined) { + // because relativeName is not guaranteed to be correct we need to check on each rename with few combinations + // Eg on ubuntoo while watchin app/node_modules the relativeName is "node_modules" which is neither relative nor full path + return event === "rename" && + (!relativeName || + relativeName === lastDirectoryPart || + relativeName.lastIndexOf(lastDirectoryPartWithDirectorySeparator!) === relativeName.length - lastDirectoryPartWithDirectorySeparator!.length) && + !fileSystemEntryExists(fileOrDirectory, entryKind) ? + invokeCallbackAndUpdateWatcher(watchMissingFileSystemEntry) : + callback(event, relativeName); + } + /** * Watch the file or directory using fs.watchFile since fs.watch threw exception * Eg. on linux the number of watches are limited and one could easily exhaust watches and the exception ENOSPC is thrown when creating watcher at that point From 8cf8eb1720fe61c48020a42456470ec85e25b4ea Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 1 Aug 2019 14:01:57 -0700 Subject: [PATCH 2/6] Add some logging to the sys.watchFile and sys.watchDirectory --- src/compiler/sys.ts | 5 +++++ src/compiler/watchUtilities.ts | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index ac710e6992b..4418737ec96 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -379,6 +379,9 @@ namespace ts { /*@internal*/ export const ignoredPaths = ["/node_modules/.", "/.git", "/.#"]; + /*@internal*/ + export let sysLog: (s: string) => void = noop; + /*@internal*/ export interface RecursiveDirectoryWatcherHost { watchDirectory: HostWatchDirectory; @@ -1053,6 +1056,7 @@ namespace ts { * @param createWatcher */ function invokeCallbackAndUpdateWatcher(createWatcher: () => FileWatcher) { + sysLog(`sysLog:: ${fileOrDirectory}:: Changing watcher to ${createWatcher === watchPresentFileSystemEntry ? "Present" : "Missing"}FileSystemEntryWatcher`); // Call the callback for current directory callback("rename", ""); @@ -1115,6 +1119,7 @@ namespace ts { * Eg. on linux the number of watches are limited and one could easily exhaust watches and the exception ENOSPC is thrown when creating watcher at that point */ function watchPresentFileSystemEntryWithFsWatchFile(): FileWatcher { + sysLog(`sysLog:: ${fileOrDirectory}:: Changing to fsWatchFile`); return fallbackPollingWatchFile(fileOrDirectory, createFileWatcherCallback(callback), pollingInterval); } diff --git a/src/compiler/watchUtilities.ts b/src/compiler/watchUtilities.ts index 7c11dcf2856..41642ca43b4 100644 --- a/src/compiler/watchUtilities.ts +++ b/src/compiler/watchUtilities.ts @@ -370,6 +370,9 @@ namespace ts { const createFileWatcher: CreateFileWatcher = getCreateFileWatcher(watchLogLevel, watchFile); const createFilePathWatcher: CreateFileWatcher = watchLogLevel === WatchLogLevel.None ? watchFilePath : createFileWatcher; const createDirectoryWatcher: CreateFileWatcher = getCreateFileWatcher(watchLogLevel, watchDirectory); + if (watchLogLevel === WatchLogLevel.Verbose && sysLog === noop) { + sysLog = s => log(s); + } return { watchFile: (host, file, callback, pollingInterval, detailInfo1, detailInfo2) => createFileWatcher(host, file, callback, pollingInterval, /*passThrough*/ undefined, detailInfo1, detailInfo2, watchFile, log, "FileWatcher", getDetailWatchInfo), From 8d902ad75ff60df6792dddeea104d9e43d335f76 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 9 Aug 2019 13:57:47 -0700 Subject: [PATCH 3/6] Update src/compiler/sys.ts Co-Authored-By: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> --- src/compiler/sys.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 4418737ec96..45a67a8fee3 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -1033,7 +1033,12 @@ namespace ts { function fsWatch(fileOrDirectory: string, entryKind: FileSystemEntryKind.File | FileSystemEntryKind.Directory, callback: FsWatchCallback, recursive: boolean, fallbackPollingWatchFile: HostWatchFile, pollingInterval?: number): FileWatcher { let options: any; - const lastDirectoryPartWithDirectorySeparator = isLinuxOrMacOs ? + let lastDirectoryPartWithDirectorySeparator: string | undefined; + let lastDirectoryPart: string | undefined; + if (isLinuxOrMacOs) { + lastDirectoryPartWithDirectorySeparator = fileOrDirectory.substr(fileOrDirectory.lastIndexOf(directorySeparator)); + lastDirectoryPart = lastDirectoryPartWithDirectorySeparator.slice(directorySeparator.length); + } fileOrDirectory.substr(fileOrDirectory.lastIndexOf(directorySeparator)) : undefined; const lastDirectoryPart = isLinuxOrMacOs ? From d6f768d3ee7b34f2c5f3520469a2a09a37dfbecc Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 9 Aug 2019 14:00:40 -0700 Subject: [PATCH 4/6] Update src/compiler/sys.ts Co-Authored-By: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> --- src/compiler/sys.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 45a67a8fee3..96204e2a751 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -1109,7 +1109,7 @@ namespace ts { function callbackChangingToMissingFileSystemEntry(event: "rename" | "change", relativeName: string | undefined) { // because relativeName is not guaranteed to be correct we need to check on each rename with few combinations - // Eg on ubuntoo while watchin app/node_modules the relativeName is "node_modules" which is neither relative nor full path + // Eg on ubuntu while watching app/node_modules the relativeName is "node_modules" which is neither relative nor full path return event === "rename" && (!relativeName || relativeName === lastDirectoryPart || From c1980c78578fbde7300dba073a1b9e024bb10419 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 9 Aug 2019 14:14:30 -0700 Subject: [PATCH 5/6] Fix the incorrectly accepted suggestion --- src/compiler/sys.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 96204e2a751..1a0df8a91c1 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -1039,11 +1039,6 @@ namespace ts { lastDirectoryPartWithDirectorySeparator = fileOrDirectory.substr(fileOrDirectory.lastIndexOf(directorySeparator)); lastDirectoryPart = lastDirectoryPartWithDirectorySeparator.slice(directorySeparator.length); } - fileOrDirectory.substr(fileOrDirectory.lastIndexOf(directorySeparator)) : - undefined; - const lastDirectoryPart = isLinuxOrMacOs ? - lastDirectoryPartWithDirectorySeparator!.slice(directorySeparator.length) : - undefined; /** Watcher for the file system entry depending on whether it is missing or present */ let watcher = !fileSystemEntryExists(fileOrDirectory, entryKind) ? watchMissingFileSystemEntry() : From 850ff783f4dad242119e362314df0882518cf4a6 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 9 Aug 2019 15:13:07 -0700 Subject: [PATCH 6/6] Fix lint error --- src/compiler/sys.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 1a0df8a91c1..b49446dd33e 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -1038,7 +1038,7 @@ namespace ts { if (isLinuxOrMacOs) { lastDirectoryPartWithDirectorySeparator = fileOrDirectory.substr(fileOrDirectory.lastIndexOf(directorySeparator)); lastDirectoryPart = lastDirectoryPartWithDirectorySeparator.slice(directorySeparator.length); - } + } /** Watcher for the file system entry depending on whether it is missing or present */ let watcher = !fileSystemEntryExists(fileOrDirectory, entryKind) ? watchMissingFileSystemEntry() :