diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts index d177c9c3e22..00224d8bba7 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts @@ -10,7 +10,7 @@ import { ExtensionType, IExtensionManifest } from 'vs/platform/extensions/common import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { ILogService } from 'vs/platform/log/common/log'; import { toErrorMessage } from 'vs/base/common/errorMessage'; -import { coalesce, isNonEmptyArray } from 'vs/base/common/arrays'; +import { isNonEmptyArray } from 'vs/base/common/arrays'; import { CancellationToken } from 'vs/base/common/cancellation'; import { localize } from 'vs/nls'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -55,19 +55,14 @@ export class NativeRemoteExtensionManagementService extends WebRemoteExtensionMa private async doInstallFromGallery(extension: IGalleryExtension, installOptions?: InstallOptions): Promise { if (this.configurationService.getValue('remote.downloadExtensionsLocally')) { - this.logService.trace(`Download '${extension.identifier.id}' extension locally and install`); - return this.downloadCompatibleAndInstall(extension); + return this.downloadAndInstall(extension, installOptions || {}); } try { - const local = await super.installFromGallery(extension, installOptions); - return local; + return await super.installFromGallery(extension, installOptions); } catch (error) { try { this.logService.error(`Error while installing '${extension.identifier.id}' extension in the remote server.`, toErrorMessage(error)); - this.logService.info(`Trying to download '${extension.identifier.id}' extension locally and install`); - const local = await this.downloadCompatibleAndInstall(extension); - this.logService.info(`Successfully installed '${extension.identifier.id}' extension`); - return local; + return await this.downloadAndInstall(extension, installOptions || {}); } catch (e) { this.logService.error(e); throw error; @@ -75,31 +70,41 @@ export class NativeRemoteExtensionManagementService extends WebRemoteExtensionMa } } - private async downloadCompatibleAndInstall(extension: IGalleryExtension): Promise { + private async downloadAndInstall(extension: IGalleryExtension, installOptions: InstallOptions): Promise { + this.logService.info(`Downloading the '${extension.identifier.id}' extension locally and install`); + installOptions = { ...installOptions, donotIncludePackAndDependencies: true }; const installed = await this.getInstalled(ExtensionType.User); + const workspaceExtensions = await this.getAllWorkspaceDependenciesAndPackedExtensions(extension, CancellationToken.None); + if (workspaceExtensions.length) { + this.logService.info(`Downloading the workspace dependencies and packed extensions of '${extension.identifier.id}' locally and install`); + for (const workspaceExtension of workspaceExtensions) { + await this.downloadCompatibleAndInstall(workspaceExtension, installed, installOptions); + } + } + return await this.downloadCompatibleAndInstall(extension, installed, installOptions); + } + + private async downloadCompatibleAndInstall(extension: IGalleryExtension, installed: ILocalExtension[], installOptions: InstallOptions): Promise { const compatible = await this.galleryService.getCompatibleExtension(extension); if (!compatible) { return Promise.reject(new Error(localize('incompatible', "Unable to install extension '{0}' as it is not compatible with VS Code '{1}'.", extension.identifier.id, this.productService.version))); } - const manifest = await this.galleryService.getManifest(compatible, CancellationToken.None); - if (manifest) { - const workspaceExtensions = await this.getAllWorkspaceDependenciesAndPackedExtensions(manifest, CancellationToken.None); - await Promises.settled(workspaceExtensions.map(e => this.downloadAndInstall(e, installed))); - } - return this.downloadAndInstall(extension, installed); - } - - private async downloadAndInstall(extension: IGalleryExtension, installed: ILocalExtension[]): Promise { const location = joinPath(this.environmentService.tmpDir, generateUuid()); - await this.galleryService.download(extension, location, installed.filter(i => areSameExtensions(i.identifier, extension.identifier))[0] ? InstallOperation.Update : InstallOperation.Install); - return super.install(location); + this.logService.info('Downloaded extension:', compatible.identifier.id, location.path); + await this.galleryService.download(compatible, location, installed.filter(i => areSameExtensions(i.identifier, compatible.identifier))[0] ? InstallOperation.Update : InstallOperation.Install); + const local = await super.install(location, installOptions); + this.logService.info(`Successfully installed '${compatible.identifier.id}' extension`); + return local; } private async installUIDependenciesAndPackedExtensions(local: ILocalExtension): Promise { const uiExtensions = await this.getAllUIDependenciesAndPackedExtensions(local.manifest, CancellationToken.None); const installed = await this.localExtensionManagementService.getInstalled(); const toInstall = uiExtensions.filter(e => installed.every(i => !areSameExtensions(i.identifier, e.identifier))); - await Promises.settled(toInstall.map(d => this.localExtensionManagementService.installFromGallery(d))); + if (toInstall.length) { + this.logService.info(`Installing UI dependencies and packed extensions of '${local.identifier.id}' locally`); + await Promises.settled(toInstall.map(d => this.localExtensionManagementService.installFromGallery(d))); + } } private async getAllUIDependenciesAndPackedExtensions(manifest: IExtensionManifest, token: CancellationToken): Promise { @@ -109,10 +114,15 @@ export class NativeRemoteExtensionManagementService extends WebRemoteExtensionMa return [...result.values()]; } - private async getAllWorkspaceDependenciesAndPackedExtensions(manifest: IExtensionManifest, token: CancellationToken): Promise { + private async getAllWorkspaceDependenciesAndPackedExtensions(extension: IGalleryExtension, token: CancellationToken): Promise { const result = new Map(); - const extensions = [...(manifest.extensionPack || []), ...(manifest.extensionDependencies || [])]; - await this.getDependenciesAndPackedExtensionsRecursively(extensions, result, false, token); + result.set(extension.identifier.id.toLowerCase(), extension); + const manifest = await this.galleryService.getManifest(extension, token); + if (manifest) { + const extensions = [...(manifest.extensionPack || []), ...(manifest.extensionDependencies || [])]; + await this.getDependenciesAndPackedExtensionsRecursively(extensions, result, false, token); + } + result.delete(extension.identifier.id); return [...result.values()]; } @@ -121,7 +131,7 @@ export class NativeRemoteExtensionManagementService extends WebRemoteExtensionMa return Promise.resolve(); } - const extensions = coalesce(await Promises.settled(toGet.map(id => this.galleryService.getCompatibleExtension({ id })))); + const extensions = await this.galleryService.getExtensions(toGet, token); const manifests = await Promise.all(extensions.map(e => this.galleryService.getManifest(e, token))); const extensionsManifests: IExtensionManifest[] = []; for (let idx = 0; idx < extensions.length; idx++) {