vscode/src/vs/server/remoteExtensionHostAgentCli.ts
2021-10-20 18:42:13 +02:00

146 lines
7.1 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { getLogLevel, ILogService, LogService } from 'vs/platform/log/common/log';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ConfigurationService } from 'vs/platform/configuration/common/configurationService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IRequestService } from 'vs/platform/request/common/request';
import { RequestService } from 'vs/platform/request/node/requestService';
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IExtensionGalleryService, IExtensionManagementCLIService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionGalleryServiceWithNoStorageService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import product from 'vs/platform/product/common/product';
import { Disposable } from 'vs/base/common/lifecycle';
import { FileService } from 'vs/platform/files/common/fileService';
import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
import { Schemas } from 'vs/base/common/network';
import { IFileService } from 'vs/platform/files/common/files';
import { IProductService } from 'vs/platform/product/common/productService';
import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog';
import { RemoteExtensionLogFileName } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IServerEnvironmentService, ServerEnvironmentService, ServerParsedArgs } from 'vs/server/serverEnvironmentService';
import { ExtensionManagementCLIService } from 'vs/platform/extensionManagement/common/extensionManagementCLIService';
import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
import { LocalizationsService } from 'vs/platform/localizations/node/localizations';
import { getErrorMessage } from 'vs/base/common/errors';
import { URI } from 'vs/base/common/uri';
import { isAbsolute, join } from 'vs/base/common/path';
import { cwd } from 'vs/base/common/process';
import { DownloadService } from 'vs/platform/download/common/downloadService';
import { IDownloadService } from 'vs/platform/download/common/download';
class CliMain extends Disposable {
constructor(private readonly args: ServerParsedArgs, private readonly remoteDataFolder: string) {
super();
this.registerListeners();
}
private registerListeners(): void {
// Dispose on exit
process.once('exit', () => this.dispose());
}
async run(): Promise<void> {
const instantiationService = await this.initServices();
await instantiationService.invokeFunction(async accessor => {
const logService = accessor.get(ILogService);
const extensionManagementCLIService = accessor.get(IExtensionManagementCLIService);
try {
await this.doRun(extensionManagementCLIService);
} catch (error) {
logService.error(error);
console.error(getErrorMessage(error));
throw error;
}
});
}
private async initServices(): Promise<IInstantiationService> {
const services = new ServiceCollection();
const productService = { _serviceBrand: undefined, ...product };
services.set(IProductService, productService);
const environmentService = new ServerEnvironmentService(this.args, productService);
services.set(IServerEnvironmentService, environmentService);
const logService: ILogService = new LogService(new SpdLogLogger(RemoteExtensionLogFileName, join(environmentService.logsPath, `${RemoteExtensionLogFileName}.log`), true, getLogLevel(environmentService)));
services.set(ILogService, logService);
logService.trace(`Remote configuration data at ${this.remoteDataFolder}`);
logService.trace('process arguments:', this.args);
// Files
const fileService = this._register(new FileService(logService));
services.set(IFileService, fileService);
fileService.registerProvider(Schemas.file, this._register(new DiskFileSystemProvider(logService)));
// Configuration
const configurationService = this._register(new ConfigurationService(environmentService.settingsResource, fileService));
await configurationService.initialize();
services.set(IConfigurationService, configurationService);
services.set(IRequestService, new SyncDescriptor(RequestService));
services.set(IDownloadService, new SyncDescriptor(DownloadService));
services.set(ITelemetryService, NullTelemetryService);
services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryServiceWithNoStorageService));
services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
services.set(IExtensionManagementCLIService, new SyncDescriptor(ExtensionManagementCLIService));
services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService));
return new InstantiationService(services);
}
private async doRun(extensionManagementCLIService: IExtensionManagementCLIService): Promise<void> {
// List Extensions
if (this.args['list-extensions']) {
return extensionManagementCLIService.listExtensions(!!this.args['show-versions'], this.args['category']);
}
// Install Extension
else if (this.args['install-extension'] || this.args['install-builtin-extension']) {
return extensionManagementCLIService.installExtensions(this.asExtensionIdOrVSIX(this.args['install-extension'] || []), this.args['install-builtin-extension'] || [], !!this.args['do-not-sync'], !!this.args['force']);
}
// Uninstall Extension
else if (this.args['uninstall-extension']) {
return extensionManagementCLIService.uninstallExtensions(this.asExtensionIdOrVSIX(this.args['uninstall-extension']), !!this.args['force']);
}
// Locate Extension
else if (this.args['locate-extension']) {
return extensionManagementCLIService.locateExtension(this.args['locate-extension']);
}
}
private asExtensionIdOrVSIX(inputs: string[]): (string | URI)[] {
return inputs.map(input => /\.vsix$/i.test(input) ? URI.file(isAbsolute(input) ? input : join(cwd(), input)) : input);
}
}
function eventuallyExit(code: number): void {
setTimeout(() => process.exit(code), 0);
}
export async function run(args: ServerParsedArgs, REMOTE_DATA_FOLDER: string): Promise<void> {
const cliMain = new CliMain(args, REMOTE_DATA_FOLDER);
try {
await cliMain.run();
eventuallyExit(0);
} catch (err) {
eventuallyExit(1);
} finally {
cliMain.dispose();
}
}