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

Pin extension in the extensions manifest #171247

Merged
merged 1 commit into from Jan 13, 2023
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 @@ -13,7 +13,7 @@ import { isWeb } from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
import * as nls from 'vs/nls';
import {
ExtensionManagementError, IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementParticipant, IGalleryExtension, IGalleryMetadata, ILocalExtension, InstallOperation,
ExtensionManagementError, IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementParticipant, IGalleryExtension, ILocalExtension, InstallOperation,
IExtensionsControlManifest, StatisticType, isTargetPlatformCompatible, TargetPlatformToString, ExtensionManagementErrorCode,
InstallOptions, InstallVSIXOptions, UninstallOptions, Metadata, InstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionResult, UninstallExtensionEvent, IExtensionManagementService
} from 'vs/platform/extensionManagement/common/extensionManagement';
Expand Down Expand Up @@ -658,9 +658,9 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
abstract download(extension: IGalleryExtension, operation: InstallOperation): Promise<URI>;
abstract reinstallFromGallery(extension: ILocalExtension): Promise<ILocalExtension>;

abstract getMetadata(extension: ILocalExtension): Promise<Metadata | undefined>;
abstract updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): Promise<ILocalExtension>;
abstract updateExtensionScope(local: ILocalExtension, isMachineScoped: boolean): Promise<ILocalExtension>;
abstract onDidUpdateExtensionMetadata: Event<ILocalExtension>;
abstract getMetadata(extension: ILocalExtension, profileLocation?: URI): Promise<Metadata | undefined>;
abstract updateMetadata(local: ILocalExtension, metadata: Partial<Metadata>, profileLocation?: URI): Promise<ILocalExtension>;

protected abstract getCurrentExtensionsManifestLocation(): URI;
protected abstract createInstallExtensionTask(manifest: IExtensionManifest, extension: URI | IGalleryExtension, options: InstallExtensionTaskOptions): IInstallExtensionTask;
Expand Down
21 changes: 16 additions & 5 deletions src/vs/platform/extensionManagement/common/extensionManagement.ts
Expand Up @@ -240,7 +240,16 @@ export interface IGalleryMetadata {
targetPlatform?: TargetPlatform;
}

export type Metadata = Partial<IGalleryMetadata & { isApplicationScoped: boolean; isMachineScoped: boolean; isBuiltin: boolean; isSystem: boolean; updated: boolean; preRelease: boolean; installedTimestamp: number }>;
export type Metadata = Partial<IGalleryMetadata & {
isApplicationScoped: boolean;
isMachineScoped: boolean;
isBuiltin: boolean;
isSystem: boolean;
updated: boolean;
preRelease: boolean;
installedTimestamp: number;
pinned: boolean;
}>;

