blob: eb650187e16ab127b9dd0e30b9b6e7bbca0f797d [file] [log] [blame]
// Copyright (c) 2022, 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 'package:file/file.dart';
import 'package:file/local.dart';
import 'package:path/path.dart' as p;
class InvalidSdkConfigurationException implements Exception {
final String? message;
InvalidSdkConfigurationException([this.message]);
@override
String toString() {
final message = this.message;
if (message == null) return 'Invalid SDK configuration';
return 'Invalid SDK configuration: $message';
}
}
/// SDK configuration provider interface.
///
/// Supports lazily populated configurations by allowing to create
/// configuration asyncronously.
abstract class SdkConfigurationProvider {
Future<SdkConfiguration> get configuration;
}
/// Data class describing the SDK layout.
///
/// Provides helpers to convert paths to uris that work on all platforms.
///
/// Call [validate] method to make sure the files in the configuration
/// layout exist before reading the files.
class SdkConfiguration {
// TODO(annagrin): update the tests to take those parameters
// and make all of the paths required (except for the compilerWorkerPath
// that is not used in Flutter).
String? sdkDirectory;
String? unsoundSdkSummaryPath;
String? soundSdkSummaryPath;
String? librariesPath;
String? compilerWorkerPath;
SdkConfiguration({
this.sdkDirectory,
this.unsoundSdkSummaryPath,
this.soundSdkSummaryPath,
this.librariesPath,
this.compilerWorkerPath,
});
static Uri? _toUri(String? path) => path == null ? null : p.toUri(path);
static Uri? _toAbsoluteUri(String? path) =>
path == null ? null : p.toUri(p.absolute(path));
Uri? get sdkDirectoryUri => _toUri(sdkDirectory);
Uri? get soundSdkSummaryUri => _toUri(soundSdkSummaryPath);
Uri? get unsoundSdkSummaryUri => _toUri(unsoundSdkSummaryPath);
Uri? get librariesUri => _toUri(librariesPath);
/// Note: has to be ///file: Uri to run in an isolate.
Uri? get compilerWorkerUri => _toAbsoluteUri(compilerWorkerPath);
/// Throws [InvalidSdkConfigurationException] if configuration does not
/// exist on disk.
void validate({FileSystem fileSystem = const LocalFileSystem()}) {
validateSdkDir(fileSystem: fileSystem);
validateSummaries(fileSystem: fileSystem);
validateLibrariesSpec(fileSystem: fileSystem);
validateCompilerWorker(fileSystem: fileSystem);
}
/// Throws [InvalidSdkConfigurationException] if SDK root does not
/// exist on the disk.
void validateSdkDir({FileSystem fileSystem = const LocalFileSystem()}) {
if (sdkDirectory == null ||
!fileSystem.directory(sdkDirectory).existsSync()) {
throw InvalidSdkConfigurationException(
'Sdk directory $sdkDirectory does not exist');
}
}
void validateSummaries({FileSystem fileSystem = const LocalFileSystem()}) {
if (unsoundSdkSummaryPath == null ||
!fileSystem.file(unsoundSdkSummaryPath).existsSync()) {
throw InvalidSdkConfigurationException(
'Sdk summary $unsoundSdkSummaryPath does not exist');
}
if (soundSdkSummaryPath == null ||
!fileSystem.file(soundSdkSummaryPath).existsSync()) {
throw InvalidSdkConfigurationException(
'Sdk summary $soundSdkSummaryPath does not exist');
}
}
void validateLibrariesSpec(
{FileSystem fileSystem = const LocalFileSystem()}) {
if (librariesPath == null || !fileSystem.file(librariesPath).existsSync()) {
throw InvalidSdkConfigurationException(
'Libraries spec $librariesPath does not exist');
}
}
void validateCompilerWorker(
{FileSystem fileSystem = const LocalFileSystem()}) {
if (compilerWorkerPath == null ||
!fileSystem.file(compilerWorkerPath).existsSync()) {
throw InvalidSdkConfigurationException(
'Compiler worker $compilerWorkerPath does not exist');
}
}
}
/// Implementation for the default SDK configuration layout.
class DefaultSdkConfigurationProvider extends SdkConfigurationProvider {
DefaultSdkConfigurationProvider();
late SdkConfiguration _configuration = _create();
/// Create and validate configuration matching the default SDK layout.
@override
Future<SdkConfiguration> get configuration async => _configuration;
SdkConfiguration _create() {
final binDir = p.dirname(Platform.resolvedExecutable);
final sdkDir = p.dirname(binDir);
return SdkConfiguration(
sdkDirectory: sdkDir,
unsoundSdkSummaryPath: p.join(sdkDir, 'lib', '_internal', 'ddc_sdk.dill'),
soundSdkSummaryPath:
p.join(sdkDir, 'lib', '_internal', 'ddc_outline_sound.dill'),
librariesPath: p.join(sdkDir, 'lib', 'libraries.json'),
compilerWorkerPath: p.join(binDir, 'snapshots', 'dartdevc.dart.snapshot'),
);
}
}