Fixes #44956: Propagate extension activation errors in the activate() calls

This commit is contained in:
Alex Dima
2018-04-06 11:55:35 +02:00
parent 36358924de
commit 8e5a374372
3 changed files with 27 additions and 9 deletions

View File

@@ -710,7 +710,7 @@ class Extension<T> implements vscode.Extension<T> {
}
activate(): Thenable<T> {
return this._extensionService.activateById(this.id, new ExtensionActivatedByAPI(false)).then(() => this.exports);
return this._extensionService.activateByIdWithErrors(this.id, new ExtensionActivatedByAPI(false)).then(() => this.exports);
}
}

View File

@@ -127,6 +127,7 @@ export class ExtensionActivationTimesBuilder {
export class ActivatedExtension {
public readonly activationFailed: boolean;
public readonly activationFailedError: Error;
public readonly activationTimes: ExtensionActivationTimes;
public readonly module: IExtensionModule;
public readonly exports: IExtensionAPI;
@@ -134,12 +135,14 @@ export class ActivatedExtension {
constructor(
activationFailed: boolean,
activationFailedError: Error,
activationTimes: ExtensionActivationTimes,
module: IExtensionModule,
exports: IExtensionAPI,
subscriptions: IDisposable[]
) {
this.activationFailed = activationFailed;
this.activationFailedError = activationFailedError;
this.activationTimes = activationTimes;
this.module = module;
this.exports = exports;
@@ -149,13 +152,13 @@ export class ActivatedExtension {
export class EmptyExtension extends ActivatedExtension {
constructor(activationTimes: ExtensionActivationTimes) {
super(false, activationTimes, { activate: undefined, deactivate: undefined }, undefined, []);
super(false, null, activationTimes, { activate: undefined, deactivate: undefined }, undefined, []);
}
}
export class FailedExtension extends ActivatedExtension {
constructor(activationTimes: ExtensionActivationTimes) {
super(true, activationTimes, { activate: undefined, deactivate: undefined }, undefined, []);
constructor(activationError: Error) {
super(true, activationError, ExtensionActivationTimes.NONE, { activate: undefined, deactivate: undefined }, undefined, []);
}
}
@@ -244,7 +247,8 @@ export class ExtensionsActivator {
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] = new FailedExtension(ExtensionActivationTimes.NONE);
const error = new Error(`Unknown dependency '${depId}'`);
this._activatedExtensions[currentExtension.id] = new FailedExtension(error);
return;
}
@@ -253,7 +257,9 @@ export class ExtensionsActivator {
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] = new FailedExtension(ExtensionActivationTimes.NONE);
const error = new Error(`Dependency ${depId} failed to activate`);
(<any>error).detail = dep.activationFailedError;
this._activatedExtensions[currentExtension.id] = new FailedExtension(error);
return;
}
} else {
@@ -286,7 +292,8 @@ export class ExtensionsActivator {
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] = new FailedExtension(ExtensionActivationTimes.NONE);
const error = new Error('More than 10 levels of dependencies (most likely a dependency loop)');
this._activatedExtensions[extensionDescriptions[i].id] = new FailedExtension(error);
}
return TPromise.as(void 0);
}
@@ -334,7 +341,7 @@ export class ExtensionsActivator {
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 new FailedExtension(ExtensionActivationTimes.NONE);
return new FailedExtension(err);
}).then((x: ActivatedExtension) => {
this._activatedExtensions[extensionDescription.id] = x;
delete this._activatingExtensions[extensionDescription.id];

View File

@@ -208,6 +208,17 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
}
}
public activateByIdWithErrors(extensionId: string, reason: ExtensionActivationReason): TPromise<void> {
return this.activateById(extensionId, reason).then(() => {
const extension = this._activator.getActivatedExtension(extensionId);
if (extension.activationFailed) {
// activation failed => bubble up the error as the promise result
return TPromise.wrapError(extension.activationFailedError);
}
return void 0;
});
}
public getAllExtensionDescriptions(): IExtensionDescription[] {
return this._registry.getAllExtensionDescriptions();
}
@@ -371,7 +382,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
};
return this._callActivateOptional(logService, extensionId, extensionModule, context, activationTimesBuilder).then((extensionExports) => {
return new ActivatedExtension(false, activationTimesBuilder.build(), extensionModule, extensionExports, context.subscriptions);
return new ActivatedExtension(false, null, activationTimesBuilder.build(), extensionModule, extensionExports, context.subscriptions);
});
}