export interface ILocalExtension extends IExtension {
isMachineScoped: boolean;
Expand All @@ -251,6 +260,7 @@ export interface ILocalExtension extends IExtension {
isPreReleaseVersion: boolean;
preRelease: boolean;
updated: boolean;
pinned: boolean;
}

export const enum SortBy {
Expand Down Expand Up @@ -416,7 +426,7 @@ export type InstallOptions = {
context?: IStringDictionary<any>;
profileLocation?: URI;
};
export type InstallVSIXOptions = Omit<InstallOptions, 'installGivenVersion'> & { installOnlyNewlyAddedFromExtensionPack?: boolean };
export type InstallVSIXOptions = InstallOptions & { installOnlyNewlyAddedFromExtensionPack?: boolean };
export type UninstallOptions = { readonly donotIncludePack?: boolean; readonly donotCheckDependents?: boolean; readonly versionOnly?: boolean; readonly remove?: boolean; readonly profileLocation?: URI };

export interface IExtensionManagementParticipant {
Expand All @@ -432,6 +442,7 @@ export interface IExtensionManagementService {
onDidInstallExtensions: Event<readonly InstallExtensionResult[]>;
onUninstallExtension: Event<UninstallExtensionEvent>;
onDidUninstallExtension: Event<DidUninstallExtensionEvent>;
onDidUpdateExtensionMetadata: Event<ILocalExtension>;

zip(extension: ILocalExtension): Promise<URI>;
unzip(zipLocation: URI): Promise<IExtensionIdentifier>;
Expand All @@ -445,10 +456,10 @@ export interface IExtensionManagementService {
getInstalled(type?: ExtensionType, profileLocation?: URI): Promise<ILocalExtension[]>;
getExtensionsControlManifest(): Promise<IExtensionsControlManifest>;

getMetadata(extension: ILocalExtension, profileLocation?: URI): Promise<Metadata | undefined>;
updateMetadata(local: ILocalExtension, metadata: Partial<Metadata>, profileLocation?: URI): Promise<ILocalExtension>;

download(extension: IGalleryExtension, operation: InstallOperation): Promise<URI>;
getMetadata(extension: ILocalExtension): Promise<Metadata | undefined>;
updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): Promise<ILocalExtension>;
updateExtensionScope(local: ILocalExtension, isMachineScoped: boolean): Promise<ILocalExtension>;

registerParticipant(pariticipant: IExtensionManagementParticipant): void;
getTargetPlatform(): Promise<TargetPlatform>;
Expand Down
Expand Up @@ -10,7 +10,7 @@ import { cloneAndChange } from 'vs/base/common/objects';
import { URI, UriComponents } from 'vs/base/common/uri';
import { DefaultURITransformer, IURITransformer, transformAndReviveIncomingURIs } from 'vs/base/common/uriIpc';
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { IExtensionIdentifier, IExtensionTipsService, IGalleryExtension, IGalleryMetadata, ILocalExtension, IExtensionsControlManifest, isTargetPlatformCompatible, InstallOptions, InstallVSIXOptions, UninstallOptions, Metadata, IExtensionManagementService, DidUninstallExtensionEvent, InstallExtensionEvent, InstallExtensionResult, UninstallExtensionEvent, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionIdentifier, IExtensionTipsService, IGalleryExtension, ILocalExtension, IExtensionsControlManifest, isTargetPlatformCompatible, InstallOptions, InstallVSIXOptions, UninstallOptions, Metadata, IExtensionManagementService, DidUninstallExtensionEvent, InstallExtensionEvent, InstallExtensionResult, UninstallExtensionEvent, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionType, IExtensionManifest, TargetPlatform } from 'vs/platform/extensions/common/extensions';

function transformIncomingURI(uri: UriComponents, transformer: IURITransformer | null): URI {
Expand Down Expand Up @@ -38,12 +38,14 @@ export class ExtensionManagementChannel implements IServerChannel {
onDidInstallExtensions: Event<readonly InstallExtensionResult[]>;
onUninstallExtension: Event<UninstallExtensionEvent>;
onDidUninstallExtension: Event<DidUninstallExtensionEvent>;
onDidUpdateExtensionMetadata: Event<ILocalExtension>;

constructor(private service: IExtensionManagementService, private getUriTransformer: (requestContext: any) => IURITransformer | null) {
this.onInstallExtension = Event.buffer(service.onInstallExtension, true);
this.onDidInstallExtensions = Event.buffer(service.onDidInstallExtensions, true);
this.onUninstallExtension = Event.buffer(service.onUninstallExtension, true);
this.onDidUninstallExtension = Event.buffer(service.onDidUninstallExtension, true);
this.onDidUpdateExtensionMetadata = Event.buffer(service.onDidUpdateExtensionMetadata, true);
}

listen(context: any, event: string): Event<any> {
Expand All @@ -53,6 +55,7 @@ export class ExtensionManagementChannel implements IServerChannel {
case 'onDidInstallExtensions': return Event.map(this.onDidInstallExtensions, results => results.map(i => ({ ...i, local: i.local ? transformOutgoingExtension(i.local, uriTransformer) : i.local })));
case 'onUninstallExtension': return this.onUninstallExtension;
case 'onDidUninstallExtension': return this.onDidUninstallExtension;
case 'onDidUpdateExtensionMetadata': return this.onDidUpdateExtensionMetadata;
}

throw new Error('Invalid listen');
Expand All @@ -72,9 +75,8 @@ export class ExtensionManagementChannel implements IServerChannel {
case 'uninstall': return this.service.uninstall(transformIncomingExtension(args[0], uriTransformer), revive(args[1]));
case 'reinstallFromGallery': return this.service.reinstallFromGallery(transformIncomingExtension(args[0], uriTransformer));
case 'getInstalled': return this.service.getInstalled(args[0], URI.revive(args[1])).then(extensions => extensions.map(e => transformOutgoingExtension(e, uriTransformer)));
case 'getMetadata': return this.service.getMetadata(transformIncomingExtension(args[0], uriTransformer));
case 'updateMetadata': return this.service.updateMetadata(transformIncomingExtension(args[0], uriTransformer), args[1]).then(e => transformOutgoingExtension(e, uriTransformer));
case 'updateExtensionScope': return this.service.updateExtensionScope(transformIncomingExtension(args[0], uriTransformer), args[1]).then(e => transformOutgoingExtension(e, uriTransformer));
case 'getMetadata': return this.service.getMetadata(transformIncomingExtension(args[0], uriTransformer), URI.revive(args[1]));
case 'updateMetadata': return this.service.updateMetadata(transformIncomingExtension(args[0], uriTransformer), args[1], URI.revive(args[2])).then(e => transformOutgoingExtension(e, uriTransformer));
case 'getExtensionsControlManifest': return this.service.getExtensionsControlManifest();
case 'download': return this.service.download(args[0], args[1]);
}
Expand All @@ -99,12 +101,16 @@ export class ExtensionManagementChannelClient extends Disposable implements IExt
private readonly _onDidUninstallExtension = this._register(new Emitter<DidUninstallExtensionEvent>());
get onDidUninstallExtension() { return this._onDidUninstallExtension.event; }

private readonly _onDidUpdateExtensionMetadata = this._register(new Emitter<ILocalExtension>());
get onDidUpdateExtensionMetadata() { return this._onDidUpdateExtensionMetadata.event; }

constructor(private readonly channel: IChannel) {
super();
this._register(this.channel.listen<InstallExtensionEvent>('onInstallExtension')(e => this._onInstallExtension.fire({ identifier: e.identifier, source: this.isUriComponents(e.source) ? URI.revive(e.source) : e.source, profileLocation: URI.revive(e.profileLocation) })));
this._register(this.channel.listen<readonly InstallExtensionResult[]>('onDidInstallExtensions')(results => this._onDidInstallExtensions.fire(results.map(e => ({ ...e, local: e.local ? transformIncomingExtension(e.local, null) : e.local, source: this.isUriComponents(e.source) ? URI.revive(e.source) : e.source, profileLocation: URI.revive(e.profileLocation) })))));
this._register(this.channel.listen<UninstallExtensionEvent>('onUninstallExtension')(e => this._onUninstallExtension.fire({ identifier: e.identifier, profileLocation: URI.revive(e.profileLocation) })));
this._register(this.channel.listen<DidUninstallExtensionEvent>('onDidUninstallExtension')(e => this._onDidUninstallExtension.fire({ ...e, profileLocation: URI.revive(e.profileLocation) })));
this._register(this.channel.listen<ILocalExtension>('onDidUpdateExtensionMetadata')(e => this._onDidUpdateExtensionMetadata.fire(transformIncomingExtension(e, null))));
}

private isUriComponents(thing: unknown): thing is UriComponents {
Expand Down Expand Up @@ -165,17 +171,12 @@ export class ExtensionManagementChannelClient extends Disposable implements IExt
.then(extensions => extensions.map(extension => transformIncomingExtension(extension, null)));
}

getMetadata(local: ILocalExtension): Promise<Metadata | undefined> {
return Promise.resolve(this.channel.call<Metadata>('getMetadata', [local]));
}

updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): Promise<ILocalExtension> {
return Promise.resolve(this.channel.call<ILocalExtension>('updateMetadata', [local, metadata]))
.then(extension => transformIncomingExtension(extension, null));
getMetadata(local: ILocalExtension, extensionsProfileResource?: URI): Promise<Metadata | undefined> {
return Promise.resolve(this.channel.call<Metadata>('getMetadata', [local, extensionsProfileResource]));
}

updateExtensionScope(local: ILocalExtension, isMachineScoped: boolean): Promise<ILocalExtension> {
return Promise.resolve(this.channel.call<ILocalExtension>('updateExtensionScope', [local, isMachineScoped]))
updateMetadata(local: ILocalExtension, metadata: Partial<Metadata>, extensionsProfileResource?: URI): Promise<ILocalExtension> {
return Promise.resolve(this.channel.call<ILocalExtension>('updateMetadata', [local, metadata, extensionsProfileResource]))
.then(extension => transformIncomingExtension(extension, null));
}

Expand Down
Expand Up @@ -17,7 +17,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import { ILogService } from 'vs/platform/log/common/log';
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
import { isObject, isString } from 'vs/base/common/types';
import { Mutable, isObject, isString } from 'vs/base/common/types';
import { getErrorMessage } from 'vs/base/common/errors';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';

Expand Down Expand Up @@ -83,6 +83,7 @@ export interface IExtensionsProfileScannerService {

scanProfileExtensions(profileLocation: URI, options?: IProfileExtensionsScanOptions): Promise<IScannedProfileExtension[]>;
addExtensionsToProfile(extensions: [IExtension, Metadata | undefined][], profileLocation: URI): Promise<IScannedProfileExtension[]>;
updateMetadata(extensions: [IExtension, Metadata | undefined][], profileLocation: URI): Promise<IScannedProfileExtension[]>;
removeExtensionFromProfile(extension: IExtension, profileLocation: URI): Promise<void>;
}

Expand Down Expand Up @@ -166,6 +167,25 @@ export abstract class AbstractExtensionsProfileScannerService extends Disposable
}
}

async updateMetadata(extensions: [IExtension, Metadata][], profileLocation: URI): Promise<IScannedProfileExtension[]> {
const updatedExtensions: IScannedProfileExtension[] = [];
await this.withProfileExtensions(profileLocation, profileExtensions => {
const result: IScannedProfileExtension[] = [];
for (const profileExtension of profileExtensions) {
const extension = extensions.find(([e]) => areSameExtensions(e.identifier, profileExtension.identifier) && e.manifest.version === profileExtension.version);
if (extension) {
profileExtension.metadata = { ...profileExtension.metadata, ...extension[1] };
updatedExtensions.push(profileExtension);
result.push(profileExtension);
} else {
result.push(profileExtension);
}
}
return result;
});
return updatedExtensions;
}

async removeExtensionFromProfile(extension: IExtension, profileLocation: URI): Promise<void> {
const extensionsToRemove: IScannedProfileExtension[] = [];
this._onRemoveExtensions.fire({ extensions: extensionsToRemove, profileLocation });
Expand Down Expand Up @@ -195,7 +215,7 @@ export abstract class AbstractExtensionsProfileScannerService extends Disposable
}
}

private async withProfileExtensions(file: URI, updateFn?: (extensions: IScannedProfileExtension[]) => IScannedProfileExtension[], options?: IProfileExtensionsScanOptions): Promise<IScannedProfileExtension[]> {
private async withProfileExtensions(file: URI, updateFn?: (extensions: Mutable<IScannedProfileExtension>[]) => IScannedProfileExtension[], options?: IProfileExtensionsScanOptions): Promise<IScannedProfileExtension[]> {
return this.getResourceAccessQueue(file).queue(async () => {
let extensions: IScannedProfileExtension[] = [];

Expand Down