diff --git a/src/vs/editor/test/common/mocks/mockExtensionService.ts b/src/vs/editor/test/common/mocks/mockExtensionService.ts deleted file mode 100644 index 039c9ec9eb6..00000000000 --- a/src/vs/editor/test/common/mocks/mockExtensionService.ts +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import Severity from 'vs/base/common/severity'; -import { AbstractExtensionService, ActivatedExtension } from 'vs/platform/extensions/common/abstractExtensionService'; - -export class MockExtensionService extends AbstractExtensionService { - constructor() { - super(true); - } - - protected _showMessage(severity: Severity, msg: string): void { - switch (severity) { - case Severity.Error: - console.error(msg); - break; - case Severity.Warning: - console.warn(msg); - break; - case Severity.Info: - console.info(msg); - break; - default: - console.log(msg); - } - } - - protected _createFailedExtension(): any { - throw new Error('not implemented'); - } - - protected _actualActivateExtension(): any { - throw new Error('not implemented'); - } -} diff --git a/src/vs/platform/extensions/common/abstractExtensionService.ts b/src/vs/platform/extensions/common/abstractExtensionService.ts index a952d903b45..a3146b46c3e 100644 --- a/src/vs/platform/extensions/common/abstractExtensionService.ts +++ b/src/vs/platform/extensions/common/abstractExtensionService.ts @@ -4,288 +4,12 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import * as nls from 'vs/nls'; -import Severity from 'vs/base/common/severity'; -import { TPromise } from 'vs/base/common/winjs.base'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; const hasOwnProperty = Object.hasOwnProperty; -export abstract class ActivatedExtension { - activationFailed: boolean; - - constructor(activationFailed: boolean) { - this.activationFailed = activationFailed; - } -} - -export interface IActivatedExtensionMap { - [extensionId: string]: T; -} - -interface IActivatingExtensionMap { - [extensionId: string]: TPromise; -} - -const NO_OP_VOID_PROMISE = TPromise.as(void 0); - -export interface IExtensionsManagerHost { - showMessage(severity: Severity, message: string): void; - - createFailedExtension(): T; - - actualActivateExtension(extensionDescription: IExtensionDescription): TPromise; -} - -export class ExtensionsManager { - - private readonly _registry: ExtensionDescriptionRegistry; - private readonly _host: IExtensionsManagerHost; - private readonly _activatingExtensions: IActivatingExtensionMap; - private readonly _activatedExtensions: IActivatedExtensionMap; - /** - * A map of already activated events to speed things up if the same activation event is triggered multiple times. - */ - private readonly _alreadyActivatedEvents: { [activationEvent: string]: boolean; }; - - constructor(registry: ExtensionDescriptionRegistry, host: IExtensionsManagerHost) { - this._registry = registry; - this._host = host; - this._activatingExtensions = {}; - this._activatedExtensions = {}; - this._alreadyActivatedEvents = Object.create(null); - } - - public isActivated(extensionId: string): boolean { - return hasOwnProperty.call(this._activatedExtensions, extensionId); - } - - public getActivatedExtension(extensionId: string): T { - if (!hasOwnProperty.call(this._activatedExtensions, extensionId)) { - throw new Error('Extension `' + extensionId + '` is not known or not activated'); - } - return this._activatedExtensions[extensionId]; - } - - public setActivatedExtension(extensionId: string, value: T): void { - this._activatedExtensions[extensionId] = value; - } - - public activateByEvent(activationEvent: string): TPromise { - if (this._alreadyActivatedEvents[activationEvent]) { - return NO_OP_VOID_PROMISE; - } - let activateExtensions = this._registry.getExtensionDescriptionsForActivationEvent(activationEvent); - return this._activateExtensions(activateExtensions, 0).then(() => { - this._alreadyActivatedEvents[activationEvent] = true; - }); - } - - public activateById(extensionId: string): TPromise { - let desc = this._registry.getExtensionDescription(extensionId); - if (!desc) { - throw new Error('Extension `' + extensionId + '` is not known'); - } - - return this._activateExtensions([desc], 0); - } - - /** - * Handle semantics related to dependencies for `currentExtension`. - * semantics: `redExtensions` must wait for `greenExtensions`. - */ - private _handleActivateRequest(currentExtension: IExtensionDescription, greenExtensions: { [id: string]: IExtensionDescription; }, redExtensions: IExtensionDescription[]): void { - let depIds = (typeof currentExtension.extensionDependencies === 'undefined' ? [] : currentExtension.extensionDependencies); - let currentExtensionGetsGreenLight = true; - - for (let j = 0, lenJ = depIds.length; j < lenJ; j++) { - let depId = depIds[j]; - let depDesc = this._registry.getExtensionDescription(depId); - - if (!depDesc) { - // Error condition 1: unknown dependency - this._host.showMessage(Severity.Error, nls.localize('unknownDep', "Extension `{1}` failed to activate. Reason: unknown dependency `{0}`.", depId, currentExtension.id)); - this._activatedExtensions[currentExtension.id] = this._host.createFailedExtension(); - return; - } - - if (hasOwnProperty.call(this._activatedExtensions, depId)) { - let dep = this._activatedExtensions[depId]; - if (dep.activationFailed) { - // Error condition 2: a dependency has already failed activation - this._host.showMessage(Severity.Error, nls.localize('failedDep1', "Extension `{1}` failed to activate. Reason: dependency `{0}` failed to activate.", depId, currentExtension.id)); - this._activatedExtensions[currentExtension.id] = this._host.createFailedExtension(); - return; - } - } else { - // must first wait for the dependency to activate - currentExtensionGetsGreenLight = false; - greenExtensions[depId] = depDesc; - } - } - - if (currentExtensionGetsGreenLight) { - greenExtensions[currentExtension.id] = currentExtension; - } else { - redExtensions.push(currentExtension); - } - } - - private _activateExtensions(extensionDescriptions: IExtensionDescription[], recursionLevel: number): TPromise { - // console.log(recursionLevel, '_activateExtensions: ', extensionDescriptions.map(p => p.id)); - if (extensionDescriptions.length === 0) { - return TPromise.as(void 0); - } - - extensionDescriptions = extensionDescriptions.filter((p) => !hasOwnProperty.call(this._activatedExtensions, p.id)); - if (extensionDescriptions.length === 0) { - return TPromise.as(void 0); - } - - if (recursionLevel > 10) { - // More than 10 dependencies deep => most likely a dependency loop - for (let i = 0, len = extensionDescriptions.length; i < len; i++) { - // Error condition 3: dependency loop - this._host.showMessage(Severity.Error, nls.localize('failedDep2', "Extension `{0}` failed to activate. Reason: more than 10 levels of dependencies (most likely a dependency loop).", extensionDescriptions[i].id)); - this._activatedExtensions[extensionDescriptions[i].id] = this._host.createFailedExtension(); - } - return TPromise.as(void 0); - } - - let greenMap: { [id: string]: IExtensionDescription; } = Object.create(null), - red: IExtensionDescription[] = []; - - for (let i = 0, len = extensionDescriptions.length; i < len; i++) { - this._handleActivateRequest(extensionDescriptions[i], greenMap, red); - } - - // Make sure no red is also green - for (let i = 0, len = red.length; i < len; i++) { - if (greenMap[red[i].id]) { - delete greenMap[red[i].id]; - } - } - - let green = Object.keys(greenMap).map(id => greenMap[id]); - - // console.log('greenExtensions: ', green.map(p => p.id)); - // console.log('redExtensions: ', red.map(p => p.id)); - - if (red.length === 0) { - // Finally reached only leafs! - return TPromise.join(green.map((p) => this._activateExtension(p))).then(_ => void 0); - } - - return this._activateExtensions(green, recursionLevel + 1).then(_ => { - return this._activateExtensions(red, recursionLevel + 1); - }); - } - - public _activateExtension(extensionDescription: IExtensionDescription): TPromise { - if (hasOwnProperty.call(this._activatedExtensions, extensionDescription.id)) { - return TPromise.as(void 0); - } - - if (hasOwnProperty.call(this._activatingExtensions, extensionDescription.id)) { - return this._activatingExtensions[extensionDescription.id]; - } - - this._activatingExtensions[extensionDescription.id] = this._host.actualActivateExtension(extensionDescription).then(null, (err) => { - this._host.showMessage(Severity.Error, nls.localize('activationError', "Activating extension `{0}` failed: {1}.", extensionDescription.id, err.message)); - console.error('Activating extension `' + extensionDescription.id + '` failed: ', err.message); - console.log('Here is the error stack: ', err.stack); - // Treat the extension as being empty - return this._host.createFailedExtension(); - }).then((x: T) => { - this._activatedExtensions[extensionDescription.id] = x; - delete this._activatingExtensions[extensionDescription.id]; - }); - - return this._activatingExtensions[extensionDescription.id]; - } -} - -export abstract class AbstractExtensionService { - public _serviceBrand: any; - - private _onReady: TPromise; - private _onReadyC: (v: boolean) => void; - private _isReady: boolean; - protected _registry: ExtensionDescriptionRegistry; - protected _manager: ExtensionsManager; - - constructor(isReadyByDefault: boolean) { - if (isReadyByDefault) { - this._isReady = true; - this._onReady = TPromise.as(true); - this._onReadyC = (v: boolean) => { /*no-op*/ }; - } else { - this._isReady = false; - this._onReady = new TPromise((c, e, p) => { - this._onReadyC = c; - }, () => { - console.warn('You should really not try to cancel this ready promise!'); - }); - } - this._registry = new ExtensionDescriptionRegistry(); - this._manager = new ExtensionsManager(this._registry, { - showMessage: (severity: Severity, message: string): void => { - this._showMessage(severity, message); - }, - - createFailedExtension: (): T => { - return this._createFailedExtension(); - }, - - actualActivateExtension: (extensionDescription: IExtensionDescription): TPromise => { - return this._actualActivateExtension(extensionDescription); - } - }); - } - - protected _triggerOnReady(): void { - this._isReady = true; - this._onReadyC(true); - } - - public onReady(): TPromise { - return this._onReady; - } - - public isActivated(extensionId: string): boolean { - return this._manager.isActivated(extensionId); - } - - public activateByEvent(activationEvent: string): TPromise { - if (this._isReady) { - return this._manager.activateByEvent(activationEvent); - } else { - return this._onReady.then(() => this._manager.activateByEvent(activationEvent)); - } - } - - public activateById(extensionId: string): TPromise { - if (this._isReady) { - return this._manager.activateById(extensionId); - } else { - return this._onReady.then(() => this._manager.activateById(extensionId)); - } - } - - protected abstract _showMessage(severity: Severity, message: string): void; - - protected abstract _createFailedExtension(): T; - - protected abstract _actualActivateExtension(extensionDescription: IExtensionDescription): TPromise; -} - - -interface IExtensionDescriptionMap { - [extensionId: string]: IExtensionDescription; -} - export class ExtensionDescriptionRegistry { - private _extensionsMap: IExtensionDescriptionMap; + private _extensionsMap: { [extensionId: string]: IExtensionDescription; }; private _extensionsArr: IExtensionDescription[]; private _activationMap: { [activationEvent: string]: IExtensionDescription[]; }; diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index 5c4d229ca87..270bba08266 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -4,12 +4,13 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import * as nls from 'vs/nls'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { join } from 'path'; import { mkdirp, dirExists } from 'vs/base/node/pfs'; import Severity from 'vs/base/common/severity'; import { TPromise } from 'vs/base/common/winjs.base'; -import { AbstractExtensionService, ActivatedExtension } from 'vs/platform/extensions/common/abstractExtensionService'; +import { ExtensionDescriptionRegistry } from 'vs/platform/extensions/common/abstractExtensionService'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ExtHostStorage } from 'vs/workbench/api/node/extHostStorage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -17,6 +18,9 @@ import { createApiFactory, initializeExtensionApi } from 'vs/workbench/api/node/ import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; import { MainContext, MainProcessExtensionServiceShape, IWorkspaceData, IEnvironment, IInitData } from './extHost.protocol'; +const hasOwnProperty = Object.hasOwnProperty; +const NO_OP_VOID_PROMISE = TPromise.as(void 0); + /** * Represents the source code (module) of an extension. */ @@ -32,6 +36,14 @@ export interface IExtensionAPI { // _extensionAPIBrand: any; } +export abstract class ActivatedExtension { + activationFailed: boolean; + + constructor(activationFailed: boolean) { + this.activationFailed = activationFailed; + } +} + export class ExtHostExtension extends ActivatedExtension { module: IExtensionModule; @@ -152,6 +164,80 @@ export interface IExtensionContext { asAbsolutePath(relativePath: string): string; } +export abstract class AbstractExtensionService { + public _serviceBrand: any; + + private _onReady: TPromise; + private _onReadyC: (v: boolean) => void; + private _isReady: boolean; + protected _registry: ExtensionDescriptionRegistry; + protected _manager: ExtensionsManager; + + constructor(isReadyByDefault: boolean) { + if (isReadyByDefault) { + this._isReady = true; + this._onReady = TPromise.as(true); + this._onReadyC = (v: boolean) => { /*no-op*/ }; + } else { + this._isReady = false; + this._onReady = new TPromise((c, e, p) => { + this._onReadyC = c; + }, () => { + console.warn('You should really not try to cancel this ready promise!'); + }); + } + this._registry = new ExtensionDescriptionRegistry(); + this._manager = new ExtensionsManager(this._registry, { + showMessage: (severity: Severity, message: string): void => { + this._showMessage(severity, message); + }, + + createFailedExtension: (): T => { + return this._createFailedExtension(); + }, + + actualActivateExtension: (extensionDescription: IExtensionDescription): TPromise => { + return this._actualActivateExtension(extensionDescription); + } + }); + } + + protected _triggerOnReady(): void { + this._isReady = true; + this._onReadyC(true); + } + + public onReady(): TPromise { + return this._onReady; + } + + public isActivated(extensionId: string): boolean { + return this._manager.isActivated(extensionId); + } + + public activateByEvent(activationEvent: string): TPromise { + if (this._isReady) { + return this._manager.activateByEvent(activationEvent); + } else { + return this._onReady.then(() => this._manager.activateByEvent(activationEvent)); + } + } + + public activateById(extensionId: string): TPromise { + if (this._isReady) { + return this._manager.activateById(extensionId); + } else { + return this._onReady.then(() => this._manager.activateById(extensionId)); + } + } + + protected abstract _showMessage(severity: Severity, message: string): void; + + protected abstract _createFailedExtension(): T; + + protected abstract _actualActivateExtension(extensionDescription: IExtensionDescription): TPromise; +} + export class ExtHostExtensionService extends AbstractExtensionService { private _threadService: IThreadService; @@ -336,6 +422,191 @@ export class ExtHostExtensionService extends AbstractExtensionService { + showMessage(severity: Severity, message: string): void; + + createFailedExtension(): T; + + actualActivateExtension(extensionDescription: IExtensionDescription): TPromise; +} + +export interface IActivatedExtensionMap { + [extensionId: string]: T; +} + +interface IActivatingExtensionMap { + [extensionId: string]: TPromise; +} + +export class ExtensionsManager { + + private readonly _registry: ExtensionDescriptionRegistry; + private readonly _host: IExtensionsManagerHost; + private readonly _activatingExtensions: IActivatingExtensionMap; + private readonly _activatedExtensions: IActivatedExtensionMap; + /** + * A map of already activated events to speed things up if the same activation event is triggered multiple times. + */ + private readonly _alreadyActivatedEvents: { [activationEvent: string]: boolean; }; + + constructor(registry: ExtensionDescriptionRegistry, host: IExtensionsManagerHost) { + this._registry = registry; + this._host = host; + this._activatingExtensions = {}; + this._activatedExtensions = {}; + this._alreadyActivatedEvents = Object.create(null); + } + + public isActivated(extensionId: string): boolean { + return hasOwnProperty.call(this._activatedExtensions, extensionId); + } + + public getActivatedExtension(extensionId: string): T { + if (!hasOwnProperty.call(this._activatedExtensions, extensionId)) { + throw new Error('Extension `' + extensionId + '` is not known or not activated'); + } + return this._activatedExtensions[extensionId]; + } + + public setActivatedExtension(extensionId: string, value: T): void { + this._activatedExtensions[extensionId] = value; + } + + public activateByEvent(activationEvent: string): TPromise { + if (this._alreadyActivatedEvents[activationEvent]) { + return NO_OP_VOID_PROMISE; + } + let activateExtensions = this._registry.getExtensionDescriptionsForActivationEvent(activationEvent); + return this._activateExtensions(activateExtensions, 0).then(() => { + this._alreadyActivatedEvents[activationEvent] = true; + }); + } + + public activateById(extensionId: string): TPromise { + let desc = this._registry.getExtensionDescription(extensionId); + if (!desc) { + throw new Error('Extension `' + extensionId + '` is not known'); + } + + return this._activateExtensions([desc], 0); + } + + /** + * Handle semantics related to dependencies for `currentExtension`. + * semantics: `redExtensions` must wait for `greenExtensions`. + */ + private _handleActivateRequest(currentExtension: IExtensionDescription, greenExtensions: { [id: string]: IExtensionDescription; }, redExtensions: IExtensionDescription[]): void { + let depIds = (typeof currentExtension.extensionDependencies === 'undefined' ? [] : currentExtension.extensionDependencies); + let currentExtensionGetsGreenLight = true; + + for (let j = 0, lenJ = depIds.length; j < lenJ; j++) { + let depId = depIds[j]; + let depDesc = this._registry.getExtensionDescription(depId); + + if (!depDesc) { + // Error condition 1: unknown dependency + this._host.showMessage(Severity.Error, nls.localize('unknownDep', "Extension `{1}` failed to activate. Reason: unknown dependency `{0}`.", depId, currentExtension.id)); + this._activatedExtensions[currentExtension.id] = this._host.createFailedExtension(); + return; + } + + if (hasOwnProperty.call(this._activatedExtensions, depId)) { + let dep = this._activatedExtensions[depId]; + if (dep.activationFailed) { + // Error condition 2: a dependency has already failed activation + this._host.showMessage(Severity.Error, nls.localize('failedDep1', "Extension `{1}` failed to activate. Reason: dependency `{0}` failed to activate.", depId, currentExtension.id)); + this._activatedExtensions[currentExtension.id] = this._host.createFailedExtension(); + return; + } + } else { + // must first wait for the dependency to activate + currentExtensionGetsGreenLight = false; + greenExtensions[depId] = depDesc; + } + } + + if (currentExtensionGetsGreenLight) { + greenExtensions[currentExtension.id] = currentExtension; + } else { + redExtensions.push(currentExtension); + } + } + + private _activateExtensions(extensionDescriptions: IExtensionDescription[], recursionLevel: number): TPromise { + // console.log(recursionLevel, '_activateExtensions: ', extensionDescriptions.map(p => p.id)); + if (extensionDescriptions.length === 0) { + return TPromise.as(void 0); + } + + extensionDescriptions = extensionDescriptions.filter((p) => !hasOwnProperty.call(this._activatedExtensions, p.id)); + if (extensionDescriptions.length === 0) { + return TPromise.as(void 0); + } + + if (recursionLevel > 10) { + // More than 10 dependencies deep => most likely a dependency loop + for (let i = 0, len = extensionDescriptions.length; i < len; i++) { + // Error condition 3: dependency loop + this._host.showMessage(Severity.Error, nls.localize('failedDep2', "Extension `{0}` failed to activate. Reason: more than 10 levels of dependencies (most likely a dependency loop).", extensionDescriptions[i].id)); + this._activatedExtensions[extensionDescriptions[i].id] = this._host.createFailedExtension(); + } + return TPromise.as(void 0); + } + + let greenMap: { [id: string]: IExtensionDescription; } = Object.create(null), + red: IExtensionDescription[] = []; + + for (let i = 0, len = extensionDescriptions.length; i < len; i++) { + this._handleActivateRequest(extensionDescriptions[i], greenMap, red); + } + + // Make sure no red is also green + for (let i = 0, len = red.length; i < len; i++) { + if (greenMap[red[i].id]) { + delete greenMap[red[i].id]; + } + } + + let green = Object.keys(greenMap).map(id => greenMap[id]); + + // console.log('greenExtensions: ', green.map(p => p.id)); + // console.log('redExtensions: ', red.map(p => p.id)); + + if (red.length === 0) { + // Finally reached only leafs! + return TPromise.join(green.map((p) => this._activateExtension(p))).then(_ => void 0); + } + + return this._activateExtensions(green, recursionLevel + 1).then(_ => { + return this._activateExtensions(red, recursionLevel + 1); + }); + } + + public _activateExtension(extensionDescription: IExtensionDescription): TPromise { + if (hasOwnProperty.call(this._activatedExtensions, extensionDescription.id)) { + return TPromise.as(void 0); + } + + if (hasOwnProperty.call(this._activatingExtensions, extensionDescription.id)) { + return this._activatingExtensions[extensionDescription.id]; + } + + this._activatingExtensions[extensionDescription.id] = this._host.actualActivateExtension(extensionDescription).then(null, (err) => { + this._host.showMessage(Severity.Error, nls.localize('activationError', "Activating extension `{0}` failed: {1}.", extensionDescription.id, err.message)); + console.error('Activating extension `' + extensionDescription.id + '` failed: ', err.message); + console.log('Here is the error stack: ', err.stack); + // Treat the extension as being empty + return this._host.createFailedExtension(); + }).then((x: T) => { + this._activatedExtensions[extensionDescription.id] = x; + delete this._activatingExtensions[extensionDescription.id]; + }); + + return this._activatingExtensions[extensionDescription.id]; + } +} + function loadCommonJSModule(modulePath: string): TPromise { let r: T = null; try { diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index 4671dbee58e..8d767289db8 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -25,6 +25,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { IInstantiationService } from "vs/platform/instantiation/common/instantiation"; import { ExtensionHostProcessWorker } from "vs/workbench/services/extensions/electron-browser/extensionHost"; import { MainThreadService } from "vs/workbench/services/thread/electron-browser/threadService"; +import { Barrier } from "vs/workbench/services/extensions/node/barrier"; const SystemExtensionsRoot = path.normalize(path.join(URI.parse(require.toUrl('')).fsPath, '..', 'extensions')); @@ -42,38 +43,6 @@ function messageWithSource2(source: string, message: string): string { const hasOwnProperty = Object.hasOwnProperty; const NO_OP_VOID_PROMISE = TPromise.as(void 0); -/** - * A barrier that is initially closed and then becomes opened permanently. - */ -class Barrier { - - private _isOpen: boolean; - private _promise: TPromise; - private _completePromise: (v: boolean) => void; - - constructor() { - this._isOpen = false; - this._promise = new TPromise((c, e, p) => { - this._completePromise = c; - }, () => { - console.warn('You should really not try to cancel this ready promise!'); - }); - } - - public isOpen(): boolean { - return this._isOpen; - } - - public open(): void { - this._isOpen = true; - this._completePromise(true); - } - - public wait(): TPromise { - return this._promise; - } -} - export class ExtensionService implements IThreadService, IExtensionService { public _serviceBrand: any; diff --git a/src/vs/workbench/services/extensions/node/barrier.ts b/src/vs/workbench/services/extensions/node/barrier.ts new file mode 100644 index 00000000000..2a368e23c3a --- /dev/null +++ b/src/vs/workbench/services/extensions/node/barrier.ts @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { TPromise } from 'vs/base/common/winjs.base'; + +/** + * A barrier that is initially closed and then becomes opened permanently. + */ +export class Barrier { + + private _isOpen: boolean; + private _promise: TPromise; + private _completePromise: (v: boolean) => void; + + constructor() { + this._isOpen = false; + this._promise = new TPromise((c, e, p) => { + this._completePromise = c; + }, () => { + console.warn('You should really not try to cancel this ready promise!'); + }); + } + + public isOpen(): boolean { + return this._isOpen; + } + + public open(): void { + this._isOpen = true; + this._completePromise(true); + } + + public wait(): TPromise { + return this._promise; + } +}