blob: dfea1f13801c5383609be35b20fd40bfe26865cd [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:package_config/package_config.dart';
import 'find_sdk_root.dart';
import 'suite.dart';
/// Writes a package config under [root] and returns the [Uri] pointing to it.
Future<Uri> writePackageConfig(
Module module, Set<Module> transitiveDependencies, Uri root,
{bool useRealPaths = false}) async {
const packageConfigJsonPath = ".dart_tool/package_config.json";
var sdkRoot = await findRoot();
Uri packageConfigUri = sdkRoot.resolve(packageConfigJsonPath);
var packageConfig = await loadPackageConfigUri(packageConfigUri);
// We create a package_config.json file to support the CFE in (a) determine
// the default nullability if the current module is a package, and (b)
// resolve `package:` imports. Technically the latter shouldn't be necessary,
// but the CFE requires that if a `package:` URI of a dependency is used in an
// import, then we need that package entry in the associated file. In fact,
// after it checks that the definition exists, the CFE will not actually use
// the resolved URI if a library for the import URI is already found in one of
// the provide .dill files of the dependencies. For that reason, and to ensure
// that a step only has access to the files provided in a module, we generate
// a config file with invalid folders for other packages.
// TODO(sigmund): follow up with the CFE to see if we can remove the need
// for these dummy entries.
var packagesJson = [];
if (module.isPackage) {
packagesJson.add(_packageConfigEntry(
module.name, Uri.parse('../${module.packageBase}')));
}
int unusedNum = 0;
for (Module dependency in transitiveDependencies) {
if (dependency.isPackage) {
// rootUri should be ignored for dependent modules, so we pass in a
// bogus value.
var rootUri =
useRealPaths ? dependency.rootUri : Uri.parse('unused${unusedNum++}');
var dependentPackage = packageConfig[dependency.name];
var packageJson = dependentPackage == null
? _packageConfigEntry(dependency.name, rootUri,
packageRoot: dependency.packageBase)
: _packageConfigEntry(dependentPackage.name, rootUri,
packageRoot: dependency.packageBase,
version: dependentPackage.languageVersion);
packagesJson.add(packageJson);
}
}
var packageConfigFile = File.fromUri(root.resolve(packageConfigJsonPath));
await packageConfigFile.create(recursive: true);
await packageConfigFile.writeAsString('{'
' "configVersion": ${packageConfig.version},'
' "packages": [ ${packagesJson.join(',')} ]'
'}');
return packageConfigFile.uri;
}
String _packageConfigEntry(String name, Uri root,
{Uri? packageRoot, LanguageVersion? version}) {
var fields = [
'"name": "$name"',
'"rootUri": "$root"',
if (packageRoot != null) '"packageUri": "$packageRoot"',
if (version != null) '"languageVersion": "$version"'
];
return '{${fields.join(',')}}';
}