From 956cbd4794854774ff49eaa3c1d50b8e8071c327 Mon Sep 17 00:00:00 2001 From: Josh Spicer Date: Wed, 29 Jan 2025 10:56:42 -0800 Subject: [PATCH] send through InstallOptions --- .../remote/common/remoteExtensionsScanner.ts | 3 +- src/vs/server/node/remoteExtensionsScanner.ts | 33 +++++++--------- .../extensions.contribution.ts | 36 +---------------- .../installFailedExtensions.ts | 39 +++++++++++++++++++ .../remote/common/remoteExtensionsScanner.ts | 7 ++-- .../test/browser/workbenchTestServices.ts | 2 +- 6 files changed, 63 insertions(+), 57 deletions(-) create mode 100644 src/vs/workbench/contrib/extensions/electron-sandbox/installFailedExtensions.ts diff --git a/src/vs/platform/remote/common/remoteExtensionsScanner.ts b/src/vs/platform/remote/common/remoteExtensionsScanner.ts index ca5e5c3852f8ac..4dd81bc78453e8 100644 --- a/src/vs/platform/remote/common/remoteExtensionsScanner.ts +++ b/src/vs/platform/remote/common/remoteExtensionsScanner.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from '../../../base/common/uri.js'; +import { InstallOptions } from '../../extensionManagement/common/extensionManagement.js'; import { IExtensionDescription } from '../../extensions/common/extensions.js'; import { createDecorator } from '../../instantiation/common/instantiation.js'; @@ -17,6 +18,6 @@ export interface IRemoteExtensionsScannerService { /** * Returns a promise that resolves to an array of extension identifiers or URIs that failed to install */ - whenExtensionsReady(): Promise>; + whenExtensionsReady(): Promise<{ extensions: Array; installOptions: InstallOptions }>; scanExtensions(): Promise; } diff --git a/src/vs/server/node/remoteExtensionsScanner.ts b/src/vs/server/node/remoteExtensionsScanner.ts index 0e63a29dc0f321..b4c96952705ae2 100644 --- a/src/vs/server/node/remoteExtensionsScanner.ts +++ b/src/vs/server/node/remoteExtensionsScanner.ts @@ -28,8 +28,8 @@ export class RemoteExtensionsScannerService implements IRemoteExtensionsScannerS readonly _serviceBrand: undefined; - private readonly _whenBuiltinExtensionsReady = Promise.resolve>([]); - private readonly _whenExtensionsReady = Promise.resolve>([]); + private readonly _whenBuiltinExtensionsReady = Promise.resolve<{ extensions: Array; installOptions: InstallOptions }>({ extensions: [], installOptions: {} }); + private readonly _whenExtensionsReady = Promise.resolve<{ extensions: Array; installOptions: InstallOptions }>({ extensions: [], installOptions: {} }); constructor( private readonly _extensionManagementCLI: ExtensionManagementCLI, @@ -49,36 +49,33 @@ export class RemoteExtensionsScannerService implements IRemoteExtensionsScannerS .then(() => { performance.mark('code/server/didInstallBuiltinExtensions'); _logService.trace('Finished installing builtin extensions'); - return []; + return { extensions: [], installOptions: {} }; }, error => { _logService.error(error); - if (error instanceof ExtensionInstallationError) { - _logService.error(`Failed installing builtin extensions`); - return error.failed; - } - return []; + return { extensions: [], installOptions: {} }; }); } const extensionsToInstall = environmentService.args['install-extension']; if (extensionsToInstall) { _logService.trace('Installing extensions passed via args...'); + const installOptions: InstallOptions = { + isMachineScoped: !!environmentService.args['do-not-sync'], + installPreReleaseVersion: !!environmentService.args['pre-release'], + isApplicationScoped: true // extensions installed during server startup are available to all profiles + }; this._whenExtensionsReady = this._whenBuiltinExtensionsReady - .then(() => _extensionManagementCLI.installExtensions(this._asExtensionIdOrVSIX(extensionsToInstall), [], { - isMachineScoped: !!environmentService.args['do-not-sync'], - installPreReleaseVersion: !!environmentService.args['pre-release'], - isApplicationScoped: true // extensions installed during server startup are available to all profiles - }, !!environmentService.args['force'])) + .then(() => _extensionManagementCLI.installExtensions(this._asExtensionIdOrVSIX(extensionsToInstall), [], installOptions, !!environmentService.args['force'])) .then(() => { _logService.trace('Finished installing extensions'); - return []; + return { extensions: [], installOptions: {} }; }, error => { _logService.error(error); if (error instanceof ExtensionInstallationError) { _logService.error(`Failed installing extensions`); - return error.failed; + return { extensions: error.failed, installOptions: {} }; } - return []; + return { extensions: [], installOptions: {} }; }); } } @@ -87,7 +84,7 @@ export class RemoteExtensionsScannerService implements IRemoteExtensionsScannerS return inputs.map(input => /\.vsix$/i.test(input) ? URI.file(isAbsolute(input) ? input : join(cwd(), input)) : input); } - whenExtensionsReady(): Promise> { + whenExtensionsReady(): Promise<{ extensions: Array; installOptions: InstallOptions }> { return this._whenExtensionsReady; } @@ -320,7 +317,7 @@ export class RemoteExtensionsScannerChannel implements IServerChannel { async call(context: any, command: string, args?: any): Promise { const uriTransformer = this.getUriTransformer(context); switch (command) { - case 'whenExtensionsReady': return this.service.whenExtensionsReady(); + case 'whenExtensionsReady': return this.service.whenExtensionsReady(); // TODO: Need to do some serialization stuff here? case 'scanExtensions': { const language = args[0]; const profileLocation = args[1] ? URI.revive(uriTransformer.transformIncoming(args[1])) : undefined; diff --git a/src/vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution.ts index 32aafb7059fea6..9f793d53124e7b 100644 --- a/src/vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution.ts @@ -3,20 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CancellationToken } from '../../../../base/common/cancellation.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { localize } from '../../../../nls.js'; import { registerAction2 } from '../../../../platform/actions/common/actions.js'; -import { IExtensionGalleryService, IExtensionManagementService } from '../../../../platform/extensionManagement/common/extensionManagement.js'; import { IExtensionRecommendationNotificationService } from '../../../../platform/extensionRecommendations/common/extensionRecommendations.js'; import { ExtensionRecommendationNotificationServiceChannel } from '../../../../platform/extensionRecommendations/common/extensionRecommendationsIpc.js'; import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js'; import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { ISharedProcessService } from '../../../../platform/ipc/electron-sandbox/services.js'; -import { ILogService } from '../../../../platform/log/common/log.js'; import { Registry } from '../../../../platform/registry/common/platform.js'; -import { IRemoteExtensionsScannerService } from '../../../../platform/remote/common/remoteExtensionsScanner.js'; import { EditorPaneDescriptor, IEditorPaneRegistry } from '../../../browser/editor.js'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from '../../../common/contributions.js'; import { EditorExtensions, IEditorFactoryRegistry, IEditorSerializer } from '../../../common/editor.js'; @@ -27,6 +23,7 @@ import { DebugExtensionHostAction, DebugExtensionsContribution } from './debugEx import { ExtensionHostProfileService } from './extensionProfileService.js'; import { CleanUpExtensionsFolderAction, OpenExtensionsFolderAction } from './extensionsActions.js'; import { ExtensionsAutoProfiler } from './extensionsAutoProfiler.js'; +import { InstallFailedExtensions } from './installFailedExtensions.js'; import { RemoteExtensionsInitializerContribution } from './remoteExtensionsInit.js'; import { IExtensionHostProfileService, OpenExtensionHostProfileACtion, RuntimeExtensionsEditor, SaveExtensionHostProfileAction, StartExtensionHostProfileAction, StopExtensionHostProfileAction } from './runtimeExtensionsEditor.js'; @@ -71,41 +68,12 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi } } -class InstallFailedExtensionsThroughWorkbenchContribution extends Disposable implements IWorkbenchContribution { - constructor( - @IRemoteExtensionsScannerService remoteExtensionsScannerService: IRemoteExtensionsScannerService, - @IExtensionGalleryService private readonly _extensionGalleryService: IExtensionGalleryService, - @IExtensionManagementService private readonly _extensionManagementService: IExtensionManagementService, - @ILogService logService: ILogService, - ) { - super(); - - remoteExtensionsScannerService.whenExtensionsReady() - .then(async (failedFromRemote) => { - logService.debug('Failed from remote', failedFromRemote); - - // TODO: We probably want to pass through other information from the remote, like pre-release status. - const registryExtensionIds = - failedFromRemote - .filter(ext => typeof ext === 'string') - .map(ext => ({ id: ext })); - const exts = await this._extensionGalleryService.getExtensions(registryExtensionIds, CancellationToken.None); - for (const ext of exts) { - await this._extensionManagementService.installFromGallery(ext); - } - // TODO: Handle VSIX URIs somehow? - }).catch(e => { - logService.error('Failed in InstallFailedExtensionsThroughWorkbenchContribution', e); - }); - } -} - const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); workbenchRegistry.registerWorkbenchContribution(ExtensionsContributions, LifecyclePhase.Restored); workbenchRegistry.registerWorkbenchContribution(ExtensionsAutoProfiler, LifecyclePhase.Eventually); workbenchRegistry.registerWorkbenchContribution(RemoteExtensionsInitializerContribution, LifecyclePhase.Restored); workbenchRegistry.registerWorkbenchContribution(DebugExtensionsContribution, LifecyclePhase.Restored); -workbenchRegistry.registerWorkbenchContribution(InstallFailedExtensionsThroughWorkbenchContribution, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(InstallFailedExtensions, LifecyclePhase.Restored); // Register Commands diff --git a/src/vs/workbench/contrib/extensions/electron-sandbox/installFailedExtensions.ts b/src/vs/workbench/contrib/extensions/electron-sandbox/installFailedExtensions.ts new file mode 100644 index 00000000000000..8d40371383579b --- /dev/null +++ b/src/vs/workbench/contrib/extensions/electron-sandbox/installFailedExtensions.ts @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { CancellationToken } from '../../../../base/common/cancellation.js'; +import { Disposable } from '../../../../base/common/lifecycle.js'; +import { IExtensionGalleryService, IExtensionManagementService } from '../../../../platform/extensionManagement/common/extensionManagement.js'; +import { ILogService } from '../../../../platform/log/common/log.js'; +import { IRemoteExtensionsScannerService } from '../../../../platform/remote/common/remoteExtensionsScanner.js'; +import { IWorkbenchContribution } from '../../../common/contributions.js'; + +export class InstallFailedExtensions extends Disposable implements IWorkbenchContribution { + constructor( + @IRemoteExtensionsScannerService remoteExtensionsScannerService: IRemoteExtensionsScannerService, + @IExtensionGalleryService private readonly _extensionGalleryService: IExtensionGalleryService, + @IExtensionManagementService private readonly _extensionManagementService: IExtensionManagementService, + @ILogService logService: ILogService + ) { + super(); + + remoteExtensionsScannerService.whenExtensionsReady() + .then(async ({ extensions, installOptions }) => { + logService.debug('Failed from remote', extensions); + + const registryExtensionIds = extensions + .filter(ext => typeof ext === 'string') + .map(ext => ({ id: ext })); + + const exts = await this._extensionGalleryService.getExtensions(registryExtensionIds, CancellationToken.None); + for (const ext of exts) { + await this._extensionManagementService.installFromGallery(ext, installOptions); + } + + }).catch(e => { + logService.error('Failed in InstallFailedExtensions', e); + }); + } +} diff --git a/src/vs/workbench/services/remote/common/remoteExtensionsScanner.ts b/src/vs/workbench/services/remote/common/remoteExtensionsScanner.ts index 2a9ec2688a1ec4..64e8de178afff0 100644 --- a/src/vs/workbench/services/remote/common/remoteExtensionsScanner.ts +++ b/src/vs/workbench/services/remote/common/remoteExtensionsScanner.ts @@ -17,6 +17,7 @@ import { InstantiationType, registerSingleton } from '../../../../platform/insta import { IActiveLanguagePackService } from '../../localization/common/locale.js'; import { IWorkbenchExtensionManagementService } from '../../extensionManagement/common/extensionManagement.js'; import { Mutable } from '../../../../base/common/types.js'; +import { InstallOptions } from '../../../../platform/extensionManagement/common/extensionManagement.js'; class RemoteExtensionsScannerService implements IRemoteExtensionsScannerService { @@ -32,10 +33,10 @@ class RemoteExtensionsScannerService implements IRemoteExtensionsScannerService @ILogService private readonly logService: ILogService, ) { } - whenExtensionsReady(): Promise> { + whenExtensionsReady(): Promise<{ extensions: Array; installOptions: InstallOptions }> { return this.withChannel( - channel => channel.call>('whenExtensionsReady'), - [], + channel => channel.call<{ extensions: Array; installOptions: InstallOptions }>('whenExtensionsReady'), + { extensions: [], installOptions: {} }, ); } diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index d9c23fc25e97af..55475fc34c06fb 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -2166,7 +2166,7 @@ export class TestRemoteExtensionsScannerService implements IRemoteExtensionsScan throw new Error('Method not implemented.'); } declare readonly _serviceBrand: undefined; - async whenExtensionsReady(): Promise> { return []; } + async whenExtensionsReady(): Promise<{ extensions: Array; installOptions: InstallOptions }> { return { extensions: [], installOptions: {} }; } scanExtensions(): Promise { throw new Error('Method not implemented.'); } }