From e65b8b98245c80bf02c7063a6c507b12af8b3ecd Mon Sep 17 00:00:00 2001 From: ggilmore Date: Thu, 11 Jan 2018 09:19:24 -0800 Subject: [PATCH 1/2] pass --no-use flag in build script --- build/tfs/common/node.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/tfs/common/node.sh b/build/tfs/common/node.sh index 23404689de5..cc1bb74d01f 100755 --- a/build/tfs/common/node.sh +++ b/build/tfs/common/node.sh @@ -4,9 +4,9 @@ set -e # setup nvm if [[ "$OSTYPE" == "darwin"* ]]; then export NVM_DIR=~/.nvm - source $(brew --prefix nvm)/nvm.sh + source $(brew --prefix nvm)/nvm.sh --no-use else - source $NVM_DIR/nvm.sh + source $NVM_DIR/nvm.sh --no-use fi # install node From 38220e32de0852bbfd47116fa4ec8155a56679a0 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 9 Feb 2018 17:11:30 +0100 Subject: [PATCH 2/2] fix #7950 --- .../files/electron-browser/fileService.ts | 32 +++++++++++++++++-- .../node/watcher/nsfw/nsfwWatcherService.ts | 22 +++++++++++-- .../watcher/unix/chokidarWatcherService.ts | 18 +++++++++-- .../files/node/watcher/unix/watcherIpc.ts | 2 +- 4 files changed, 65 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/services/files/electron-browser/fileService.ts b/src/vs/workbench/services/files/electron-browser/fileService.ts index 91518f361e4..99b4e90c588 100644 --- a/src/vs/workbench/services/files/electron-browser/fileService.ts +++ b/src/vs/workbench/services/files/electron-browser/fileService.ts @@ -21,7 +21,6 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import Event, { Emitter } from 'vs/base/common/event'; - import { shell } from 'electron'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { isMacintosh } from 'vs/base/common/platform'; @@ -36,6 +35,9 @@ export class FileService implements IFileService { private static readonly NET_VERSION_ERROR = 'System.MissingMethodException'; private static readonly NET_VERSION_ERROR_IGNORE_KEY = 'ignoreNetVersionError'; + private static readonly ENOSPC_ERROR = 'ENOSPC'; + private static readonly ENOSPC_ERROR_IGNORE_KEY = 'ignoreEnospcError'; + private raw: NodeFileService; private toUnbind: IDisposable[]; @@ -96,13 +98,17 @@ export class FileService implements IFileService { return this._onAfterOperation.event; } - private onFileServiceError(msg: string): void { + private onFileServiceError(error: string | Error): void { + const msg = error ? error.toString() : void 0; + if (!msg) { + return; + } // Forward to unexpected error handler errors.onUnexpectedError(msg); // Detect if we run < .NET Framework 4.5 (TODO@ben remove with new watcher impl) - if (typeof msg === 'string' && msg.indexOf(FileService.NET_VERSION_ERROR) >= 0 && !this.storageService.getBoolean(FileService.NET_VERSION_ERROR_IGNORE_KEY, StorageScope.WORKSPACE)) { + if (msg.indexOf(FileService.NET_VERSION_ERROR) >= 0 && !this.storageService.getBoolean(FileService.NET_VERSION_ERROR_IGNORE_KEY, StorageScope.WORKSPACE)) { this.messageService.show(Severity.Warning, { message: nls.localize('netVersionError', "The Microsoft .NET Framework 4.5 is required. Please follow the link to install it."), actions: [ @@ -120,6 +126,26 @@ export class FileService implements IFileService { ] }); } + + // Detect if we run into ENOSPC issues (TODO@ben remove with new watcher impl) + if (msg.indexOf(FileService.ENOSPC_ERROR) >= 0 && !this.storageService.getBoolean(FileService.ENOSPC_ERROR_IGNORE_KEY, StorageScope.WORKSPACE)) { + this.messageService.show(Severity.Warning, { + message: nls.localize('enospcError', "{0} is running out of file handles. Please follow the instructions link to resolve this issue.", product.nameLong), + actions: [ + new Action('learnMore', nls.localize('learnMore', "Instructions"), null, true, () => { + window.open('https://go.microsoft.com/fwlink/?linkid=867693'); + + return TPromise.as(true); + }), + new Action('enospc.error.ignore', nls.localize('neverShowAgain', "Don't Show Again"), '', true, () => { + this.storageService.store(FileService.ENOSPC_ERROR_IGNORE_KEY, true, StorageScope.WORKSPACE); + + return TPromise.as(null); + }), + CloseAction + ] + }); + } } private registerListeners(): void { diff --git a/src/vs/workbench/services/files/node/watcher/nsfw/nsfwWatcherService.ts b/src/vs/workbench/services/files/node/watcher/nsfw/nsfwWatcherService.ts index 3e17fc59357..e874ca74002 100644 --- a/src/vs/workbench/services/files/node/watcher/nsfw/nsfwWatcherService.ts +++ b/src/vs/workbench/services/files/node/watcher/nsfw/nsfwWatcherService.ts @@ -10,7 +10,7 @@ import * as platform from 'vs/base/common/platform'; import * as watcher from 'vs/workbench/services/files/node/watcher/common'; import * as nsfw from 'nsfw'; import { IWatcherService, IWatcherRequest } from 'vs/workbench/services/files/node/watcher/nsfw/watcher'; -import { TPromise, ProgressCallback, TValueCallback } from 'vs/base/common/winjs.base'; +import { TPromise, ProgressCallback, TValueCallback, ErrorCallback } from 'vs/base/common/winjs.base'; import { ThrottledDelayer } from 'vs/base/common/async'; import { FileChangeType } from 'vs/platform/files/common/files'; import { normalizeNFC } from 'vs/base/common/strings'; @@ -37,13 +37,16 @@ export class NsfwWatcherService implements IWatcherService { private _pathWatchers: { [watchPath: string]: IPathWatcher } = {}; private _watcherPromise: TPromise; private _progressCallback: ProgressCallback; + private _errorCallback: ErrorCallback; private _verboseLogging: boolean; - + private enospcErrorLogged: boolean; public initialize(verboseLogging: boolean): TPromise { - this._verboseLogging = verboseLogging; + this._verboseLogging = true; this._watcherPromise = new TPromise((c, e, p) => { + this._errorCallback = e; this._progressCallback = p; + }); return this._watcherPromise; } @@ -58,6 +61,19 @@ export class NsfwWatcherService implements IWatcherService { ignored: request.ignored }; + process.on('uncaughtException', e => { + + // Specially handle ENOSPC errors that can happen when + // the watcher consumes so many file descriptors that + // we are running into a limit. We only want to warn + // once in this case to avoid log spam. + // See https://github.com/Microsoft/vscode/issues/7950 + if (e === 'Inotify limit reached' && !this.enospcErrorLogged) { + this.enospcErrorLogged = true; + this._errorCallback(new Error('Inotify limit reached (ENOSPC)')); + } + }); + nsfw(request.basePath, events => { for (let i = 0; i < events.length; i++) { const e = events[i]; diff --git a/src/vs/workbench/services/files/node/watcher/unix/chokidarWatcherService.ts b/src/vs/workbench/services/files/node/watcher/unix/chokidarWatcherService.ts index 808b863f0cc..80265380b4c 100644 --- a/src/vs/workbench/services/files/node/watcher/unix/chokidarWatcherService.ts +++ b/src/vs/workbench/services/files/node/watcher/unix/chokidarWatcherService.ts @@ -18,7 +18,7 @@ import strings = require('vs/base/common/strings'); import { realcaseSync } from 'vs/base/node/extfs'; import { isMacintosh } from 'vs/base/common/platform'; import watcher = require('vs/workbench/services/files/node/watcher/common'); -import { IWatcherRequest, IWatcherService } from './watcher'; +import { IWatcherRequest, IWatcherService } from 'vs/workbench/services/files/node/watcher/unix/watcher'; export class ChokidarWatcherService implements IWatcherService { @@ -27,6 +27,7 @@ export class ChokidarWatcherService implements IWatcherService { private spamCheckStartTime: number; private spamWarningLogged: boolean; + private enospcErrorLogged: boolean; public watch(request: IWatcherRequest): TPromise { const watcherOpts: chokidar.IOptions = { @@ -138,7 +139,20 @@ export class ChokidarWatcherService implements IWatcherService { chokidarWatcher.on('error', (error: Error) => { if (error) { - console.error(error.toString()); + + // Specially handle ENOSPC errors that can happen when + // the watcher consumes so many file descriptors that + // we are running into a limit. We only want to warn + // once in this case to avoid log spam. + // See https://github.com/Microsoft/vscode/issues/7950 + if ((error).code === 'ENOSPC') { + if (!this.enospcErrorLogged) { + this.enospcErrorLogged = true; + e(new Error('Inotify limit reached (ENOSPC)')); + } + } else { + console.error(error.toString()); + } } }); }, () => { diff --git a/src/vs/workbench/services/files/node/watcher/unix/watcherIpc.ts b/src/vs/workbench/services/files/node/watcher/unix/watcherIpc.ts index f949ab0e6fe..9fcd515708f 100644 --- a/src/vs/workbench/services/files/node/watcher/unix/watcherIpc.ts +++ b/src/vs/workbench/services/files/node/watcher/unix/watcherIpc.ts @@ -7,7 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IWatcherRequest, IWatcherService } from './watcher'; +import { IWatcherRequest, IWatcherService } from 'vs/workbench/services/files/node/watcher/unix/watcher'; export interface IWatcherChannel extends IChannel { call(command: 'watch', request: IWatcherRequest): TPromise;