Skip to content

Commit 3635164

Browse files
authored
1 parent 35a5a6f commit 3635164

File tree

2 files changed

+85
-19
lines changed

2 files changed

+85
-19
lines changed

src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,11 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench
147147
throw new Error(localize('cannot change enablement environment', "Cannot change enablement of {0} extension because it is enabled in environment", extension.manifest.displayName || extension.identifier.id));
148148
}
149149

150-
switch (this.getEnablementState(extension)) {
150+
this.throwErrorIfEnablementStateCannotBeChanged(extension, this.getEnablementState(extension), donotCheckDependencies);
151+
}
152+
153+
private throwErrorIfEnablementStateCannotBeChanged(extension: IExtension, enablementStateOfExtension: EnablementState, donotCheckDependencies?: boolean): void {
154+
switch (enablementStateOfExtension) {
151155
case EnablementState.DisabledByEnvironment:
152156
throw new Error(localize('cannot change disablement environment', "Cannot change enablement of {0} extension because it is disabled in environment", extension.manifest.displayName || extension.identifier.id));
153157
case EnablementState.DisabledByVirtualWorkspace:
@@ -219,30 +223,60 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench
219223
}
220224

221225
private getExtensionsToEnableRecursively(extensions: IExtension[], allExtensions: ReadonlyArray<IExtension>, enablementState: EnablementState, options: { dependencies: boolean; pack: boolean }, checked: IExtension[] = []): IExtension[] {
226+
if (!options.dependencies && !options.pack) {
227+
return [];
228+
}
229+
222230
const toCheck = extensions.filter(e => checked.indexOf(e) === -1);
223-
if (toCheck.length) {
224-
for (const extension of toCheck) {
225-
checked.push(extension);
231+
if (!toCheck.length) {
232+
return [];
233+
}
234+
235+
for (const extension of toCheck) {
236+
checked.push(extension);
237+
}
238+
239+
const extensionsToDisable: IExtension[] = [];
240+
for (const extension of allExtensions) {
241+
// Extension is already checked
242+
if (checked.some(e => areSameExtensions(e.identifier, extension.identifier))) {
243+
continue;
226244
}
227-
const extensionsToDisable = allExtensions.filter(i => {
228-
if (checked.indexOf(i) !== -1) {
229-
return false;
245+
246+
const enablementStateOfExtension = this.getEnablementState(extension);
247+
// Extension enablement state is same as the end enablement state
248+
if (enablementStateOfExtension === enablementState) {
249+
continue;
250+
}
251+
252+
// Check if the extension is a dependency or in extension pack
253+
if (extensions.some(e =>
254+
(options.dependencies && e.manifest.extensionDependencies?.some(id => areSameExtensions({ id }, extension.identifier)))
255+
|| (options.pack && e.manifest.extensionPack?.some(id => areSameExtensions({ id }, extension.identifier))))) {
256+
257+
const index = extensionsToDisable.findIndex(e => areSameExtensions(e.identifier, extension.identifier));
258+
259+
// Extension is not aded to the disablement list so add it
260+
if (index === -1) {
261+
extensionsToDisable.push(extension);
230262
}
231-
if (this.getEnablementState(i) === enablementState) {
232-
return false;
263+
264+
// Extension is there already in the disablement list.
265+
else {
266+
try {
267+
// Replace only if the enablement state can be changed
268+
this.throwErrorIfEnablementStateCannotBeChanged(extension, enablementStateOfExtension, true);
269+
extensionsToDisable.splice(index, 1, extension);
270+
} catch (error) { /*Do not add*/ }
233271
}
234-
return (options.dependencies || options.pack)
235-
&& extensions.some(extension =>
236-
(options.dependencies && extension.manifest.extensionDependencies?.some(id => areSameExtensions({ id }, i.identifier)))
237-
|| (options.pack && extension.manifest.extensionPack?.some(id => areSameExtensions({ id }, i.identifier)))
238-
);
239-
});
240-
if (extensionsToDisable.length) {
241-
extensionsToDisable.push(...this.getExtensionsToEnableRecursively(extensionsToDisable, allExtensions, enablementState, options, checked));
242272
}
243-
return extensionsToDisable;
244273
}
245-
return [];
274+
275+
if (extensionsToDisable.length) {
276+
extensionsToDisable.push(...this.getExtensionsToEnableRecursively(extensionsToDisable, allExtensions, enablementState, options, checked));
277+
}
278+
279+
return extensionsToDisable;
246280
}
247281

248282
private _setUserEnablementState(extension: IExtension, newState: EnablementState): Promise<boolean> {

src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,38 @@ suite('ExtensionEnablementService Test', () => {
624624
assert.deepStrictEqual(testObject.getEnablementState(extension), EnablementState.DisabledByVirtualWorkspace);
625625
});
626626

627+
test('test enable a remote workspace extension and local ui extension that is a dependency of remote', async () => {
628+
instantiationService.stub(IExtensionManagementServerService, anExtensionManagementServerService(anExtensionManagementServer('vscode-local', instantiationService), anExtensionManagementServer('vscode-remote', instantiationService), null));
629+
const localUIExtension = aLocalExtension2('pub.a', { main: 'main.js', extensionKind: ['ui'] }, { location: URI.file(`pub.a`) });
630+
const remoteUIExtension = aLocalExtension2('pub.a', { main: 'main.js', extensionKind: ['ui'] }, { location: URI.file(`pub.a`).with({ scheme: 'vscode-remote' }) });
631+
const target = aLocalExtension2('pub.b', { main: 'main.js', extensionDependencies: ['pub.a'] }, { location: URI.file(`pub.b`).with({ scheme: 'vscode-remote' }) });
632+
testObject = new TestExtensionEnablementService(instantiationService);
633+
634+
installed.push(localUIExtension, remoteUIExtension, target);
635+
await testObject.setEnablement([target, localUIExtension], EnablementState.DisabledGlobally);
636+
await testObject.setEnablement([target, localUIExtension], EnablementState.EnabledGlobally);
637+
assert.ok(testObject.isEnabled(target));
638+
assert.ok(testObject.isEnabled(localUIExtension));
639+
assert.strictEqual(testObject.getEnablementState(target), EnablementState.EnabledGlobally);
640+
assert.strictEqual(testObject.getEnablementState(localUIExtension), EnablementState.EnabledGlobally);
641+
});
642+
643+
test('test enable a remote workspace extension also enables its dependency in local', async () => {
644+
instantiationService.stub(IExtensionManagementServerService, anExtensionManagementServerService(anExtensionManagementServer('vscode-local', instantiationService), anExtensionManagementServer('vscode-remote', instantiationService), null));
645+
const localUIExtension = aLocalExtension2('pub.a', { main: 'main.js', extensionKind: ['ui'] }, { location: URI.file(`pub.a`) });
646+
const remoteUIExtension = aLocalExtension2('pub.a', { main: 'main.js', extensionKind: ['ui'] }, { location: URI.file(`pub.a`).with({ scheme: 'vscode-remote' }) });
647+
const target = aLocalExtension2('pub.b', { main: 'main.js', extensionDependencies: ['pub.a'] }, { location: URI.file(`pub.b`).with({ scheme: 'vscode-remote' }) });
648+
testObject = new TestExtensionEnablementService(instantiationService);
649+
650+
installed.push(localUIExtension, remoteUIExtension, target);
651+
await testObject.setEnablement([target, localUIExtension], EnablementState.DisabledGlobally);
652+
await testObject.setEnablement([target], EnablementState.EnabledGlobally);
653+
assert.ok(testObject.isEnabled(target));
654+
assert.ok(testObject.isEnabled(localUIExtension));
655+
assert.strictEqual(testObject.getEnablementState(target), EnablementState.EnabledGlobally);
656+
assert.strictEqual(testObject.getEnablementState(localUIExtension), EnablementState.EnabledGlobally);
657+
});
658+
627659
test('test canChangeEnablement return false when extension is disabled in virtual workspace', () => {
628660
const extension = aLocalExtension2('pub.a', { capabilities: { virtualWorkspaces: false } });
629661
instantiationService.stub(IWorkspaceContextService, 'getWorkspace', <IWorkspace>{ folders: [{ uri: URI.file('worskapceA').with(({ scheme: 'virtual' })) }] });

0 commit comments

Comments
 (0)