Add extension id that triggered the activation event

This commit is contained in:
Christof Marti
2019-09-18 14:12:03 +02:00
parent c8fa927f76
commit 715b6c5792
11 changed files with 109 additions and 85 deletions

View File

@@ -164,18 +164,22 @@ export interface IExtensionsActivatorHost {
export class ExtensionActivatedByEvent {
constructor(
public readonly startup: boolean,
public readonly extensionId: ExtensionIdentifier,
public readonly activationEvent: string
) { }
}
export class ExtensionActivatedByAPI {
constructor(
public readonly startup: boolean
public readonly startup: boolean,
public readonly extensionId: ExtensionIdentifier
) { }
}
export type ExtensionActivationReason = ExtensionActivatedByEvent | ExtensionActivatedByAPI;
type ActivationIdAndReason = { id: ExtensionIdentifier, reason: ExtensionActivationReason };
export class ExtensionsActivator {
private readonly _registry: ExtensionDescriptionRegistry;
@@ -217,12 +221,15 @@ export class ExtensionsActivator {
return activatedExtension;
}
public activateByEvent(activationEvent: string, reason: ExtensionActivationReason): Promise<void> {
public activateByEvent(activationEvent: string, startup: boolean): Promise<void> {
if (this._alreadyActivatedEvents[activationEvent]) {
return NO_OP_VOID_PROMISE;
}
const activateExtensions = this._registry.getExtensionDescriptionsForActivationEvent(activationEvent);
return this._activateExtensions(activateExtensions.map(e => e.identifier), reason).then(() => {
return this._activateExtensions(activateExtensions.map(e => ({
id: e.identifier,
reason: new ExtensionActivatedByEvent(startup, e.identifier, activationEvent)
}))).then(() => {
this._alreadyActivatedEvents[activationEvent] = true;
});
}
@@ -233,20 +240,23 @@ export class ExtensionsActivator {
throw new Error('Extension `' + extensionId + '` is not known');
}
return this._activateExtensions([desc.identifier], reason);
return this._activateExtensions([{
id: desc.identifier,
reason
}]);
}
/**
* Handle semantics related to dependencies for `currentExtension`.
* semantics: `redExtensions` must wait for `greenExtensions`.
*/
private _handleActivateRequest(currentExtensionId: ExtensionIdentifier, greenExtensions: { [id: string]: ExtensionIdentifier; }, redExtensions: ExtensionIdentifier[]): void {
if (this._hostExtensionsMap.has(ExtensionIdentifier.toKey(currentExtensionId))) {
greenExtensions[ExtensionIdentifier.toKey(currentExtensionId)] = currentExtensionId;
private _handleActivateRequest(currentActivation: ActivationIdAndReason, greenExtensions: { [id: string]: ActivationIdAndReason; }, redExtensions: ActivationIdAndReason[]): void {
if (this._hostExtensionsMap.has(ExtensionIdentifier.toKey(currentActivation.id))) {
greenExtensions[ExtensionIdentifier.toKey(currentActivation.id)] = currentActivation;
return;
}
const currentExtension = this._registry.getExtensionDescription(currentExtensionId)!;
const currentExtension = this._registry.getExtensionDescription(currentActivation.id)!;
const depIds = (typeof currentExtension.extensionDependencies === 'undefined' ? [] : currentExtension.extensionDependencies);
let currentExtensionGetsGreenLight = true;
@@ -276,7 +286,10 @@ export class ExtensionsActivator {
if (this._hostExtensionsMap.has(ExtensionIdentifier.toKey(depId))) {
// must first wait for the dependency to activate
currentExtensionGetsGreenLight = false;
greenExtensions[ExtensionIdentifier.toKey(depId)] = this._hostExtensionsMap.get(ExtensionIdentifier.toKey(depId))!;
greenExtensions[ExtensionIdentifier.toKey(depId)] = {
id: this._hostExtensionsMap.get(ExtensionIdentifier.toKey(depId))!,
reason: currentActivation.reason
};
continue;
}
@@ -284,7 +297,10 @@ export class ExtensionsActivator {
if (depDesc) {
// must first wait for the dependency to activate
currentExtensionGetsGreenLight = false;
greenExtensions[ExtensionIdentifier.toKey(depId)] = depDesc.identifier;
greenExtensions[ExtensionIdentifier.toKey(depId)] = {
id: depDesc.identifier,
reason: currentActivation.reason
};
continue;
}
@@ -296,33 +312,33 @@ export class ExtensionsActivator {
}
if (currentExtensionGetsGreenLight) {
greenExtensions[ExtensionIdentifier.toKey(currentExtension.identifier)] = currentExtensionId;
greenExtensions[ExtensionIdentifier.toKey(currentExtension.identifier)] = currentActivation;
} else {
redExtensions.push(currentExtensionId);
redExtensions.push(currentActivation);
}
}
private _activateExtensions(extensionIds: ExtensionIdentifier[], reason: ExtensionActivationReason): Promise<void> {
// console.log('_activateExtensions: ', extensionIds.map(p => p.value));
if (extensionIds.length === 0) {
private _activateExtensions(extensions: ActivationIdAndReason[]): Promise<void> {
// console.log('_activateExtensions: ', extensions.map(p => p.id.value));
if (extensions.length === 0) {
return Promise.resolve(undefined);
}
extensionIds = extensionIds.filter((p) => !this._activatedExtensions.has(ExtensionIdentifier.toKey(p)));
if (extensionIds.length === 0) {
extensions = extensions.filter((p) => !this._activatedExtensions.has(ExtensionIdentifier.toKey(p.id)));
if (extensions.length === 0) {
return Promise.resolve(undefined);
}
const greenMap: { [id: string]: ExtensionIdentifier; } = Object.create(null),
red: ExtensionIdentifier[] = [];
const greenMap: { [id: string]: ActivationIdAndReason; } = Object.create(null),
red: ActivationIdAndReason[] = [];
for (let i = 0, len = extensionIds.length; i < len; i++) {
this._handleActivateRequest(extensionIds[i], greenMap, red);
for (let i = 0, len = extensions.length; i < len; i++) {
this._handleActivateRequest(extensions[i], greenMap, red);
}
// Make sure no red is also green
for (let i = 0, len = red.length; i < len; i++) {
const redExtensionKey = ExtensionIdentifier.toKey(red[i]);
const redExtensionKey = ExtensionIdentifier.toKey(red[i].id);
if (greenMap[redExtensionKey]) {
delete greenMap[redExtensionKey];
}
@@ -330,16 +346,16 @@ export class ExtensionsActivator {
const green = Object.keys(greenMap).map(id => greenMap[id]);
// console.log('greenExtensions: ', green.map(p => p.id));
// console.log('redExtensions: ', red.map(p => p.id));
// console.log('greenExtensions: ', green.map(p => p.id.value));
// console.log('redExtensions: ', red.map(p => p.id.value));
if (red.length === 0) {
// Finally reached only leafs!
return Promise.all(green.map((p) => this._activateExtension(p, reason))).then(_ => undefined);
return Promise.all(green.map((p) => this._activateExtension(p.id, p.reason))).then(_ => undefined);
}
return this._activateExtensions(green, reason).then(_ => {
return this._activateExtensions(red, reason);
return this._activateExtensions(green).then(_ => {
return this._activateExtensions(red);
});
}