(logger: Logger, sdks: DartSdks)
| 551 | } |
| 552 | |
| 553 | private spawnServer(logger: Logger, sdks: DartSdks): Promise<StreamInfo> { |
| 554 | // TODO: Replace with constructing an Analyzer that passes LSP flag (but still reads config |
| 555 | // from paths etc) and provide it's process. |
| 556 | const vmPath = path.join(sdks.dart, dartVMPath); |
| 557 | const args = getAnalyzerArgs(logger); |
| 558 | |
| 559 | logger.info(`Spawning ${vmPath} with args ${JSON.stringify(args)}`); |
| 560 | const analysisServerStartTime = Date.now(); |
| 561 | const process = safeToolSpawn(undefined, vmPath, args); |
| 562 | // Ensure during dispose we terminate the process if it doesn't |
| 563 | // naturally exit in time. |
| 564 | this.disposables.push({ |
| 565 | dispose: () => this.handleDisposeCleanup(process) |
| 566 | }); |
| 567 | logger.info(` PID: ${process.pid}`); |
| 568 | |
| 569 | const reader = process.stdout.pipe(new LoggingTransform(logger, "<==")); |
| 570 | const writer = new LoggingTransform(logger, "==>"); |
| 571 | writer.pipe(process.stdin); |
| 572 | |
| 573 | process.stderr.on("data", (data) => { |
| 574 | const errorOutput = data.toString(); |
| 575 | |
| 576 | // Handle some well-known kinds of errors to help troubleshoot. |
| 577 | if (typeof errorOutput === "string") { |
| 578 | if (!hasShownAnalysisServerVersionMismatchError && config.analyzerPath && errorOutput.includes("analysis_server.dart") && errorOutput.includes("The specified language version is too high")) { |
| 579 | hasShownAnalysisServerVersionMismatchError = true; |
| 580 | void promptToReloadExtension(logger, { |
| 581 | prompt: "Running the analysis server from source failed because of a version mismatch. Is your Dart SDK an older version than this server version requires?", |
| 582 | offerLog: true, |
| 583 | severity: "ERROR", |
| 584 | restartReason: ExtensionRestartReason.AnalysisServerFromSourceMismatch |
| 585 | }); |
| 586 | } |
| 587 | } |
| 588 | |
| 589 | logger.error(errorOutput); |
| 590 | }); |
| 591 | |
| 592 | const processName = "Analysis server"; |
| 593 | process.on("close", (code, signal) => logger.info(`${processName} closed (${code}, ${signal})`)); |
| 594 | process.on("exit", (code, signal) => { |
| 595 | logger.info(`${processName} exited (${code}, ${signal})`); |
| 596 | |
| 597 | if (code) |
| 598 | reportAnalyzerTerminatedWithError(logger); |
| 599 | |
| 600 | if (!config.analyzerPath) { // Don't report for devs running from source. |
| 601 | const durationMs = Date.now() - analysisServerStartTime; |
| 602 | this.analytics.logAnalysisServerTerminate(code ?? 0, durationMs); |
| 603 | } |
| 604 | }); |
| 605 | |
| 606 | return Promise.resolve({ reader, writer }); |
| 607 | } |
| 608 | |
| 609 | /** |
| 610 | * Handle a call to dispose by waiting for the process to exit, or |
no test coverage detected