blob: 81685c3070a8f8a573c8ac7ee11cf08e41306691 [file] [log] [blame]
// Copyright (c) 2020, 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:convert';
import 'dart:io';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as p;
import 'package:shelf/shelf.dart';
import '../debugging/metadata/provider.dart';
import '../loaders/strategy.dart';
import '../readers/asset_reader.dart';
import '../services/expression_compiler.dart';
import 'require.dart';
/// Provides a [RequireStrategy] suitable for use with `package:build_runner`.
class BuildRunnerRequireStrategyProvider {
final _logger = Logger('BuildRunnerRequireStrategyProvider');
final Handler _assetHandler;
final ReloadConfiguration _configuration;
final AssetReader _assetReader;
late final RequireStrategy _requireStrategy = RequireStrategy(
_configuration,
_moduleProvider,
_digestsProvider,
_moduleForServerPath,
_serverPathForModule,
_sourceMapPathForModule,
_serverPathForAppUri,
_moduleInfoForProvider,
_assetReader,
);
BuildRunnerRequireStrategyProvider(
this._assetHandler, this._configuration, this._assetReader);
RequireStrategy get strategy => _requireStrategy;
Future<Map<String, String>> _digestsProvider(
MetadataProvider metadataProvider) async {
final modules = await metadataProvider.modulePathToModule;
final digestsPath = metadataProvider.entrypoint
.replaceAll('.dart.bootstrap.js', '.digests');
final response = await _assetHandler(
Request('GET', Uri.parse('http://foo:0000/$digestsPath')));
if (response.statusCode != HttpStatus.ok) {
throw StateError('Could not read digests at path: $digestsPath');
}
final body = await response.readAsString();
final digests = json.decode(body) as Map<String, dynamic>;
for (final key in digests.keys) {
if (!modules.containsKey(key)) {
_logger.warning('Digest key $key is not a module name.');
}
}
return {
for (var entry in digests.entries)
if (modules.containsKey(entry.key))
modules[entry.key]!: entry.value as String,
};
}
Future<Map<String, String>> _moduleProvider(
MetadataProvider metadataProvider) async =>
(await metadataProvider.moduleToModulePath).map((key, value) =>
MapEntry(key, stripTopLevelDirectory(removeJsExtension(value))));
Future<String?> _moduleForServerPath(
MetadataProvider metadataProvider, String serverPath) async {
final modulePathToModule = await metadataProvider.modulePathToModule;
final relativePath = stripLeadingSlashes(serverPath);
for (var e in modulePathToModule.entries) {
if (stripTopLevelDirectory(e.key) == relativePath) {
return e.value;
}
}
return null;
}
Future<String?> _serverPathForModule(
MetadataProvider metadataProvider, String module) async {
final modulePath = (await metadataProvider.moduleToModulePath)[module];
return modulePath == null ? null : stripTopLevelDirectory(modulePath);
}
Future<String?> _sourceMapPathForModule(
MetadataProvider metadataProvider, String module) async {
final sourceMapPath = (await metadataProvider.moduleToSourceMap)[module];
return sourceMapPath == null ? null : stripTopLevelDirectory(sourceMapPath);
}
String? _serverPathForAppUri(String appUrl) {
final appUri = Uri.parse(appUrl);
if (appUri.isScheme('org-dartlang-app')) {
// We skip the root from which we are serving.
return appUri.pathSegments.skip(1).join('/');
}
if (appUri.isScheme('package')) {
return '/packages/${appUri.path}';
}
return null;
}
Future<Map<String, ModuleInfo>> _moduleInfoForProvider(
MetadataProvider metadataProvider) async {
final modules = await metadataProvider.modules;
final result = <String, ModuleInfo>{};
for (var module in modules) {
final serverPath = await _serverPathForModule(metadataProvider, module);
if (serverPath == null) {
_logger.warning('No module info found for module $module');
} else {
result[module] = ModuleInfo(
// TODO: Save locations of full kernel files in ddc metadata.
// Issue: https://github.com/dart-lang/sdk/issues/43684
// TODO: Change these to URIs instead of paths when the SDK supports
// it.
p.setExtension(serverPath, '.full.dill'),
p.setExtension(serverPath, '.dill'));
}
}
return result;
}
}