mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 21:55:38 +00:00
Merge pull request #115302 from microsoft/sandy081/remoteCLI
Remote CLI: Only manage remote extensions
This commit is contained in:
commit
c8a90a4826
|
@ -17,7 +17,6 @@ import { Schemas } from 'vs/base/common/network';
|
||||||
import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
|
import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
|
||||||
|
|
||||||
const notFound = (id: string) => localize('notFound', "Extension '{0}' not found.", id);
|
const notFound = (id: string) => localize('notFound', "Extension '{0}' not found.", id);
|
||||||
const notInstalled = (id: string) => localize('notInstalled', "Extension '{0}' is not installed.", id);
|
|
||||||
const useId = localize('useId', "Make sure you use the full extension ID, including the publisher, e.g.: {0}", 'ms-dotnettools.csharp');
|
const useId = localize('useId', "Make sure you use the full extension ID, including the publisher, e.g.: {0}", 'ms-dotnettools.csharp');
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,6 +51,9 @@ export class ExtensionManagementCLIService implements IExtensionManagementCLISer
|
||||||
@ILocalizationsService private readonly localizationsService: ILocalizationsService
|
@ILocalizationsService private readonly localizationsService: ILocalizationsService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
protected get location(): string | undefined {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
public async listExtensions(showVersions: boolean, category?: string, output: CLIOutput = console): Promise<void> {
|
public async listExtensions(showVersions: boolean, category?: string, output: CLIOutput = console): Promise<void> {
|
||||||
let extensions = await this.extensionManagementService.getInstalled(ExtensionType.User);
|
let extensions = await this.extensionManagementService.getInstalled(ExtensionType.User);
|
||||||
|
@ -75,6 +77,10 @@ export class ExtensionManagementCLIService implements IExtensionManagementCLISer
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (this.location) {
|
||||||
|
output.log(localize('listFromLocation', "Extensions installed on {0}:", this.location));
|
||||||
|
}
|
||||||
|
|
||||||
extensions = extensions.sort((e1, e2) => e1.identifier.id.localeCompare(e2.identifier.id));
|
extensions = extensions.sort((e1, e2) => e1.identifier.id.localeCompare(e2.identifier.id));
|
||||||
let lastId: string | undefined = undefined;
|
let lastId: string | undefined = undefined;
|
||||||
for (let extension of extensions) {
|
for (let extension of extensions) {
|
||||||
|
@ -89,7 +95,7 @@ export class ExtensionManagementCLIService implements IExtensionManagementCLISer
|
||||||
const failed: string[] = [];
|
const failed: string[] = [];
|
||||||
const installedExtensionsManifests: IExtensionManifest[] = [];
|
const installedExtensionsManifests: IExtensionManifest[] = [];
|
||||||
if (extensions.length) {
|
if (extensions.length) {
|
||||||
output.log(localize('installingExtensions', "Installing extensions..."));
|
output.log(this.location ? localize('installingExtensionsOnLocation', "Installing extensions on {0}...", this.location) : localize('installingExtensions', "Installing extensions..."));
|
||||||
}
|
}
|
||||||
|
|
||||||
const installed = await this.extensionManagementService.getInstalled(ExtensionType.User);
|
const installed = await this.extensionManagementService.getInstalled(ExtensionType.User);
|
||||||
|
@ -176,7 +182,11 @@ export class ExtensionManagementCLIService implements IExtensionManagementCLISer
|
||||||
private async installVSIX(vsix: URI, force: boolean, output: CLIOutput): Promise<IExtensionManifest | null> {
|
private async installVSIX(vsix: URI, force: boolean, output: CLIOutput): Promise<IExtensionManifest | null> {
|
||||||
|
|
||||||
const manifest = await this.extensionManagementService.getManifest(vsix);
|
const manifest = await this.extensionManagementService.getManifest(vsix);
|
||||||
const valid = await this.validate(manifest, force, output);
|
if (!manifest) {
|
||||||
|
throw new Error('Invalid vsix');
|
||||||
|
}
|
||||||
|
|
||||||
|
const valid = await this.validateVSIX(manifest, force, output);
|
||||||
if (valid) {
|
if (valid) {
|
||||||
try {
|
try {
|
||||||
await this.extensionManagementService.install(vsix);
|
await this.extensionManagementService.install(vsix);
|
||||||
|
@ -217,6 +227,10 @@ export class ExtensionManagementCLIService implements IExtensionManagementCLISer
|
||||||
|
|
||||||
private async installFromGallery({ id, version, installOptions }: InstallExtensionInfo, galleryExtension: IGalleryExtension, installed: ILocalExtension[], force: boolean, output: CLIOutput): Promise<IExtensionManifest | null> {
|
private async installFromGallery({ id, version, installOptions }: InstallExtensionInfo, galleryExtension: IGalleryExtension, installed: ILocalExtension[], force: boolean, output: CLIOutput): Promise<IExtensionManifest | null> {
|
||||||
const manifest = await this.extensionGalleryService.getManifest(galleryExtension, CancellationToken.None);
|
const manifest = await this.extensionGalleryService.getManifest(galleryExtension, CancellationToken.None);
|
||||||
|
if (manifest && !this.validateExtensionKind(manifest, output)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const installedExtension = installed.find(e => areSameExtensions(e.identifier, galleryExtension.identifier));
|
const installedExtension = installed.find(e => areSameExtensions(e.identifier, galleryExtension.identifier));
|
||||||
if (installedExtension) {
|
if (installedExtension) {
|
||||||
if (galleryExtension.version === installedExtension.manifest.version) {
|
if (galleryExtension.version === installedExtension.manifest.version) {
|
||||||
|
@ -232,6 +246,7 @@ export class ExtensionManagementCLIService implements IExtensionManagementCLISer
|
||||||
} else {
|
} else {
|
||||||
output.log(localize('installing', "Installing extension '{0}' v{1}...", id, galleryExtension.version));
|
output.log(localize('installing', "Installing extension '{0}' v{1}...", id, galleryExtension.version));
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.extensionManagementService.installFromGallery(galleryExtension, installOptions);
|
await this.extensionManagementService.installFromGallery(galleryExtension, installOptions);
|
||||||
output.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed.", id, galleryExtension.version));
|
output.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed.", id, galleryExtension.version));
|
||||||
return manifest;
|
return manifest;
|
||||||
|
@ -245,11 +260,11 @@ export class ExtensionManagementCLIService implements IExtensionManagementCLISer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async validate(manifest: IExtensionManifest, force: boolean, output: CLIOutput): Promise<boolean> {
|
protected validateExtensionKind(_manifest: IExtensionManifest, output: CLIOutput): boolean {
|
||||||
if (!manifest) {
|
return true;
|
||||||
throw new Error('Invalid vsix');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
private async validateVSIX(manifest: IExtensionManifest, force: boolean, output: CLIOutput): Promise<boolean> {
|
||||||
const extensionIdentifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) };
|
const extensionIdentifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) };
|
||||||
const installedExtensions = await this.extensionManagementService.getInstalled(ExtensionType.User);
|
const installedExtensions = await this.extensionManagementService.getInstalled(ExtensionType.User);
|
||||||
const newer = installedExtensions.find(local => areSameExtensions(extensionIdentifier, local.identifier) && gt(local.manifest.version, manifest.version));
|
const newer = installedExtensions.find(local => areSameExtensions(extensionIdentifier, local.identifier) && gt(local.manifest.version, manifest.version));
|
||||||
|
@ -259,7 +274,7 @@ export class ExtensionManagementCLIService implements IExtensionManagementCLISer
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return this.validateExtensionKind(manifest, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async uninstallExtensions(extensions: (string | URI)[], force: boolean, output: CLIOutput = console): Promise<void> {
|
public async uninstallExtensions(extensions: (string | URI)[], force: boolean, output: CLIOutput = console): Promise<void> {
|
||||||
|
@ -277,7 +292,7 @@ export class ExtensionManagementCLIService implements IExtensionManagementCLISer
|
||||||
const installed = await this.extensionManagementService.getInstalled();
|
const installed = await this.extensionManagementService.getInstalled();
|
||||||
const extensionsToUninstall = installed.filter(e => areSameExtensions(e.identifier, { id }));
|
const extensionsToUninstall = installed.filter(e => areSameExtensions(e.identifier, { id }));
|
||||||
if (!extensionsToUninstall.length) {
|
if (!extensionsToUninstall.length) {
|
||||||
throw new Error(`${notInstalled(id)}\n${useId}`);
|
throw new Error(`${this.notInstalled(id)}\n${useId}`);
|
||||||
}
|
}
|
||||||
if (extensionsToUninstall.some(e => e.type === ExtensionType.System)) {
|
if (extensionsToUninstall.some(e => e.type === ExtensionType.System)) {
|
||||||
output.log(localize('builtin', "Extension '{0}' is a Built-in extension and cannot be uninstalled", id));
|
output.log(localize('builtin', "Extension '{0}' is a Built-in extension and cannot be uninstalled", id));
|
||||||
|
@ -293,7 +308,12 @@ export class ExtensionManagementCLIService implements IExtensionManagementCLISer
|
||||||
uninstalledExtensions.push(extensionToUninstall);
|
uninstalledExtensions.push(extensionToUninstall);
|
||||||
}
|
}
|
||||||
|
|
||||||
output.log(localize('successUninstall', "Extension '{0}' was successfully uninstalled!", id));
|
if (this.location) {
|
||||||
|
output.log(localize('successUninstallFromLocation', "Extension '{0}' was successfully uninstalled from {1}!", id, this.location));
|
||||||
|
} else {
|
||||||
|
output.log(localize('successUninstall', "Extension '{0}' was successfully uninstalled!", id));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uninstalledExtensions.some(e => isLanguagePackExtension(e.manifest))) {
|
if (uninstalledExtensions.some(e => isLanguagePackExtension(e.manifest))) {
|
||||||
|
@ -319,4 +339,9 @@ export class ExtensionManagementCLIService implements IExtensionManagementCLISer
|
||||||
private updateLocalizationsCache(): Promise<boolean> {
|
private updateLocalizationsCache(): Promise<boolean> {
|
||||||
return this.localizationsService.update();
|
return this.localizationsService.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private notInstalled(id: string) {
|
||||||
|
return this.location ? localize('notInstalleddOnLocation', "Extension '{0}' is not installed on {1}.", id, this.location) : localize('notInstalled', "Extension '{0}' is not installed.", id);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,28 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { isString } from 'vs/base/common/types';
|
import { isString } from 'vs/base/common/types';
|
||||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||||
|
import { localize } from 'vs/nls';
|
||||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||||
import { IExtensionManagementCLIService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
import { CLIOutput, IExtensionGalleryService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||||
|
import { ExtensionManagementCLIService } from 'vs/platform/extensionManagement/common/extensionManagementCLIService';
|
||||||
|
import { getExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||||
|
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||||
|
import { ILabelService } from 'vs/platform/label/common/label';
|
||||||
|
import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
|
||||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
|
import { IProductService } from 'vs/platform/product/common/productService';
|
||||||
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
|
import { IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||||
|
import { canExecuteOnWorkspace } from 'vs/workbench/services/extensions/common/extensionsUtil';
|
||||||
|
import { IExtensionManifest } from 'vs/workbench/workbench.web.api';
|
||||||
|
|
||||||
|
|
||||||
// this class contains the command that the CLI server is reying on
|
// this class contains the commands that the CLI server is reying on
|
||||||
|
|
||||||
CommandsRegistry.registerCommand('_remoteCLI.openExternal', function (accessor: ServicesAccessor, uri: UriComponents, options: { allowTunneling?: boolean }) {
|
CommandsRegistry.registerCommand('_remoteCLI.openExternal', function (accessor: ServicesAccessor, uri: UriComponents, options: { allowTunneling?: boolean }) {
|
||||||
// TODO: discuss martin, ben where to put this
|
// TODO: discuss martin, ben where to put this
|
||||||
|
@ -28,7 +41,14 @@ interface ManageExtensionsArgs {
|
||||||
|
|
||||||
CommandsRegistry.registerCommand('_remoteCLI.manageExtensions', async function (accessor: ServicesAccessor, args: ManageExtensionsArgs) {
|
CommandsRegistry.registerCommand('_remoteCLI.manageExtensions', async function (accessor: ServicesAccessor, args: ManageExtensionsArgs) {
|
||||||
|
|
||||||
const cliService = accessor.get(IExtensionManagementCLIService);
|
const instantiationService = accessor.get(IInstantiationService);
|
||||||
|
const extensionManagementServerService = accessor.get(IExtensionManagementServerService);
|
||||||
|
const remoteExtensionManagementService = extensionManagementServerService.remoteExtensionManagementServer?.extensionManagementService;
|
||||||
|
if (!remoteExtensionManagementService) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cliService = instantiationService.createChild(new ServiceCollection([IExtensionManagementService, remoteExtensionManagementService])).createInstance(RemoteExtensionCLIManagementService);
|
||||||
|
|
||||||
const lines: string[] = [];
|
const lines: string[] = [];
|
||||||
const output = { log: lines.push.bind(lines), error: lines.push.bind(lines) };
|
const output = { log: lines.push.bind(lines), error: lines.push.bind(lines) };
|
||||||
|
@ -55,3 +75,34 @@ CommandsRegistry.registerCommand('_remoteCLI.manageExtensions', async function (
|
||||||
return lines.join('\n');
|
return lines.join('\n');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
class RemoteExtensionCLIManagementService extends ExtensionManagementCLIService {
|
||||||
|
|
||||||
|
private _location: string | undefined;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@IExtensionManagementService extensionManagementService: IExtensionManagementService,
|
||||||
|
@IProductService private readonly productService: IProductService,
|
||||||
|
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||||
|
@IExtensionGalleryService extensionGalleryService: IExtensionGalleryService,
|
||||||
|
@ILocalizationsService localizationsService: ILocalizationsService,
|
||||||
|
@ILabelService labelService: ILabelService,
|
||||||
|
@IWorkbenchEnvironmentService envService: IWorkbenchEnvironmentService
|
||||||
|
) {
|
||||||
|
super(extensionManagementService, extensionGalleryService, localizationsService);
|
||||||
|
|
||||||
|
const remoteAuthority = envService.remoteAuthority;
|
||||||
|
this._location = remoteAuthority ? labelService.getHostLabel(Schemas.vscodeRemote, remoteAuthority) : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected get location(): string | undefined {
|
||||||
|
return this._location;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected validateExtensionKind(manifest: IExtensionManifest, output: CLIOutput): boolean {
|
||||||
|
if (!canExecuteOnWorkspace(manifest, this.productService, this.configurationService)) {
|
||||||
|
output.log(localize('cannot be installed', "Cannot install '{0}' because this extension has defined that it cannot run on the remote server.", getExtensionId(manifest.publisher, manifest.name)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -93,9 +93,8 @@ import 'vs/workbench/services/outline/browser/outlineService';
|
||||||
|
|
||||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||||
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
|
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
|
||||||
import { ExtensionManagementCLIService } from 'vs/platform/extensionManagement/common/extensionManagementCLIService';
|
|
||||||
import { GlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService';
|
import { GlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService';
|
||||||
import { IExtensionGalleryService, IExtensionManagementCLIService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
import { IExtensionGalleryService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||||
import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService';
|
import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService';
|
||||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||||
import { IListService, ListService } from 'vs/platform/list/browser/listService';
|
import { IListService, ListService } from 'vs/platform/list/browser/listService';
|
||||||
|
@ -127,7 +126,6 @@ registerSingleton(IIgnoredExtensionsManagementService, IgnoredExtensionsManageme
|
||||||
registerSingleton(IGlobalExtensionEnablementService, GlobalExtensionEnablementService);
|
registerSingleton(IGlobalExtensionEnablementService, GlobalExtensionEnablementService);
|
||||||
registerSingleton(IExtensionsStorageSyncService, ExtensionsStorageSyncService);
|
registerSingleton(IExtensionsStorageSyncService, ExtensionsStorageSyncService);
|
||||||
registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true);
|
registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true);
|
||||||
registerSingleton(IExtensionManagementCLIService, ExtensionManagementCLIService);
|
|
||||||
registerSingleton(IContextViewService, ContextViewService, true);
|
registerSingleton(IContextViewService, ContextViewService, true);
|
||||||
registerSingleton(IListService, ListService, true);
|
registerSingleton(IListService, ListService, true);
|
||||||
registerSingleton(IEditorWorkerService, EditorWorkerServiceImpl);
|
registerSingleton(IEditorWorkerService, EditorWorkerServiceImpl);
|
||||||
|
|
Loading…
Reference in a new issue