mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-01 12:06:24 +01:00
151 lines
6.3 KiB
TypeScript
151 lines
6.3 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 * as performance from '../../../base/common/performance.js';
|
|
import { createApiFactoryAndRegisterActors } from '../common/extHost.api.impl.js';
|
|
import { RequireInterceptor } from '../common/extHostRequireInterceptor.js';
|
|
import { ExtensionActivationTimesBuilder } from '../common/extHostExtensionActivator.js';
|
|
import { connectProxyResolver } from './proxyResolver.js';
|
|
import { AbstractExtHostExtensionService } from '../common/extHostExtensionService.js';
|
|
import { ExtHostDownloadService } from './extHostDownloadService.js';
|
|
import { URI } from '../../../base/common/uri.js';
|
|
import { Schemas } from '../../../base/common/network.js';
|
|
import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
|
|
import { ExtensionRuntime } from '../common/extHostTypes.js';
|
|
import { CLIServer } from './extHostCLIServer.js';
|
|
import { realpathSync } from '../../../base/node/extpath.js';
|
|
import { ExtHostConsoleForwarder } from './extHostConsoleForwarder.js';
|
|
import { ExtHostDiskFileSystemProvider } from './extHostDiskFileSystemProvider.js';
|
|
import { createRequire } from 'node:module';
|
|
const require = createRequire(import.meta.url);
|
|
|
|
class NodeModuleRequireInterceptor extends RequireInterceptor {
|
|
|
|
protected _installInterceptor(): void {
|
|
const that = this;
|
|
const node_module = require('module');
|
|
const originalLoad = node_module._load;
|
|
node_module._load = function load(request: string, parent: { filename: string }, isMain: boolean) {
|
|
request = applyAlternatives(request);
|
|
if (!that._factories.has(request)) {
|
|
return originalLoad.apply(this, arguments);
|
|
}
|
|
return that._factories.get(request)!.load(
|
|
request,
|
|
URI.file(realpathSync(parent.filename)),
|
|
request => originalLoad.apply(this, [request, parent, isMain])
|
|
);
|
|
};
|
|
|
|
const originalLookup = node_module._resolveLookupPaths;
|
|
node_module._resolveLookupPaths = (request: string, parent: unknown) => {
|
|
return originalLookup.call(this, applyAlternatives(request), parent);
|
|
};
|
|
|
|
const originalResolveFilename = node_module._resolveFilename;
|
|
node_module._resolveFilename = function resolveFilename(request: string, parent: unknown, isMain: boolean, options?: { paths?: string[] }) {
|
|
if (request === 'vsda' && Array.isArray(options?.paths) && options.paths.length === 0) {
|
|
// ESM: ever since we moved to ESM, `require.main` will be `undefined` for extensions
|
|
// Some extensions have been using `require.resolve('vsda', { paths: require.main.paths })`
|
|
// to find the `vsda` module in our app root. To be backwards compatible with this pattern,
|
|
// we help by filling in the `paths` array with the node modules paths of the current module.
|
|
options.paths = node_module._nodeModulePaths(import.meta.dirname);
|
|
}
|
|
return originalResolveFilename.call(this, request, parent, isMain, options);
|
|
};
|
|
|
|
const applyAlternatives = (request: string) => {
|
|
for (const alternativeModuleName of that._alternatives) {
|
|
const alternative = alternativeModuleName(request);
|
|
if (alternative) {
|
|
request = alternative;
|
|
break;
|
|
}
|
|
}
|
|
return request;
|
|
};
|
|
}
|
|
}
|
|
|
|
export class ExtHostExtensionService extends AbstractExtHostExtensionService {
|
|
|
|
readonly extensionRuntime = ExtensionRuntime.Node;
|
|
|
|
protected async _beforeAlmostReadyToRunExtensions(): Promise<void> {
|
|
// make sure console.log calls make it to the render
|
|
this._instaService.createInstance(ExtHostConsoleForwarder);
|
|
|
|
// initialize API and register actors
|
|
const extensionApiFactory = this._instaService.invokeFunction(createApiFactoryAndRegisterActors);
|
|
|
|
// Register Download command
|
|
this._instaService.createInstance(ExtHostDownloadService);
|
|
|
|
// Register CLI Server for ipc
|
|
if (this._initData.remote.isRemote && this._initData.remote.authority) {
|
|
const cliServer = this._instaService.createInstance(CLIServer);
|
|
process.env['VSCODE_IPC_HOOK_CLI'] = cliServer.ipcHandlePath;
|
|
}
|
|
|
|
// Register local file system shortcut
|
|
this._instaService.createInstance(ExtHostDiskFileSystemProvider);
|
|
|
|
// Module loading tricks
|
|
const interceptor = this._instaService.createInstance(NodeModuleRequireInterceptor, extensionApiFactory, { mine: this._myRegistry, all: this._globalRegistry });
|
|
await interceptor.install();
|
|
performance.mark('code/extHost/didInitAPI');
|
|
|
|
// Do this when extension service exists, but extensions are not being activated yet.
|
|
const configProvider = await this._extHostConfiguration.getConfigProvider();
|
|
await connectProxyResolver(this._extHostWorkspace, configProvider, this, this._logService, this._mainThreadTelemetryProxy, this._initData, this._store);
|
|
performance.mark('code/extHost/didInitProxyResolver');
|
|
}
|
|
|
|
protected _getEntryPoint(extensionDescription: IExtensionDescription): string | undefined {
|
|
return extensionDescription.main;
|
|
}
|
|
|
|
protected async _loadCommonJSModule<T>(extension: IExtensionDescription | null, module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
|
|
if (module.scheme !== Schemas.file) {
|
|
throw new Error(`Cannot load URI: '${module}', must be of file-scheme`);
|
|
}
|
|
let r: T | null = null;
|
|
activationTimesBuilder.codeLoadingStart();
|
|
this._logService.trace(`ExtensionService#loadCommonJSModule ${module.toString(true)}`);
|
|
this._logService.flush();
|
|
const extensionId = extension?.identifier.value;
|
|
if (extension) {
|
|
await this._extHostLocalizationService.initializeLocalizedMessages(extension);
|
|
}
|
|
try {
|
|
if (extensionId) {
|
|
performance.mark(`code/extHost/willLoadExtensionCode/${extensionId}`);
|
|
}
|
|
r = <T>(require)(module.fsPath);
|
|
} finally {
|
|
if (extensionId) {
|
|
performance.mark(`code/extHost/didLoadExtensionCode/${extensionId}`);
|
|
}
|
|
activationTimesBuilder.codeLoadingStop();
|
|
}
|
|
return r;
|
|
}
|
|
|
|
public async $setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void> {
|
|
if (!this._initData.remote.isRemote) {
|
|
return;
|
|
}
|
|
|
|
for (const key in env) {
|
|
const value = env[key];
|
|
if (value === null) {
|
|
delete process.env[key];
|
|
} else {
|
|
process.env[key] = value;
|
|
}
|
|
}
|
|
}
|
|
}
|