Merge pull request #32745 from microsoft/fsWatchInode
Change to missing file watcher on linux and darwin explicitly to avoid watching deleted inode
This commit is contained in:
commit
b84e65db4e
|
@ -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;
|
||||
|
@ -730,6 +733,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 +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;
|
||||
let lastDirectoryPartWithDirectorySeparator: string | undefined;
|
||||
let lastDirectoryPart: string | undefined;
|
||||
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() :
|
||||
|
@ -1046,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", "");
|
||||
|
||||
|
@ -1072,11 +1083,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,11 +1102,24 @@ 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 ubuntu while watching 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
|
||||
*/
|
||||
function watchPresentFileSystemEntryWithFsWatchFile(): FileWatcher {
|
||||
sysLog(`sysLog:: ${fileOrDirectory}:: Changing to fsWatchFile`);
|
||||
return fallbackPollingWatchFile(fileOrDirectory, createFileWatcherCallback(callback), pollingInterval);
|
||||
}
|
||||
|
||||
|
|
|
@ -370,6 +370,9 @@ namespace ts {
|
|||
const createFileWatcher: CreateFileWatcher<WatchFileHost, PollingInterval, FileWatcherEventKind, never, X, Y> = getCreateFileWatcher(watchLogLevel, watchFile);
|
||||
const createFilePathWatcher: CreateFileWatcher<WatchFileHost, PollingInterval, FileWatcherEventKind, Path, X, Y> = watchLogLevel === WatchLogLevel.None ? watchFilePath : createFileWatcher;
|
||||
const createDirectoryWatcher: CreateFileWatcher<WatchDirectoryHost, WatchDirectoryFlags, undefined, never, X, Y> = 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),
|
||||
|
|
Loading…
Reference in a new issue