This commit is contained in:
Sandeep Somavarapu 2021-05-31 17:44:08 +02:00
parent 78c865d70d
commit 1176faf27f
No known key found for this signature in database
GPG key ID: 1FED25EC4646638B
7 changed files with 48 additions and 29 deletions

View file

@ -203,6 +203,7 @@ export class ExtensionManagementError extends Error {
}
export type InstallOptions = { isBuiltin?: boolean, isMachineScoped?: boolean, donotIncludePackAndDependencies?: boolean };
export type InstallVSIXOptions = InstallOptions & { installOnlyNewlyAddedFromExtensionPack?: boolean };
export type UninstallOptions = { donotIncludePack?: boolean, donotCheckDependents?: boolean };
export const IExtensionManagementService = createDecorator<IExtensionManagementService>('extensionManagementService');
@ -217,7 +218,7 @@ export interface IExtensionManagementService {
zip(extension: ILocalExtension): Promise<URI>;
unzip(zipLocation: URI): Promise<IExtensionIdentifier>;
getManifest(vsix: URI): Promise<IExtensionManifest>;
install(vsix: URI, options?: InstallOptions): Promise<ILocalExtension>;
install(vsix: URI, options?: InstallVSIXOptions): Promise<ILocalExtension>;
canInstall(extension: IGalleryExtension): Promise<boolean>;
installFromGallery(extension: IGalleryExtension, options?: InstallOptions): Promise<ILocalExtension>;
uninstall(extension: ILocalExtension, options?: UninstallOptions): Promise<void>;

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension, IExtensionTipsService, InstallOptions, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension, IExtensionTipsService, InstallOptions, UninstallOptions, InstallVSIXOptions } from 'vs/platform/extensionManagement/common/extensionManagement';
import { Emitter, Event } from 'vs/base/common/event';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IURITransformer, DefaultURITransformer, transformAndReviveIncomingURIs } from 'vs/base/common/uriIpc';
@ -62,7 +62,7 @@ export class ExtensionManagementChannel implements IServerChannel {
switch (command) {
case 'zip': return this.service.zip(transformIncomingExtension(args[0], uriTransformer)).then(uri => transformOutgoingURI(uri, uriTransformer));
case 'unzip': return this.service.unzip(transformIncomingURI(args[0], uriTransformer));
case 'install': return this.service.install(transformIncomingURI(args[0], uriTransformer));
case 'install': return this.service.install(transformIncomingURI(args[0], uriTransformer), args[1]);
case 'getManifest': return this.service.getManifest(transformIncomingURI(args[0], uriTransformer));
case 'canInstall': return this.service.canInstall(args[0]);
case 'installFromGallery': return this.service.installFromGallery(args[0], args[1]);
@ -112,8 +112,8 @@ export class ExtensionManagementChannelClient extends Disposable implements IExt
return Promise.resolve(this.channel.call('unzip', [zipLocation]));
}
install(vsix: URI): Promise<ILocalExtension> {
return Promise.resolve(this.channel.call<ILocalExtension>('install', [vsix])).then(local => transformIncomingExtension(local, null));
install(vsix: URI, options?: InstallVSIXOptions): Promise<ILocalExtension> {
return Promise.resolve(this.channel.call<ILocalExtension>('install', [vsix, options])).then(local => transformIncomingExtension(local, null));
}
getManifest(vsix: URI): Promise<IExtensionManifest> {

View file

@ -21,7 +21,8 @@ import {
INSTALL_ERROR_INCOMPATIBLE,
ExtensionManagementError,
InstallOptions,
UninstallOptions
UninstallOptions,
InstallVSIXOptions
} from 'vs/platform/extensionManagement/common/extensionManagement';
import { areSameExtensions, getGalleryExtensionId, getMaliciousExtensionsSet, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, ExtensionIdentifierWithVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
@ -159,7 +160,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
return files.map(f => (<IFile>{ path: `extension/${path.relative(extension.location.fsPath, f)}`, localPath: f }));
}
async install(vsix: URI, options: InstallOptions = {}): Promise<ILocalExtension> {
async install(vsix: URI, options: InstallVSIXOptions = {}): Promise<ILocalExtension> {
this.logService.trace('ExtensionManagementService#install', vsix.toString());
return createCancelablePromise(async token => {
@ -211,7 +212,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
} catch (e) { /* Ignore */ }
try {
const local = await this.installFromZipPath(identifierWithVersion, zipPath, { ...(metadata || {}), ...options }, options, operation, token);
const local = await this.installFromZipPath(identifierWithVersion, zipPath, options.installOnlyNewlyAddedFromExtensionPack ? existing : undefined, { ...(metadata || {}), ...options }, options, operation, token);
this.logService.info('Successfully installed the extension:', identifier.id);
return local;
} catch (e) {
@ -234,11 +235,13 @@ export class ExtensionManagementService extends Disposable implements IExtension
return downloadedLocation;
}
private async installFromZipPath(identifierWithVersion: ExtensionIdentifierWithVersion, zipPath: string, metadata: IMetadata | undefined, options: InstallOptions, operation: InstallOperation, token: CancellationToken): Promise<ILocalExtension> {
private async installFromZipPath(identifierWithVersion: ExtensionIdentifierWithVersion, zipPath: string, existing: ILocalExtension | undefined, metadata: IMetadata | undefined, options: InstallOptions, operation: InstallOperation, token: CancellationToken): Promise<ILocalExtension> {
try {
const local = await this.installExtension({ zipPath, identifierWithVersion, metadata }, token);
try {
await this.installDependenciesAndPackExtensions(local, undefined, options);
if (!options.donotIncludePackAndDependencies) {
await this.installDependenciesAndPackExtensions(local, existing, options);
}
} catch (error) {
if (isNonEmptyArray(local.manifest.extensionDependencies)) {
this.logService.warn(`Cannot install dependencies of extension:`, local.identifier.id, error.message);

View file

@ -251,14 +251,29 @@ CommandsRegistry.registerCommand({
description: localize('workbench.extensions.installExtension.description', "Install the given extension"),
args: [
{
name: localize('workbench.extensions.installExtension.arg.name', "Extension id or VSIX resource uri"),
name: 'extensionIdOrVSIXUri',
description: localize('workbench.extensions.installExtension.arg.decription', "Extension id or VSIX resource uri"),
constraint: (value: any) => typeof value === 'string' || value instanceof URI,
},
{
name: 'options',
description: '(optional) Options for installing the extension. Object with the following properties: ' +
'`installOnlyNewlyAddedFromExtensionPackVSIX`: When enabled, VS Code installs only newly added extensions from the extension pack VSIX. This option is considered only when installing VSIX. ',
isOptional: true,
schema: {
'type': ['object', 'string']
'type': 'object',
'properties': {
'installOnlyNewlyAddedFromExtensionPackVSIX': {
'type': 'boolean',
'description': localize('workbench.extensions.installExtension.option.installOnlyNewlyAddedFromExtensionPackVSIX', "When enabled, VS Code installs only newly added extensions from the extension pack VSIX. This option is considered only while installing a VSIX."),
default: false
}
}
}
}
]
},
handler: async (accessor, arg: string | UriComponents) => {
handler: async (accessor, arg: string | UriComponents, options?: { installOnlyNewlyAddedFromExtensionPackVSIX?: boolean }) => {
const extensionManagementService = accessor.get(IExtensionManagementService);
const extensionGalleryService = accessor.get(IExtensionGalleryService);
try {
@ -271,7 +286,7 @@ CommandsRegistry.registerCommand({
}
} else {
const vsix = URI.revive(arg);
await extensionManagementService.install(vsix);
await extensionManagementService.install(vsix, { installOnlyNewlyAddedFromExtensionPack: options?.installOnlyNewlyAddedFromExtensionPackVSIX });
}
} catch (e) {
onUnexpectedError(e);

View file

@ -5,7 +5,7 @@
import { Event, EventMultiplexer } from 'vs/base/common/event';
import {
ILocalExtension, IGalleryExtension, InstallExtensionEvent, DidInstallExtensionEvent, IExtensionIdentifier, DidUninstallExtensionEvent, IReportedExtension, IGalleryMetadata, IExtensionGalleryService, InstallOptions, UninstallOptions, INSTALL_ERROR_NOT_SUPPORTED
ILocalExtension, IGalleryExtension, InstallExtensionEvent, DidInstallExtensionEvent, IExtensionIdentifier, DidUninstallExtensionEvent, IReportedExtension, IGalleryMetadata, IExtensionGalleryService, InstallOptions, UninstallOptions, INSTALL_ERROR_NOT_SUPPORTED, InstallVSIXOptions
} from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionManagementServer, IExtensionManagementServerService, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { ExtensionType, isLanguagePackExtension, IExtensionManifest } from 'vs/platform/extensions/common/extensions';
@ -171,35 +171,35 @@ export class ExtensionManagementService extends Disposable implements IWorkbench
.map(({ extensionManagementService }) => extensionManagementService.unzip(zipLocation))).then(([extensionIdentifier]) => extensionIdentifier);
}
async install(vsix: URI): Promise<ILocalExtension> {
async install(vsix: URI, options?: InstallVSIXOptions): Promise<ILocalExtension> {
if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) {
const manifest = await this.getManifest(vsix);
if (isLanguagePackExtension(manifest)) {
// Install on both servers
const [local] = await Promises.settled([this.extensionManagementServerService.localExtensionManagementServer, this.extensionManagementServerService.remoteExtensionManagementServer].map(server => this.installVSIX(vsix, server)));
const [local] = await Promises.settled([this.extensionManagementServerService.localExtensionManagementServer, this.extensionManagementServerService.remoteExtensionManagementServer].map(server => this.installVSIX(vsix, server, options)));
return local;
}
if (this.extensionManifestPropertiesService.prefersExecuteOnUI(manifest)) {
// Install only on local server
return this.installVSIX(vsix, this.extensionManagementServerService.localExtensionManagementServer);
return this.installVSIX(vsix, this.extensionManagementServerService.localExtensionManagementServer, options);
}
// Install only on remote server
return this.installVSIX(vsix, this.extensionManagementServerService.remoteExtensionManagementServer);
return this.installVSIX(vsix, this.extensionManagementServerService.remoteExtensionManagementServer, options);
}
if (this.extensionManagementServerService.localExtensionManagementServer) {
return this.installVSIX(vsix, this.extensionManagementServerService.localExtensionManagementServer);
return this.installVSIX(vsix, this.extensionManagementServerService.localExtensionManagementServer, options);
}
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
return this.installVSIX(vsix, this.extensionManagementServerService.remoteExtensionManagementServer);
return this.installVSIX(vsix, this.extensionManagementServerService.remoteExtensionManagementServer, options);
}
return Promise.reject('No Servers to Install');
}
protected async installVSIX(vsix: URI, server: IExtensionManagementServer): Promise<ILocalExtension> {
protected async installVSIX(vsix: URI, server: IExtensionManagementServer, options: InstallVSIXOptions | undefined): Promise<ILocalExtension> {
const manifest = await this.getManifest(vsix);
if (manifest) {
await this.checkForWorkspaceTrust(manifest);
return server.extensionManagementService.install(vsix);
return server.extensionManagementService.install(vsix, options);
}
return Promise.reject('Unable to get the extension manifest.');
}

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { generateUuid } from 'vs/base/common/uuid';
import { ILocalExtension, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ILocalExtension, IExtensionGalleryService, InstallVSIXOptions } from 'vs/platform/extensionManagement/common/extensionManagement';
import { URI } from 'vs/base/common/uri';
import { ExtensionManagementService as BaseExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagementService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
@ -38,7 +38,7 @@ export class ExtensionManagementService extends BaseExtensionManagementService {
super(extensionManagementServerService, extensionGalleryService, configurationService, productService, downloadService, userDataAutoSyncEnablementService, userDataSyncResourceEnablementService, dialogService, workspaceTrustRequestService, extensionManifestPropertiesService);
}
protected override async installVSIX(vsix: URI, server: IExtensionManagementServer): Promise<ILocalExtension> {
protected override async installVSIX(vsix: URI, server: IExtensionManagementServer, options: InstallVSIXOptions | undefined): Promise<ILocalExtension> {
if (vsix.scheme === Schemas.vscodeRemote && server === this.extensionManagementServerService.localExtensionManagementServer) {
const downloadedLocation = joinPath(this.environmentService.tmpDir, generateUuid());
await this.downloadService.download(vsix, downloadedLocation);
@ -47,7 +47,7 @@ export class ExtensionManagementService extends BaseExtensionManagementService {
const manifest = await this.getManifest(vsix);
if (manifest) {
await this.checkForWorkspaceTrust(manifest);
return server.extensionManagementService.install(vsix);
return server.extensionManagementService.install(vsix, options);
}
return Promise.reject('Unable to get the extension manifest.');

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { IExtensionManagementService, ILocalExtension, IGalleryExtension, IExtensionGalleryService, InstallOperation, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionManagementService, ILocalExtension, IGalleryExtension, IExtensionGalleryService, InstallOperation, InstallOptions, InstallVSIXOptions } 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';
@ -41,8 +41,8 @@ export class NativeRemoteExtensionManagementService extends WebRemoteExtensionMa
this.localExtensionManagementService = localExtensionManagementServer.extensionManagementService;
}
override async install(vsix: URI): Promise<ILocalExtension> {
const local = await super.install(vsix);
override async install(vsix: URI, options?: InstallVSIXOptions): Promise<ILocalExtension> {
const local = await super.install(vsix, options);
await this.installUIDependenciesAndPackedExtensions(local);
return local;
}