Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up in profiles land #154188

Merged
merged 1 commit into from Jul 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -381,7 +381,7 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem
private async createExtensionScannerInput(location: URI, profile: boolean, type: ExtensionType, excludeObsolete: boolean, language: string | undefined, validate: boolean = true): Promise<ExtensionScannerInput> {
const translations = await this.getTranslations(language ?? platform.language);
const mtime = await this.getMtime(location);
const applicationExtensionsLocation = this.userDataProfilesService.defaultProfile.extensionsResource;
const applicationExtensionsLocation = profile ? this.userDataProfilesService.defaultProfile.extensionsResource : undefined;
const applicationExtensionsLocationMtime = applicationExtensionsLocation ? await this.getMtime(applicationExtensionsLocation) : undefined;
return new ExtensionScannerInput(
location,
Expand Down
2 changes: 1 addition & 1 deletion src/vs/platform/userDataProfile/common/userDataProfile.ts
Expand Up @@ -104,7 +104,7 @@ export const EXTENSIONS_RESOURCE_NAME = 'extensions.json';

export function toUserDataProfile(name: string, location: URI, useDefaultFlags?: UseDefaultProfileFlags): CustomUserDataProfile {
return {
id: hash(location.toString()).toString(16),
id: hash(location.path).toString(16),
name: name,
location: location,
isDefault: false,
Expand Down
7 changes: 6 additions & 1 deletion src/vs/workbench/contrib/snippets/browser/snippetsService.ts
Expand Up @@ -358,7 +358,12 @@ class SnippetsService implements ISnippetsService {
await this._initFolderSnippets(SnippetSource.User, userSnippetsFolder, disposables);
};
this._disposables.add(disposables);
this._disposables.add(this._userDataProfileService.onDidChangeCurrentProfile(() => this._pendingWork.push(updateUserSnippets())));
this._disposables.add(this._userDataProfileService.onDidChangeCurrentProfile(e => e.join((async () => {
if (e.preserveData) {
await this._fileService.copy(e.previous.snippetsHome, e.profile.snippetsHome);
}
this._pendingWork.push(updateUserSnippets());
})())));
await updateUserSnippets();
}

Expand Down
Expand Up @@ -711,15 +711,21 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
}

private onUserDataProfileChanged(e: DidChangeUserDataProfileEvent): void {
const promises: Promise<ConfigurationModel>[] = [];
promises.push(this.localUserConfiguration.reset(e.profile.settingsResource, e.profile.tasksResource, getLocalUserConfigurationScopes(e.profile, !!this.remoteUserConfiguration)));
if (e.previous.isDefault !== e.profile.isDefault) {
this.createApplicationConfiguration();
if (this.applicationConfiguration) {
promises.push(this.reloadApplicationConfiguration(true));
}
}
e.join((async () => {
if (e.preserveData) {
await Promise.all([
this.fileService.copy(e.previous.settingsResource, e.profile.settingsResource),
this.fileService.copy(e.previous.tasksResource, e.profile.tasksResource)
]);
}
const promises: Promise<ConfigurationModel>[] = [];
promises.push(this.localUserConfiguration.reset(e.profile.settingsResource, e.profile.tasksResource, getLocalUserConfigurationScopes(e.profile, !!this.remoteUserConfiguration)));
if (e.previous.isDefault !== e.profile.isDefault) {
this.createApplicationConfiguration();
if (this.applicationConfiguration) {
promises.push(this.reloadApplicationConfiguration(true));
}
}
const [localUser, application] = await Promise.all(promises);
await this.loadConfiguration(application ?? this._configuration.applicationConfiguration, localUser, this._configuration.remoteUserConfiguration);
})());
Expand Down
Expand Up @@ -13,8 +13,7 @@ import { FileAccess } from 'vs/base/common/network';
export type DidChangeProfileExtensionsEvent = { readonly added: ILocalExtension[]; readonly removed: ILocalExtension[] };

export interface IProfileAwareExtensionManagementService extends IExtensionManagementService {
onDidChangeProfileExtensions: Event<DidChangeProfileExtensionsEvent>;
switchExtensionsProfile(extensionsProfileResource: URI | undefined): Promise<void>;
readonly onDidChangeProfileExtensions: Event<DidChangeProfileExtensionsEvent>;
}

export interface IExtensionManagementServer {
Expand Down
Expand Up @@ -7,14 +7,15 @@ import { localize } from 'vs/nls';
import { ExtensionInstallLocation, IExtensionManagementServer, IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { Schemas } from 'vs/base/common/network';
import { Event } from 'vs/base/common/event';
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ILabelService } from 'vs/platform/label/common/label';
import { isWeb } from 'vs/base/common/platform';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { WebExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/webExtensionManagementService';
import { IExtension } from 'vs/platform/extensions/common/extensions';
import { NativeProfileAwareExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/profileAwareExtensionManagementService';
import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc';

export class ExtensionManagementServerService implements IExtensionManagementServerService {

Expand All @@ -31,7 +32,9 @@ export class ExtensionManagementServerService implements IExtensionManagementSer
) {
const remoteAgentConnection = remoteAgentService.getConnection();
if (remoteAgentConnection) {
const extensionManagementService = instantiationService.createInstance(NativeProfileAwareExtensionManagementService, remoteAgentConnection.getChannel<IChannel>('extensions'), undefined);
const extensionManagementService = new class extends ExtensionManagementChannelClient {
readonly onDidChangeProfileExtensions = Event.None;
}(remoteAgentConnection.getChannel<IChannel>('extensions'));
this.remoteExtensionManagementServer = {
id: 'remote',
extensionManagementService,
Expand Down
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import { ExtensionType, IExtension, IExtensionIdentifier, IExtensionManifest, TargetPlatform } from 'vs/platform/extensions/common/extensions';
import { IExtensionManagementService, ILocalExtension, IGalleryExtension, IGalleryMetadata, InstallOperation, IExtensionGalleryService, InstallOptions, Metadata, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ILocalExtension, IGalleryExtension, IGalleryMetadata, InstallOperation, IExtensionGalleryService, InstallOptions, Metadata, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement';
import { URI } from 'vs/base/common/uri';
import { Event } from 'vs/base/common/event';
import { areSameExtensions, getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
Expand All @@ -20,7 +20,7 @@ import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagemen
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';

export class WebExtensionManagementService extends AbstractExtensionManagementService implements IExtensionManagementService, IProfileAwareExtensionManagementService {
export class WebExtensionManagementService extends AbstractExtensionManagementService implements IProfileAwareExtensionManagementService {

declare readonly _serviceBrand: undefined;

Expand Down Expand Up @@ -100,8 +100,6 @@ export class WebExtensionManagementService extends AbstractExtensionManagementSe
return local;
}

async switchExtensionsProfile(extensionsProfileResource: URI | undefined): Promise<void> { }

protected createDefaultInstallExtensionTask(manifest: IExtensionManifest, extension: URI | IGalleryExtension, options: InstallOptions): IInstallExtensionTask {
return new InstallExtensionTask(manifest, extension, options, this.webExtensionsScannerService);
}
Expand Down
Expand Up @@ -15,7 +15,7 @@ import { ILabelService } from 'vs/platform/label/common/label';
import { IExtension } from 'vs/platform/extensions/common/extensions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
import { NativeProfileAwareExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/profileAwareExtensionManagementService';
import { NativeExtensionManagementService } from 'vs/workbench/services/extensionManagement/electron-sandbox/nativeExtensionManagementService';
import { Disposable } from 'vs/base/common/lifecycle';
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';

Expand All @@ -36,14 +36,8 @@ export class ExtensionManagementServerService extends Disposable implements IExt
@IInstantiationService instantiationService: IInstantiationService,
) {
super();
const localExtensionManagementService = this._register(instantiationService.createInstance(NativeProfileAwareExtensionManagementService, sharedProcessService.getChannel('extensions'), userDataProfileService.currentProfile.extensionsResource));
const localExtensionManagementService = this._register(instantiationService.createInstance(NativeExtensionManagementService, sharedProcessService.getChannel('extensions')));
this.localExtensionManagementServer = { extensionManagementService: localExtensionManagementService, id: 'local', label: localize('local', "Local") };
this._register(userDataProfilesService.onDidChangeProfiles(e => {
if (userDataProfileService.currentProfile.isDefault) {
localExtensionManagementService.extensionsProfileResource = userDataProfilesService.defaultProfile.extensionsResource;
}
}));
this._register(userDataProfileService.onDidChangeCurrentProfile(e => e.join(localExtensionManagementService.switchExtensionsProfile(e.profile.extensionsResource))));
const remoteAgentConnection = remoteAgentService.getConnection();
if (remoteAgentConnection) {
const extensionManagementService = instantiationService.createInstance(NativeRemoteExtensionManagementService, remoteAgentConnection.getChannel<IChannel>('extensions'), this.localExtensionManagementServer);
Expand Down
Expand Up @@ -14,8 +14,12 @@ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'
import { delta } from 'vs/base/common/arrays';
import { compare } from 'vs/base/common/strings';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { DidChangeUserDataProfileEvent, IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
import { EXTENSIONS_RESOURCE_NAME } from 'vs/platform/userDataProfile/common/userDataProfile';
import { joinPath } from 'vs/base/common/resources';
import { IFileService } from 'vs/platform/files/common/files';

export class NativeProfileAwareExtensionManagementService extends ExtensionManagementChannelClient implements IProfileAwareExtensionManagementService {
export class NativeExtensionManagementService extends ExtensionManagementChannelClient implements IProfileAwareExtensionManagementService {

private readonly disposables = this._register(new DisposableStore());

Expand All @@ -31,42 +35,47 @@ export class NativeProfileAwareExtensionManagementService extends ExtensionManag
private readonly _onDidChangeProfileExtensions = this._register(new Emitter<{ readonly added: ILocalExtension[]; readonly removed: ILocalExtension[] }>());
readonly onDidChangeProfileExtensions = this._onDidChangeProfileExtensions.event;

constructor(channel: IChannel, public extensionsProfileResource: URI | undefined,
constructor(
channel: IChannel,
@IUserDataProfileService private readonly userDataProfileService: IUserDataProfileService,
@IFileService private readonly fileService: IFileService,
@IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
) {
super(channel);
this._register(userDataProfileService.onDidChangeCurrentProfile(e => e.join(this.whenProfileChanged(e))));
}

private filterEvent({ profileLocation, applicationScoped }: { profileLocation?: URI; applicationScoped?: boolean }): boolean {
return applicationScoped || this.uriIdentityService.extUri.isEqual(this.extensionsProfileResource, profileLocation);
return applicationScoped || this.uriIdentityService.extUri.isEqual(this.userDataProfileService.currentProfile.extensionsResource, profileLocation);
}

override install(vsix: URI, options?: InstallVSIXOptions): Promise<ILocalExtension> {
return super.install(vsix, { ...options, profileLocation: this.extensionsProfileResource });
return super.install(vsix, { ...options, profileLocation: this.userDataProfileService.currentProfile.extensionsResource });
}

override installFromGallery(extension: IGalleryExtension, installOptions?: InstallOptions): Promise<ILocalExtension> {
return super.installFromGallery(extension, { ...installOptions, profileLocation: this.extensionsProfileResource });
return super.installFromGallery(extension, { ...installOptions, profileLocation: this.userDataProfileService.currentProfile.extensionsResource });
}

override uninstall(extension: ILocalExtension, options?: UninstallOptions): Promise<void> {
return super.uninstall(extension, { ...options, profileLocation: this.extensionsProfileResource });
return super.uninstall(extension, { ...options, profileLocation: this.userDataProfileService.currentProfile.extensionsResource });
}

override getInstalled(type: ExtensionType | null = null): Promise<ILocalExtension[]> {
return super.getInstalled(type, this.extensionsProfileResource);
return super.getInstalled(type, this.userDataProfileService.currentProfile.extensionsResource);
}

async switchExtensionsProfile(extensionsProfileResource: URI | undefined): Promise<void> {
if (this.uriIdentityService.extUri.isEqual(extensionsProfileResource, this.extensionsProfileResource)) {
return;
}
const oldExtensions = await this.getInstalled(ExtensionType.User);
this.extensionsProfileResource = extensionsProfileResource;
const newExtensions = await this.getInstalled(ExtensionType.User);
const { added, removed } = delta(oldExtensions, newExtensions, (a, b) => compare(`${ExtensionIdentifier.toKey(a.identifier.id)}@${a.manifest.version}`, `${ExtensionIdentifier.toKey(b.identifier.id)}@${b.manifest.version}`));
if (added.length || removed.length) {
this._onDidChangeProfileExtensions.fire({ added, removed });
private async whenProfileChanged(e: DidChangeUserDataProfileEvent): Promise<void> {
const previousExtensionsResource = e.previous.extensionsResource ?? joinPath(e.previous.location, EXTENSIONS_RESOURCE_NAME);
if (e.preserveData) {
await this.fileService.copy(previousExtensionsResource, e.profile.extensionsResource!);
} else {
const oldExtensions = await super.getInstalled(ExtensionType.User, previousExtensionsResource);
const newExtensions = await this.getInstalled(ExtensionType.User);
const { added, removed } = delta(oldExtensions, newExtensions, (a, b) => compare(`${ExtensionIdentifier.toKey(a.identifier.id)}@${a.manifest.version}`, `${ExtensionIdentifier.toKey(b.identifier.id)}@${b.manifest.version}`));
if (added.length || removed.length) {
this._onDidChangeProfileExtensions.fire({ added, removed });
}
}
}

Expand Down
Expand Up @@ -4,7 +4,8 @@
*--------------------------------------------------------------------------------------------*/

import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { IExtensionManagementService, ILocalExtension, IGalleryExtension, IExtensionGalleryService, InstallOperation, InstallOptions, InstallVSIXOptions, ExtensionManagementError, ExtensionManagementErrorCode } from 'vs/platform/extensionManagement/common/extensionManagement';
import { Event } from 'vs/base/common/event';
import { ILocalExtension, IGalleryExtension, IExtensionGalleryService, InstallOperation, InstallOptions, InstallVSIXOptions, ExtensionManagementError, ExtensionManagementErrorCode } from 'vs/platform/extensionManagement/common/extensionManagement';
import { URI } from 'vs/base/common/uri';
import { ExtensionType, IExtensionManifest } from 'vs/platform/extensions/common/extensions';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
Expand All @@ -17,14 +18,15 @@ import { IProductService } from 'vs/platform/product/common/productService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { generateUuid } from 'vs/base/common/uuid';
import { joinPath } from 'vs/base/common/resources';
import { IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { IExtensionManagementServer, IProfileAwareExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService';
import { Promises } from 'vs/base/common/async';
import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
import { NativeProfileAwareExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/profileAwareExtensionManagementService';
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc';

export class NativeRemoteExtensionManagementService extends NativeProfileAwareExtensionManagementService implements IExtensionManagementService {
export class NativeRemoteExtensionManagementService extends ExtensionManagementChannelClient implements IProfileAwareExtensionManagementService {

readonly onDidChangeProfileExtensions = Event.None;

constructor(
channel: IChannel,
Expand All @@ -35,9 +37,8 @@ export class NativeRemoteExtensionManagementService extends NativeProfileAwareEx
@IProductService private readonly productService: IProductService,
@INativeWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService,
@IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService,
@IUriIdentityService uriIdentityService: IUriIdentityService,
) {
super(channel, undefined, uriIdentityService);
super(channel);
}

override async install(vsix: URI, options?: InstallVSIXOptions): Promise<ILocalExtension> {
Expand Down
15 changes: 10 additions & 5 deletions src/vs/workbench/services/keybinding/browser/keybindingService.ts
Expand Up @@ -50,7 +50,7 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { dirname } from 'vs/base/common/resources';
import { getAllUnboundCommands } from 'vs/workbench/services/keybinding/browser/unboundCommands';
import { UserSettingsLabelProvider } from 'vs/base/common/keybindingLabels';
import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
import { DidChangeUserDataProfileEvent, IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';

interface ContributedKeyBinding {
command: string;
Expand Down Expand Up @@ -738,10 +738,15 @@ class UserKeybindings extends Disposable {
}
}));

this._register(userDataProfileService.onDidChangeCurrentProfile(e => {
this.watch();
this.reloadConfigurationScheduler.schedule();
}));
this._register(userDataProfileService.onDidChangeCurrentProfile(e => e.join(this.whenCurrentProfieChanged(e))));
}

private async whenCurrentProfieChanged(e: DidChangeUserDataProfileEvent): Promise<void> {
if (e.preserveData) {
await this.fileService.copy(e.previous.keybindingsResource, e.profile.keybindingsResource);
}
this.watch();
this.reloadConfigurationScheduler.schedule();
}

private watch(): void {
Expand Down