Merge pull request #19058 from Microsoft/whenWatchesFail

Swallow the directory watcher exceptions and ignore them
This commit is contained in:
Sheetal Nandi
2017-10-10 18:32:22 -07:00
committed by GitHub
14 changed files with 79 additions and 25 deletions

View File

@@ -1218,7 +1218,7 @@ namespace ts.server {
projectRootPath?: NormalizedPath) {
let searchPath = asNormalizedPath(getDirectoryPath(info.fileName));
while (!projectRootPath || searchPath.indexOf(projectRootPath) >= 0) {
while (!projectRootPath || stringContains(searchPath, projectRootPath)) {
const canonicalSearchPath = normalizedPathToPath(searchPath, this.currentDirectory, this.toCanonicalFileName);
const tsconfigFileName = asNormalizedPath(combinePaths(searchPath, "tsconfig.json"));
let result = action(tsconfigFileName, combinePaths(canonicalSearchPath, "tsconfig.json"));

View File

@@ -753,10 +753,23 @@ namespace ts.server {
const sys = <ServerHost>ts.sys;
// use watchGuard process on Windows when node version is 4 or later
const useWatchGuard = process.platform === "win32" && getNodeMajorVersion() >= 4;
const originalWatchDirectory: ServerHost["watchDirectory"] = sys.watchDirectory.bind(sys);
const noopWatcher: FileWatcher = { close: noop };
// This is the function that catches the exceptions when watching directory, and yet lets project service continue to function
// 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 watchDirectorySwallowingException(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher {
try {
return originalWatchDirectory(path, callback, recursive);
}
catch (e) {
logger.info(`Exception when creating directory watcher: ${e.message}`);
return noopWatcher;
}
}
if (useWatchGuard) {
const currentDrive = extractWatchDirectoryCacheKey(sys.resolvePath(sys.getCurrentDirectory()), /*currentDriveKey*/ undefined);
const statusCache = createMap<boolean>();
const originalWatchDirectory = sys.watchDirectory;
sys.watchDirectory = function (path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher {
const cacheKey = extractWatchDirectoryCacheKey(path, currentDrive);
let status = cacheKey && statusCache.get(cacheKey);
@@ -790,14 +803,17 @@ namespace ts.server {
}
if (status) {
// this drive is safe to use - call real 'watchDirectory'
return originalWatchDirectory.call(sys, path, callback, recursive);
return watchDirectorySwallowingException(path, callback, recursive);
}
else {
// this drive is unsafe - return no-op watcher
return { close() { } };
return noopWatcher;
}
};
}
else {
sys.watchDirectory = watchDirectorySwallowingException;
}
// Override sys.write because fs.writeSync is not reliable on Node 4
sys.write = (s: string) => writeMessage(new Buffer(s, "utf8"));

View File

@@ -1608,7 +1608,7 @@ namespace ts.server {
}
// No need to analyze lib.d.ts
const fileNamesInProject = fileNames.filter(value => value.indexOf("lib.d.ts") < 0);
const fileNamesInProject = fileNames.filter(value => !stringContains(value, "lib.d.ts"));
if (fileNamesInProject.length === 0) {
return;
}

View File

@@ -88,7 +88,7 @@ namespace ts.server.typingsInstaller {
this.npmPath = npmLocation !== undefined ? npmLocation : getDefaultNPMLocation(process.argv[0]);
// If the NPM path contains spaces and isn't wrapped in quotes, do so.
if (this.npmPath.indexOf(" ") !== -1 && this.npmPath[0] !== `"`) {
if (stringContains(this.npmPath, " ") && this.npmPath[0] !== `"`) {
this.npmPath = `"${this.npmPath}"`;
}
if (this.log.isEnabled()) {