Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/code/node/cliProcessMain.ts
5237 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { setDefaultResultOrder } from 'dns';
7
import * as fs from 'fs';
8
import { hostname, release } from 'os';
9
import { raceTimeout } from '../../base/common/async.js';
10
import { toErrorMessage } from '../../base/common/errorMessage.js';
11
import { isSigPipeError, onUnexpectedError, setUnexpectedErrorHandler } from '../../base/common/errors.js';
12
import { Disposable } from '../../base/common/lifecycle.js';
13
import { Schemas } from '../../base/common/network.js';
14
import { isAbsolute, join } from '../../base/common/path.js';
15
import { isWindows, isMacintosh, isLinux } from '../../base/common/platform.js';
16
import { cwd } from '../../base/common/process.js';
17
import { URI } from '../../base/common/uri.js';
18
import { IConfigurationService } from '../../platform/configuration/common/configuration.js';
19
import { ConfigurationService } from '../../platform/configuration/common/configurationService.js';
20
import { IDownloadService } from '../../platform/download/common/download.js';
21
import { DownloadService } from '../../platform/download/common/downloadService.js';
22
import { NativeParsedArgs } from '../../platform/environment/common/argv.js';
23
import { INativeEnvironmentService } from '../../platform/environment/common/environment.js';
24
import { NativeEnvironmentService } from '../../platform/environment/node/environmentService.js';
25
import { ExtensionGalleryServiceWithNoStorageService } from '../../platform/extensionManagement/common/extensionGalleryService.js';
26
import { IAllowedExtensionsService, IExtensionGalleryService, InstallOptions } from '../../platform/extensionManagement/common/extensionManagement.js';
27
import { ExtensionSignatureVerificationService, IExtensionSignatureVerificationService } from '../../platform/extensionManagement/node/extensionSignatureVerificationService.js';
28
import { ExtensionManagementCLI } from '../../platform/extensionManagement/common/extensionManagementCLI.js';
29
import { IExtensionsProfileScannerService } from '../../platform/extensionManagement/common/extensionsProfileScannerService.js';
30
import { IExtensionsScannerService } from '../../platform/extensionManagement/common/extensionsScannerService.js';
31
import { ExtensionManagementService, INativeServerExtensionManagementService } from '../../platform/extensionManagement/node/extensionManagementService.js';
32
import { ExtensionsScannerService } from '../../platform/extensionManagement/node/extensionsScannerService.js';
33
import { IFileService } from '../../platform/files/common/files.js';
34
import { FileService } from '../../platform/files/common/fileService.js';
35
import { DiskFileSystemProvider } from '../../platform/files/node/diskFileSystemProvider.js';
36
import { SyncDescriptor } from '../../platform/instantiation/common/descriptors.js';
37
import { IInstantiationService } from '../../platform/instantiation/common/instantiation.js';
38
import { InstantiationService } from '../../platform/instantiation/common/instantiationService.js';
39
import { ServiceCollection } from '../../platform/instantiation/common/serviceCollection.js';
40
import { ILanguagePackService } from '../../platform/languagePacks/common/languagePacks.js';
41
import { NativeLanguagePackService } from '../../platform/languagePacks/node/languagePacks.js';
42
import { ConsoleLogger, getLogLevel, ILogger, ILoggerService, ILogService, LogLevel } from '../../platform/log/common/log.js';
43
import { FilePolicyService } from '../../platform/policy/common/filePolicyService.js';
44
import { IPolicyService, NullPolicyService } from '../../platform/policy/common/policy.js';
45
import { NativePolicyService } from '../../platform/policy/node/nativePolicyService.js';
46
import product from '../../platform/product/common/product.js';
47
import { IProductService } from '../../platform/product/common/productService.js';
48
import { IRequestService } from '../../platform/request/common/request.js';
49
import { RequestService } from '../../platform/request/node/requestService.js';
50
import { SaveStrategy, StateReadonlyService } from '../../platform/state/node/stateService.js';
51
import { resolveCommonProperties } from '../../platform/telemetry/common/commonProperties.js';
52
import { ITelemetryService } from '../../platform/telemetry/common/telemetry.js';
53
import { ITelemetryServiceConfig, TelemetryService } from '../../platform/telemetry/common/telemetryService.js';
54
import { supportsTelemetry, NullTelemetryService, getPiiPathsFromEnvironment, isInternalTelemetry, ITelemetryAppender } from '../../platform/telemetry/common/telemetryUtils.js';
55
import { OneDataSystemAppender } from '../../platform/telemetry/node/1dsAppender.js';
56
import { buildTelemetryMessage } from '../../platform/telemetry/node/telemetry.js';
57
import { IUriIdentityService } from '../../platform/uriIdentity/common/uriIdentity.js';
58
import { UriIdentityService } from '../../platform/uriIdentity/common/uriIdentityService.js';
59
import { IUserDataProfile, IUserDataProfilesService } from '../../platform/userDataProfile/common/userDataProfile.js';
60
import { UserDataProfilesReadonlyService } from '../../platform/userDataProfile/node/userDataProfile.js';
61
import { resolveMachineId, resolveSqmId, resolveDevDeviceId } from '../../platform/telemetry/node/telemetryUtils.js';
62
import { ExtensionsProfileScannerService } from '../../platform/extensionManagement/node/extensionsProfileScannerService.js';
63
import { LogService } from '../../platform/log/common/logService.js';
64
import { LoggerService } from '../../platform/log/node/loggerService.js';
65
import { localize } from '../../nls.js';
66
import { FileUserDataProvider } from '../../platform/userData/common/fileUserDataProvider.js';
67
import { addUNCHostToAllowlist, getUNCHost } from '../../base/node/unc.js';
68
import { AllowedExtensionsService } from '../../platform/extensionManagement/common/allowedExtensionsService.js';
69
import { McpManagementCli } from '../../platform/mcp/common/mcpManagementCli.js';
70
import { IExtensionGalleryManifestService } from '../../platform/extensionManagement/common/extensionGalleryManifest.js';
71
import { ExtensionGalleryManifestService } from '../../platform/extensionManagement/common/extensionGalleryManifestService.js';
72
import { IAllowedMcpServersService, IMcpGalleryService, IMcpManagementService } from '../../platform/mcp/common/mcpManagement.js';
73
import { McpManagementService } from '../../platform/mcp/node/mcpManagementService.js';
74
import { IMcpResourceScannerService, McpResourceScannerService } from '../../platform/mcp/common/mcpResourceScannerService.js';
75
import { McpGalleryService } from '../../platform/mcp/common/mcpGalleryService.js';
76
import { AllowedMcpServersService } from '../../platform/mcp/common/allowedMcpServersService.js';
77
import { IMcpGalleryManifestService } from '../../platform/mcp/common/mcpGalleryManifest.js';
78
import { McpGalleryManifestService } from '../../platform/mcp/common/mcpGalleryManifestService.js';
79
import { LINUX_SYSTEM_POLICY_FILE_PATH } from '../../base/common/policy.js';
80
81
class CliMain extends Disposable {
82
83
constructor(
84
private argv: NativeParsedArgs
85
) {
86
super();
87
88
this.registerListeners();
89
}
90
91
private registerListeners(): void {
92
93
// Dispose on exit
94
process.once('exit', () => this.dispose());
95
}
96
97
async run(): Promise<void> {
98
99
// Services
100
const [instantiationService, appenders] = await this.initServices();
101
102
return instantiationService.invokeFunction(async accessor => {
103
const logService = accessor.get(ILogService);
104
const fileService = accessor.get(IFileService);
105
const environmentService = accessor.get(INativeEnvironmentService);
106
const userDataProfilesService = accessor.get(IUserDataProfilesService);
107
108
// Log info
109
logService.info('CLI main', this.argv);
110
111
// Error handler
112
this.registerErrorHandler(logService);
113
114
// DNS result order
115
// Refs https://github.com/microsoft/vscode/issues/264136
116
setDefaultResultOrder('ipv4first');
117
118
// Run based on argv
119
await this.doRun(environmentService, fileService, userDataProfilesService, instantiationService);
120
121
// Flush the remaining data in AI adapter (with 1s timeout)
122
await Promise.all(appenders.map(a => {
123
raceTimeout(a.flush(), 1000);
124
}));
125
return;
126
});
127
}
128
129
private async initServices(): Promise<[IInstantiationService, ITelemetryAppender[]]> {
130
const services = new ServiceCollection();
131
132
// Product
133
const productService = { _serviceBrand: undefined, ...product };
134
services.set(IProductService, productService);
135
136
// Environment
137
const environmentService = new NativeEnvironmentService(this.argv, productService);
138
services.set(INativeEnvironmentService, environmentService);
139
140
// Init folders
141
await Promise.all([
142
this.allowWindowsUNCPath(environmentService.appSettingsHome.with({ scheme: Schemas.file }).fsPath),
143
this.allowWindowsUNCPath(environmentService.extensionsPath)
144
].map(path => path ? fs.promises.mkdir(path, { recursive: true }) : undefined));
145
146
// Logger
147
const loggerService = new LoggerService(getLogLevel(environmentService), environmentService.logsHome);
148
services.set(ILoggerService, loggerService);
149
150
// Log
151
const logger = this._register(loggerService.createLogger('cli', { name: localize('cli', "CLI") }));
152
const otherLoggers: ILogger[] = [];
153
if (loggerService.getLogLevel() === LogLevel.Trace) {
154
otherLoggers.push(new ConsoleLogger(loggerService.getLogLevel()));
155
}
156
157
const logService = this._register(new LogService(logger, otherLoggers));
158
services.set(ILogService, logService);
159
160
// Files
161
const fileService = this._register(new FileService(logService));
162
services.set(IFileService, fileService);
163
164
const diskFileSystemProvider = this._register(new DiskFileSystemProvider(logService));
165
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
166
167
// Uri Identity
168
const uriIdentityService = new UriIdentityService(fileService);
169
services.set(IUriIdentityService, uriIdentityService);
170
171
// User Data Profiles
172
const stateService = new StateReadonlyService(SaveStrategy.DELAYED, environmentService, logService, fileService);
173
const userDataProfilesService = new UserDataProfilesReadonlyService(stateService, uriIdentityService, environmentService, fileService, logService);
174
services.set(IUserDataProfilesService, userDataProfilesService);
175
176
// Use FileUserDataProvider for user data to
177
// enable atomic read / write operations.
178
fileService.registerProvider(Schemas.vscodeUserData, new FileUserDataProvider(Schemas.file, diskFileSystemProvider, Schemas.vscodeUserData, userDataProfilesService, uriIdentityService, logService));
179
180
// Policy
181
let policyService: IPolicyService | undefined;
182
if (isWindows && productService.win32RegValueName) {
183
policyService = this._register(new NativePolicyService(logService, productService.win32RegValueName));
184
} else if (isMacintosh && productService.darwinBundleIdentifier) {
185
policyService = this._register(new NativePolicyService(logService, productService.darwinBundleIdentifier));
186
} else if (isLinux) {
187
policyService = this._register(new FilePolicyService(URI.file(LINUX_SYSTEM_POLICY_FILE_PATH), fileService, logService));
188
} else if (environmentService.policyFile) {
189
policyService = this._register(new FilePolicyService(environmentService.policyFile, fileService, logService));
190
} else {
191
policyService = new NullPolicyService();
192
}
193
services.set(IPolicyService, policyService);
194
195
// Configuration
196
const configurationService = this._register(new ConfigurationService(userDataProfilesService.defaultProfile.settingsResource, fileService, policyService, logService));
197
services.set(IConfigurationService, configurationService);
198
199
// Initialize
200
await Promise.all([
201
stateService.init(),
202
configurationService.initialize()
203
]);
204
205
// Get machine ID
206
let machineId: string | undefined = undefined;
207
try {
208
machineId = await resolveMachineId(stateService, logService);
209
} catch (error) {
210
if (error.code !== 'ENOENT') {
211
logService.error(error);
212
}
213
}
214
const sqmId = await resolveSqmId(stateService, logService);
215
const devDeviceId = await resolveDevDeviceId(stateService, logService);
216
217
// Initialize user data profiles after initializing the state
218
userDataProfilesService.init();
219
220
// URI Identity
221
services.set(IUriIdentityService, new UriIdentityService(fileService));
222
223
// Request
224
const requestService = new RequestService('local', configurationService, environmentService, logService);
225
services.set(IRequestService, requestService);
226
227
// Download Service
228
services.set(IDownloadService, new SyncDescriptor(DownloadService, undefined, true));
229
230
// Extensions
231
services.set(IExtensionsProfileScannerService, new SyncDescriptor(ExtensionsProfileScannerService, undefined, true));
232
services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService, undefined, true));
233
services.set(IExtensionSignatureVerificationService, new SyncDescriptor(ExtensionSignatureVerificationService, undefined, true));
234
services.set(IAllowedExtensionsService, new SyncDescriptor(AllowedExtensionsService, undefined, true));
235
services.set(INativeServerExtensionManagementService, new SyncDescriptor(ExtensionManagementService, undefined, true));
236
services.set(IExtensionGalleryManifestService, new SyncDescriptor(ExtensionGalleryManifestService));
237
services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryServiceWithNoStorageService, undefined, true));
238
239
// Localizations
240
services.set(ILanguagePackService, new SyncDescriptor(NativeLanguagePackService, undefined, false));
241
242
// MCP
243
services.set(IAllowedMcpServersService, new SyncDescriptor(AllowedMcpServersService, undefined, true));
244
services.set(IMcpResourceScannerService, new SyncDescriptor(McpResourceScannerService, undefined, true));
245
services.set(IMcpGalleryManifestService, new SyncDescriptor(McpGalleryManifestService, undefined, true));
246
services.set(IMcpGalleryService, new SyncDescriptor(McpGalleryService, undefined, true));
247
services.set(IMcpManagementService, new SyncDescriptor(McpManagementService, undefined, true));
248
249
// Telemetry
250
const appenders: ITelemetryAppender[] = [];
251
const isInternal = isInternalTelemetry(productService, configurationService);
252
if (supportsTelemetry(productService, environmentService)) {
253
if (productService.aiConfig?.ariaKey) {
254
appenders.push(new OneDataSystemAppender(requestService, isInternal, 'monacoworkbench', null, productService.aiConfig.ariaKey));
255
}
256
257
const config: ITelemetryServiceConfig = {
258
appenders,
259
sendErrorTelemetry: false,
260
commonProperties: resolveCommonProperties(release(), hostname(), process.arch, productService.commit, productService.version, machineId, sqmId, devDeviceId, isInternal, productService.date),
261
piiPaths: getPiiPathsFromEnvironment(environmentService)
262
};
263
264
services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config], false));
265
266
} else {
267
services.set(ITelemetryService, NullTelemetryService);
268
}
269
270
return [new InstantiationService(services), appenders];
271
}
272
273
private allowWindowsUNCPath(path: string): string {
274
if (isWindows) {
275
const host = getUNCHost(path);
276
if (host) {
277
addUNCHostToAllowlist(host);
278
}
279
}
280
281
return path;
282
}
283
284
private registerErrorHandler(logService: ILogService): void {
285
286
// Install handler for unexpected errors
287
setUnexpectedErrorHandler(error => {
288
const message = toErrorMessage(error, true);
289
if (!message) {
290
return;
291
}
292
293
logService.error(`[uncaught exception in CLI]: ${message}`);
294
});
295
296
// Handle unhandled errors that can occur
297
process.on('uncaughtException', err => {
298
if (!isSigPipeError(err)) {
299
onUnexpectedError(err);
300
}
301
});
302
process.on('unhandledRejection', (reason: unknown) => onUnexpectedError(reason));
303
}
304
305
private async doRun(environmentService: INativeEnvironmentService, fileService: IFileService, userDataProfilesService: IUserDataProfilesService, instantiationService: IInstantiationService): Promise<void> {
306
let profile: IUserDataProfile | undefined = undefined;
307
if (environmentService.args.profile) {
308
profile = userDataProfilesService.profiles.find(p => p.name === environmentService.args.profile);
309
if (!profile) {
310
throw new Error(`Profile '${environmentService.args.profile}' not found.`);
311
}
312
}
313
const profileLocation = (profile ?? userDataProfilesService.defaultProfile).extensionsResource;
314
315
// List Extensions
316
if (this.argv['list-extensions']) {
317
return instantiationService.createInstance(ExtensionManagementCLI, [], new ConsoleLogger(LogLevel.Info, false)).listExtensions(!!this.argv['show-versions'], this.argv['category'], profileLocation);
318
}
319
320
// Install Extension
321
else if (this.argv['install-extension'] || this.argv['install-builtin-extension']) {
322
const installOptions: InstallOptions = { isMachineScoped: !!this.argv['do-not-sync'], installPreReleaseVersion: !!this.argv['pre-release'], donotIncludePackAndDependencies: !!this.argv['do-not-include-pack-dependencies'], profileLocation };
323
return instantiationService.createInstance(ExtensionManagementCLI, [], new ConsoleLogger(LogLevel.Info, false)).installExtensions(this.asExtensionIdOrVSIX(this.argv['install-extension'] || []), this.asExtensionIdOrVSIX(this.argv['install-builtin-extension'] || []), installOptions, !!this.argv['force']);
324
}
325
326
// Uninstall Extension
327
else if (this.argv['uninstall-extension']) {
328
return instantiationService.createInstance(ExtensionManagementCLI, [], new ConsoleLogger(LogLevel.Info, false)).uninstallExtensions(this.asExtensionIdOrVSIX(this.argv['uninstall-extension']), !!this.argv['force'], profileLocation);
329
}
330
331
else if (this.argv['update-extensions']) {
332
return instantiationService.createInstance(ExtensionManagementCLI, [], new ConsoleLogger(LogLevel.Info, false)).updateExtensions(profileLocation);
333
}
334
335
// Locate Extension
336
else if (this.argv['locate-extension']) {
337
return instantiationService.createInstance(ExtensionManagementCLI, [], new ConsoleLogger(LogLevel.Info, false)).locateExtension(this.argv['locate-extension']);
338
}
339
340
// Install MCP server
341
else if (this.argv['add-mcp']) {
342
return instantiationService.createInstance(McpManagementCli, new ConsoleLogger(LogLevel.Info, false)).addMcpDefinitions(this.argv['add-mcp']);
343
}
344
345
// Telemetry
346
else if (this.argv['telemetry']) {
347
console.log(await buildTelemetryMessage(environmentService.appRoot, environmentService.extensionsPath));
348
}
349
}
350
351
private asExtensionIdOrVSIX(inputs: string[]): (string | URI)[] {
352
return inputs.map(input => /\.vsix$/i.test(input) ? URI.file(isAbsolute(input) ? input : join(cwd(), input)) : input);
353
}
354
}
355
356
export async function main(argv: NativeParsedArgs): Promise<void> {
357
const cliMain = new CliMain(argv);
358
359
try {
360
await cliMain.run();
361
} finally {
362
cliMain.dispose();
363
}
364
}
365
366