blob: 983f081e3275f71a6e025e7fa1d1f63a74120e58 [file] [log] [blame]
// 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;
}