| // Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| import 'dart:io'; | |
| import 'dart:isolate'; | |
| import 'package:path/path.dart' as path; | |
| /// The compiled version of the analysis server snapshot that should be used | |
| /// for integration tests. Set by [getAnalysisServerPath]. | |
| String? _compiledServerPath; | |
| /// The path of the `pkg/analysis_server` folder, resolved using the active | |
| /// `package_config.json`. | |
| String get analysisServerPackagePath { | |
| // Locate the root of the analysis server package without using | |
| // `Platform.script` as it fails when run through the `dart test`. | |
| // https://github.com/dart-lang/test/issues/110 | |
| var serverLibUri = Isolate.resolvePackageUriSync( | |
| Uri.parse('package:analysis_server/'), | |
| ); | |
| return path.normalize(path.join(serverLibUri!.toFilePath(), '..')); | |
| } | |
| /// The path of the `package_config.json` file in the root of the SDK, | |
| /// computed by resolving the path to `pkg:analysis_server`. | |
| String get sdkPackageConfigPath { | |
| return path.normalize( | |
| path.join(sdkRootPath, '.dart_tool', 'package_config.json'), | |
| ); | |
| } | |
| /// The path the SDK, computed as the parent of the `pkg/analysis_server` | |
| /// folder, resolved using the active `package_config.json`. | |
| String get sdkRootPath { | |
| return path.normalize(path.join(analysisServerPackagePath, '..', '..')); | |
| } | |
| /// Gets the path of the analysis server entry point which may be the snapshot | |
| /// from the current SDK (default) or a compiled version of the source script | |
| /// depending on the `TEST_SERVER_SNAPSHOT` environment variable. | |
| Future<String> getAnalysisServerPath(String dartSdkPath) async { | |
| // If we have already computed the path once, use that. | |
| if (_compiledServerPath case var compiledServerPath?) { | |
| return compiledServerPath; | |
| } | |
| // The 'TEST_SERVER_SNAPSHOT' env variable can either be: | |
| // | |
| // - Unset, in which case the tests run from the SDK compiled snapshot | |
| // - The string 'false' which will cause the server to compiled from source. | |
| // This is a simple way to run from source using the test_all file that | |
| // runs all tests in a single isolate and will trigger a single | |
| // compilation for all integration tests. | |
| // - A path to a pre-compiled snapshot. | |
| // This allows configuring VS Code to pre-compile the snapshot once and | |
| // then use 'dart test' which will run each sweet in a separate isolate | |
| // without each test/isolate having to compile. | |
| var snapshotPath = switch (Platform.environment['TEST_SERVER_SNAPSHOT']) { | |
| // Compile on the fly | |
| 'false' => await _compileTemporaryServerSnapshot(), | |
| // Default, use the SDK-bundled snapshot | |
| 'true' || '' || null => path.join( | |
| dartSdkPath, | |
| 'bin', | |
| 'snapshots', | |
| 'analysis_server.dart.snapshot', | |
| ), | |
| // Custom path in the env variable | |
| String snapshotPath => snapshotPath, | |
| }; | |
| return _compiledServerPath = path.normalize(snapshotPath); | |
| } | |
| /// Compiles a temporary snapshot for the analysis server into a temporary file | |
| /// and returns the full path. | |
| /// | |
| /// This function can only be called once in a single process/isolate. | |
| Future<String> _compileTemporaryServerSnapshot() async { | |
| if (_compiledServerPath != null) { | |
| throw 'Snapshot is already compiled or being compiled'; | |
| } | |
| var dartBinary = Platform.resolvedExecutable; | |
| var tempSnapshotDirectory = Directory.systemTemp.createTempSync( | |
| 'analysisServer_test_integration_compiledServer', | |
| ); | |
| var tempSnapshotFilePath = path.join( | |
| tempSnapshotDirectory.path, | |
| 'analysis_server.dart.snapshot', | |
| ); | |
| var sourcePath = path.join(analysisServerPackagePath, 'bin', 'server.dart'); | |
| var result = await Process.run(dartBinary, [ | |
| 'compile', | |
| 'kernel', | |
| sourcePath, | |
| '-o', | |
| tempSnapshotFilePath, | |
| ]); | |
| if (result.exitCode != 0) { | |
| throw 'Failed to compile analysis server:\n' | |
| 'Exit code: ${result.exitCode}\n' | |
| 'stdout: ${result.stdout}\n' | |
| 'stderr: ${result.stderr}\n'; | |
| } | |
| return tempSnapshotFilePath; | |
| } |