diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index af483787e1d..a28a1ea8d6c 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -12,8 +12,8 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; -import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ExtensionManagementChannel, GlobalExtensionEnablementServiceClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; +import { IExtensionManagementService, IExtensionGalleryService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -185,6 +185,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat services.set(IUserDataAuthTokenService, new SyncDescriptor(UserDataAuthTokenService)); services.set(IUserDataSyncLogService, new SyncDescriptor(UserDataSyncLogService)); services.set(IUserDataSyncUtilService, new UserDataSyncUtilServiceClient(server.getChannel('userDataSyncUtil', activeWindowRouter))); + services.set(IGlobalExtensionEnablementService, new GlobalExtensionEnablementServiceClient(server.getChannel('globalExtensionEnablement', activeWindowRouter))); services.set(IUserDataSyncStoreService, new SyncDescriptor(UserDataSyncStoreService)); services.set(ISettingsSyncService, new SyncDescriptor(SettingsSynchroniser)); services.set(IUserDataSyncService, new SyncDescriptor(UserDataSyncService)); diff --git a/src/vs/platform/extensionManagement/common/extensionEnablementService.ts b/src/vs/platform/extensionManagement/common/extensionEnablementService.ts index f4d9b1ee806..a8fe676d7cf 100644 --- a/src/vs/platform/extensionManagement/common/extensionEnablementService.ts +++ b/src/vs/platform/extensionManagement/common/extensionEnablementService.ts @@ -44,6 +44,10 @@ export class GlobalExtensionEnablementService extends Disposable implements IGlo return this._getExtensions(DISABLED_EXTENSIONS_STORAGE_PATH); } + async getDisabledExtensionsAsync(): Promise { + return this.getDisabledExtensions(); + } + private _addToDisabledExtensions(identifier: IExtensionIdentifier): boolean { let disabledExtensions = this.getDisabledExtensions(); if (disabledExtensions.every(e => !areSameExtensions(e, identifier))) { diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index d0450f544ef..1c73c5ad346 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -214,9 +214,13 @@ export const IGlobalExtensionEnablementService = createDecorator; + getDisabledExtensions(): IExtensionIdentifier[]; enableExtension(extension: IExtensionIdentifier): Promise; disableExtension(extension: IExtensionIdentifier): Promise; + + // Async method until storage service is available in shared process + getDisabledExtensionsAsync(): Promise; } export const ExtensionsLabel = localize('extensions', "Extensions"); diff --git a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts index 035559f7ec6..b5f8114efe0 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { Event } from 'vs/base/common/event'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IURITransformer, DefaultURITransformer, transformAndReviveIncomingURIs } from 'vs/base/common/uriIpc'; @@ -130,3 +130,53 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer return Promise.resolve(this.channel.call('getExtensionsReport')); } } + +export class GlobalExtensionEnablementServiceChannel implements IServerChannel { + + constructor(private readonly service: IGlobalExtensionEnablementService) { } + + listen(_: unknown, event: string): Event { + switch (event) { + case 'onDidChangeEnablement': return this.service.onDidChangeEnablement; + } + throw new Error(`Event not found: ${event}`); + } + + call(context: any, command: string, args?: any): Promise { + switch (command) { + case 'getDisabledExtensionsAsync': return Promise.resolve(this.service.getDisabledExtensions()); + case 'enableExtension': return this.service.enableExtension(args[0]); + case 'disableExtension': return this.service.disableExtension(args[0]); + } + throw new Error('Invalid call'); + } +} + +export class GlobalExtensionEnablementServiceClient implements IGlobalExtensionEnablementService { + + _serviceBrand: undefined; + + get onDidChangeEnablement(): Event { return this.channel.listen('onDidChangeEnablement'); } + + constructor(private readonly channel: IChannel) { + } + + getDisabledExtensionsAsync(): Promise { + return this.channel.call('getDisabledExtensionsAsync'); + } + + enableExtension(extension: IExtensionIdentifier): Promise { + return this.channel.call('enableExtension', [extension]); + } + + disableExtension(extension: IExtensionIdentifier): Promise { + return this.channel.call('disableExtension', [extension]); + } + + getDisabledExtensions(): IExtensionIdentifier[] { + throw new Error('not supported'); + } + +} + + diff --git a/src/vs/platform/userDataSync/common/extensionsMerge.ts b/src/vs/platform/userDataSync/common/extensionsMerge.ts index 364c7513ecd..5d02314b264 100644 --- a/src/vs/platform/userDataSync/common/extensionsMerge.ts +++ b/src/vs/platform/userDataSync/common/extensionsMerge.ts @@ -100,14 +100,8 @@ export function merge(localExtensions: ISyncExtension[], remoteExtensions: ISync // Remotely updated extensions for (const key of values(baseToRemote.updated)) { - // If updated in local - if (baseToLocal.updated.has(key)) { - // Is different from local to remote - if (localToRemote.updated.has(key)) { - // update it in local - updated.push(massageSyncExtension(remoteExtensionsMap.get(key)!, key)); - } - } + // Update in local always + updated.push(massageSyncExtension(remoteExtensionsMap.get(key)!, key)); } // Locally added extensions diff --git a/src/vs/platform/userDataSync/common/extensionsSync.ts b/src/vs/platform/userDataSync/common/extensionsSync.ts index 4d0c3595fa0..d00d62def18 100644 --- a/src/vs/platform/userDataSync/common/extensionsSync.ts +++ b/src/vs/platform/userDataSync/common/extensionsSync.ts @@ -9,7 +9,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { URI } from 'vs/base/common/uri'; import { joinPath } from 'vs/base/common/resources'; -import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, IExtensionGalleryService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionType, IExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IFileService } from 'vs/platform/files/common/files'; @@ -53,6 +53,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse @IFileService fileService: IFileService, @IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, + @IGlobalExtensionEnablementService private readonly extensionEnablementService: IGlobalExtensionEnablementService, @IUserDataSyncLogService private readonly logService: IUserDataSyncLogService, @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, @IConfigurationService private readonly configurationService: IConfigurationService, @@ -285,6 +286,11 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse try { await this.extensionManagementService.installFromGallery(extension); removeFromSkipped.push(extension.identifier); + if (e.enabled) { + await this.extensionEnablementService.enableExtension(extension.identifier); + } else { + await this.extensionEnablementService.disableExtension(extension.identifier); + } } catch (error) { addToSkipped.push(e); this.logService.error(error); @@ -312,8 +318,9 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse private async getLocalExtensions(): Promise { const installedExtensions = await this.extensionManagementService.getInstalled(ExtensionType.User); + const disabledExtensions = await this.extensionEnablementService.getDisabledExtensionsAsync(); return installedExtensions - .map(({ identifier }) => ({ identifier, enabled: true })); + .map(({ identifier }) => ({ identifier, enabled: !disabledExtensions.some(disabledExtension => areSameExtensions(disabledExtension, identifier)) })); } private async getLastSyncUserData(): Promise { diff --git a/src/vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution.ts b/src/vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution.ts index 926a6d2e7a2..42e83a301df 100644 --- a/src/vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution.ts +++ b/src/vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution.ts @@ -9,14 +9,18 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; import { UserDataSycnUtilServiceChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc'; +import { GlobalExtensionEnablementServiceChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; +import { IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; class UserDataSyncServicesContribution implements IWorkbenchContribution { constructor( @IUserDataSyncUtilService userDataSyncUtilService: IUserDataSyncUtilService, @ISharedProcessService sharedProcessService: ISharedProcessService, + @IGlobalExtensionEnablementService globalExtensionEnablementService: IGlobalExtensionEnablementService, ) { sharedProcessService.registerChannel('userDataSyncUtil', new UserDataSycnUtilServiceChannel(userDataSyncUtilService)); + sharedProcessService.registerChannel('globalExtensionEnablement', new GlobalExtensionEnablementServiceChannel(globalExtensionEnablementService)); } }