From 4a053c9d6d797b6c92dd3329b01eac5e608ab186 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 20 Jun 2019 16:00:36 -0700 Subject: [PATCH] Extract server spanwer to own file --- .../src/tsServer/server.ts | 185 +---------------- .../src/tsServer/spanwer.ts | 195 ++++++++++++++++++ .../src/typescriptServiceClient.ts | 3 +- 3 files changed, 198 insertions(+), 185 deletions(-) create mode 100644 extensions/typescript-language-features/src/tsServer/spanwer.ts diff --git a/extensions/typescript-language-features/src/tsServer/server.ts b/extensions/typescript-language-features/src/tsServer/server.ts index 881e35b6ece..52534972f1b 100644 --- a/extensions/typescript-language-features/src/tsServer/server.ts +++ b/extensions/typescript-language-features/src/tsServer/server.ts @@ -3,180 +3,20 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as child_process from 'child_process'; import * as fs from 'fs'; -import * as path from 'path'; import * as stream from 'stream'; import * as vscode from 'vscode'; import * as Proto from '../protocol'; import { ServerResponse } from '../typescriptService'; -import API from '../utils/api'; -import { TsServerLogLevel, TypeScriptServiceConfiguration } from '../utils/configuration'; import { Disposable } from '../utils/dispose'; -import * as electron from '../utils/electron'; -import LogDirectoryProvider from '../utils/logDirectoryProvider'; -import Logger from '../utils/logger'; -import { TypeScriptPluginPathsProvider } from '../utils/pluginPathsProvider'; -import { PluginManager } from '../utils/plugins'; import TelemetryReporter from '../utils/telemetry'; import Tracer from '../utils/tracer'; -import { TypeScriptVersion, TypeScriptVersionProvider } from '../utils/versionProvider'; +import { TypeScriptVersion } from '../utils/versionProvider'; import { Reader } from '../utils/wireProtocol'; import { CallbackMap } from './callbackMap'; import { RequestItem, RequestQueue, RequestQueueingType } from './requestQueue'; import { TypeScriptServerError } from './serverError'; -export class TypeScriptServerSpawner { - public constructor( - private readonly _versionProvider: TypeScriptVersionProvider, - private readonly _logDirectoryProvider: LogDirectoryProvider, - private readonly _pluginPathsProvider: TypeScriptPluginPathsProvider, - private readonly _logger: Logger, - private readonly _telemetryReporter: TelemetryReporter, - private readonly _tracer: Tracer, - ) { } - - public spawn( - version: TypeScriptVersion, - configuration: TypeScriptServiceConfiguration, - pluginManager: PluginManager - ): ITypeScriptServer { - const apiVersion = version.version || API.defaultVersion; - - const { args, cancellationPipeName, tsServerLogFile } = this.getTsServerArgs(configuration, version, apiVersion, pluginManager); - - if (TypeScriptServerSpawner.isLoggingEnabled(apiVersion, configuration)) { - if (tsServerLogFile) { - this._logger.info(`TSServer log file: ${tsServerLogFile}`); - } else { - this._logger.error('Could not create TSServer log directory'); - } - } - - this._logger.info('Forking TSServer'); - const childProcess = electron.fork(version.tsServerPath, args, this.getForkOptions()); - this._logger.info('Started TSServer'); - - return new TypeScriptServer( - new ChildServerProcess(childProcess), - tsServerLogFile, - new PipeRequestCanceller(cancellationPipeName, this._tracer), - version, - this._telemetryReporter, - this._tracer); - } - - private getForkOptions() { - const debugPort = TypeScriptServerSpawner.getDebugPort(); - const tsServerForkOptions: electron.ForkOptions = { - execArgv: debugPort ? [`--inspect=${debugPort}`] : [], - }; - return tsServerForkOptions; - } - - private getTsServerArgs( - configuration: TypeScriptServiceConfiguration, - currentVersion: TypeScriptVersion, - apiVersion: API, - pluginManager: PluginManager, - ): { args: string[], cancellationPipeName: string | undefined, tsServerLogFile: string | undefined } { - const args: string[] = []; - let cancellationPipeName: string | undefined; - let tsServerLogFile: string | undefined; - - if (apiVersion.gte(API.v206)) { - if (apiVersion.gte(API.v250)) { - args.push('--useInferredProjectPerProjectRoot'); - } else { - args.push('--useSingleInferredProject'); - } - - if (configuration.disableAutomaticTypeAcquisition) { - args.push('--disableAutomaticTypingAcquisition'); - } - } - - if (apiVersion.gte(API.v208)) { - args.push('--enableTelemetry'); - } - - if (apiVersion.gte(API.v222)) { - cancellationPipeName = electron.getTempFile('tscancellation'); - args.push('--cancellationPipeName', cancellationPipeName + '*'); - } - - if (TypeScriptServerSpawner.isLoggingEnabled(apiVersion, configuration)) { - const logDir = this._logDirectoryProvider.getNewLogDirectory(); - if (logDir) { - tsServerLogFile = path.join(logDir, `tsserver.log`); - args.push('--logVerbosity', TsServerLogLevel.toString(configuration.tsServerLogLevel)); - args.push('--logFile', tsServerLogFile); - } - } - - if (apiVersion.gte(API.v230)) { - const pluginPaths = this._pluginPathsProvider.getPluginPaths(); - - if (pluginManager.plugins.length) { - args.push('--globalPlugins', pluginManager.plugins.map(x => x.name).join(',')); - - const isUsingBundledTypeScriptVersion = currentVersion.path === this._versionProvider.defaultVersion.path; - for (const plugin of pluginManager.plugins) { - if (isUsingBundledTypeScriptVersion || plugin.enableForWorkspaceTypeScriptVersions) { - pluginPaths.push(plugin.path); - } - } - } - - if (pluginPaths.length !== 0) { - args.push('--pluginProbeLocations', pluginPaths.join(',')); - } - } - - if (apiVersion.gte(API.v234)) { - if (configuration.npmLocation) { - args.push('--npmLocation', `"${configuration.npmLocation}"`); - } - } - - if (apiVersion.gte(API.v260)) { - args.push('--locale', TypeScriptServerSpawner.getTsLocale(configuration)); - } - - if (apiVersion.gte(API.v291)) { - args.push('--noGetErrOnBackgroundUpdate'); - } - - if (apiVersion.gte(API.v345)) { - args.push('--validateDefaultNpmLocation'); - } - - return { args, cancellationPipeName, tsServerLogFile }; - } - - private static getDebugPort(): number | undefined { - const value = process.env['TSS_DEBUG']; - if (value) { - const port = parseInt(value); - if (!isNaN(port)) { - return port; - } - } - return undefined; - } - - private static isLoggingEnabled(apiVersion: API, configuration: TypeScriptServiceConfiguration) { - return apiVersion.gte(API.v222) && - configuration.tsServerLogLevel !== TsServerLogLevel.Off; - } - - private static getTsLocale(configuration: TypeScriptServiceConfiguration): string { - return configuration.locale - ? configuration.locale - : vscode.env.language; - } -} - export interface OngoingRequestCanceller { tryCancelOngoingRequest(seq: number): boolean; } @@ -211,28 +51,6 @@ export interface ServerProcess { kill(): void; } -class ChildServerProcess implements ServerProcess { - - public constructor( - private readonly _process: child_process.ChildProcess, - ) { } - - get stdout(): stream.Readable { return this._process.stdout!; } - - write(serverRequest: Proto.Request): void { - this._process.stdin!.write(JSON.stringify(serverRequest) + '\r\n', 'utf8'); - } - - on(name: 'exit', handler: (code: number | null) => void): void; - on(name: 'error', handler: (error: Error) => void): void; - on(name: any, handler: any) { - this._process.on(name, handler); - } - - kill(): void { - this._process.kill(); - } -} export interface ITypeScriptServer { readonly onEvent: vscode.Event; @@ -476,4 +294,3 @@ function getQueueingType( } return lowPriority ? RequestQueueingType.LowPriority : RequestQueueingType.Normal; } - diff --git a/extensions/typescript-language-features/src/tsServer/spanwer.ts b/extensions/typescript-language-features/src/tsServer/spanwer.ts new file mode 100644 index 00000000000..be3cf5f4104 --- /dev/null +++ b/extensions/typescript-language-features/src/tsServer/spanwer.ts @@ -0,0 +1,195 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as child_process from 'child_process'; +import * as path from 'path'; +import * as stream from 'stream'; +import * as vscode from 'vscode'; +import * as Proto from '../protocol'; +import API from '../utils/api'; +import { TsServerLogLevel, TypeScriptServiceConfiguration } from '../utils/configuration'; +import * as electron from '../utils/electron'; +import LogDirectoryProvider from '../utils/logDirectoryProvider'; +import Logger from '../utils/logger'; +import { TypeScriptPluginPathsProvider } from '../utils/pluginPathsProvider'; +import { PluginManager } from '../utils/plugins'; +import TelemetryReporter from '../utils/telemetry'; +import Tracer from '../utils/tracer'; +import { TypeScriptVersion, TypeScriptVersionProvider } from '../utils/versionProvider'; +import { ITypeScriptServer, ServerProcess, TypeScriptServer, PipeRequestCanceller } from './server'; + +export class TypeScriptServerSpawner { + public constructor( + private readonly _versionProvider: TypeScriptVersionProvider, + private readonly _logDirectoryProvider: LogDirectoryProvider, + private readonly _pluginPathsProvider: TypeScriptPluginPathsProvider, + private readonly _logger: Logger, + private readonly _telemetryReporter: TelemetryReporter, + private readonly _tracer: Tracer, + ) { } + + public spawn( + version: TypeScriptVersion, + configuration: TypeScriptServiceConfiguration, + pluginManager: PluginManager + ): ITypeScriptServer { + const apiVersion = version.version || API.defaultVersion; + + const { args, cancellationPipeName, tsServerLogFile } = this.getTsServerArgs(configuration, version, apiVersion, pluginManager); + + if (TypeScriptServerSpawner.isLoggingEnabled(apiVersion, configuration)) { + if (tsServerLogFile) { + this._logger.info(`TSServer log file: ${tsServerLogFile}`); + } else { + this._logger.error('Could not create TSServer log directory'); + } + } + + this._logger.info('Forking TSServer'); + const childProcess = electron.fork(version.tsServerPath, args, this.getForkOptions()); + this._logger.info('Started TSServer'); + + return new TypeScriptServer( + new ChildServerProcess(childProcess), + tsServerLogFile, + new PipeRequestCanceller(cancellationPipeName, this._tracer), + version, + this._telemetryReporter, + this._tracer); + } + + private getForkOptions() { + const debugPort = TypeScriptServerSpawner.getDebugPort(); + const tsServerForkOptions: electron.ForkOptions = { + execArgv: debugPort ? [`--inspect=${debugPort}`] : [], + }; + return tsServerForkOptions; + } + + private getTsServerArgs( + configuration: TypeScriptServiceConfiguration, + currentVersion: TypeScriptVersion, + apiVersion: API, + pluginManager: PluginManager, + ): { args: string[], cancellationPipeName: string | undefined, tsServerLogFile: string | undefined } { + const args: string[] = []; + let cancellationPipeName: string | undefined; + let tsServerLogFile: string | undefined; + + if (apiVersion.gte(API.v206)) { + if (apiVersion.gte(API.v250)) { + args.push('--useInferredProjectPerProjectRoot'); + } else { + args.push('--useSingleInferredProject'); + } + + if (configuration.disableAutomaticTypeAcquisition) { + args.push('--disableAutomaticTypingAcquisition'); + } + } + + if (apiVersion.gte(API.v208)) { + args.push('--enableTelemetry'); + } + + if (apiVersion.gte(API.v222)) { + cancellationPipeName = electron.getTempFile('tscancellation'); + args.push('--cancellationPipeName', cancellationPipeName + '*'); + } + + if (TypeScriptServerSpawner.isLoggingEnabled(apiVersion, configuration)) { + const logDir = this._logDirectoryProvider.getNewLogDirectory(); + if (logDir) { + tsServerLogFile = path.join(logDir, `tsserver.log`); + args.push('--logVerbosity', TsServerLogLevel.toString(configuration.tsServerLogLevel)); + args.push('--logFile', tsServerLogFile); + } + } + + if (apiVersion.gte(API.v230)) { + const pluginPaths = this._pluginPathsProvider.getPluginPaths(); + + if (pluginManager.plugins.length) { + args.push('--globalPlugins', pluginManager.plugins.map(x => x.name).join(',')); + + const isUsingBundledTypeScriptVersion = currentVersion.path === this._versionProvider.defaultVersion.path; + for (const plugin of pluginManager.plugins) { + if (isUsingBundledTypeScriptVersion || plugin.enableForWorkspaceTypeScriptVersions) { + pluginPaths.push(plugin.path); + } + } + } + + if (pluginPaths.length !== 0) { + args.push('--pluginProbeLocations', pluginPaths.join(',')); + } + } + + if (apiVersion.gte(API.v234)) { + if (configuration.npmLocation) { + args.push('--npmLocation', `"${configuration.npmLocation}"`); + } + } + + if (apiVersion.gte(API.v260)) { + args.push('--locale', TypeScriptServerSpawner.getTsLocale(configuration)); + } + + if (apiVersion.gte(API.v291)) { + args.push('--noGetErrOnBackgroundUpdate'); + } + + if (apiVersion.gte(API.v345)) { + args.push('--validateDefaultNpmLocation'); + } + + return { args, cancellationPipeName, tsServerLogFile }; + } + + private static getDebugPort(): number | undefined { + const value = process.env['TSS_DEBUG']; + if (value) { + const port = parseInt(value); + if (!isNaN(port)) { + return port; + } + } + return undefined; + } + + private static isLoggingEnabled(apiVersion: API, configuration: TypeScriptServiceConfiguration) { + return apiVersion.gte(API.v222) && + configuration.tsServerLogLevel !== TsServerLogLevel.Off; + } + + private static getTsLocale(configuration: TypeScriptServiceConfiguration): string { + return configuration.locale + ? configuration.locale + : vscode.env.language; + } +} + +class ChildServerProcess implements ServerProcess { + + public constructor( + private readonly _process: child_process.ChildProcess, + ) { } + + get stdout(): stream.Readable { return this._process.stdout!; } + + write(serverRequest: Proto.Request): void { + this._process.stdin!.write(JSON.stringify(serverRequest) + '\r\n', 'utf8'); + } + + on(name: 'exit', handler: (code: number | null) => void): void; + on(name: 'error', handler: (error: Error) => void): void; + on(name: any, handler: any) { + this._process.on(name, handler); + } + + kill(): void { + this._process.kill(); + } +} \ No newline at end of file diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index 2849cfcd012..bccddbf16f9 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -10,7 +10,7 @@ import * as nls from 'vscode-nls'; import BufferSyncSupport from './features/bufferSyncSupport'; import { DiagnosticKind, DiagnosticsManager } from './features/diagnostics'; import * as Proto from './protocol'; -import { ITypeScriptServer, TypeScriptServerSpawner } from './tsServer/server'; +import { ITypeScriptServer } from './tsServer/server'; import { ITypeScriptServiceClient, ServerResponse } from './typescriptService'; import API from './utils/api'; import { TsServerLogLevel, TypeScriptServiceConfiguration } from './utils/configuration'; @@ -25,6 +25,7 @@ import Tracer from './utils/tracer'; import { inferredProjectConfig } from './utils/tsconfig'; import { TypeScriptVersionPicker } from './utils/versionPicker'; import { TypeScriptVersion, TypeScriptVersionProvider } from './utils/versionProvider'; +import { TypeScriptServerSpawner } from './tsServer/spanwer'; const localize = nls.loadMessageBundle(); -- GitLab