blob: 7391ffae82c41e9989fbfb2190f1f7081641c596 [file]
// 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(',')}}';
}