2022-03-01 18:20:29 +00:00
|
|
|
#!/usr/bin/env dart
|
2020-02-27 17:52:23 +00:00
|
|
|
|
|
|
|
/// Generates the repo's ".dart_tool/package_config.json" file.
|
|
|
|
import 'dart:convert';
|
|
|
|
import 'dart:io';
|
|
|
|
|
2022-03-01 18:20:29 +00:00
|
|
|
import 'package:args/args.dart';
|
|
|
|
import 'package:path/path.dart' as p;
|
|
|
|
import 'package:pub_semver/pub_semver.dart';
|
|
|
|
import 'package:yaml/yaml.dart';
|
2020-02-27 17:52:23 +00:00
|
|
|
|
2022-03-01 18:20:29 +00:00
|
|
|
bool _parseOptions(List<String> args) {
|
|
|
|
const usage = "Usage: dart generate_package_config.dart [flags...]";
|
|
|
|
|
|
|
|
var parser = ArgParser();
|
|
|
|
|
|
|
|
parser.addFlag("help", abbr: "h");
|
|
|
|
|
|
|
|
parser.addFlag("check",
|
|
|
|
abbr: "c",
|
|
|
|
help: "Return with a non-zero exit code if not up-to-date",
|
|
|
|
negatable: false);
|
|
|
|
|
|
|
|
var results = parser.parse(args);
|
|
|
|
|
|
|
|
if (results["help"] as bool) {
|
|
|
|
print("Regenerate the .dart_tool/package_config.json file.");
|
|
|
|
print("");
|
|
|
|
print(usage);
|
|
|
|
print("");
|
|
|
|
print(parser.usage);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return results["check"] as bool;
|
|
|
|
}
|
|
|
|
|
|
|
|
final repoRoot = p.dirname(p.dirname(p.fromUri(Platform.script)));
|
|
|
|
final configFilePath = p.join(repoRoot, '.dart_tool/package_config.json');
|
2020-02-27 17:52:23 +00:00
|
|
|
|
|
|
|
void main(List<String> args) {
|
2022-03-01 18:20:29 +00:00
|
|
|
bool checkOnly = _parseOptions(args);
|
|
|
|
|
2020-02-27 17:52:23 +00:00
|
|
|
var packageDirs = [
|
2022-03-01 18:20:29 +00:00
|
|
|
...listSubdirectories('pkg'),
|
|
|
|
...listSubdirectories('third_party/pkg'),
|
|
|
|
...listSubdirectories('third_party/pkg_tested'),
|
|
|
|
...listSubdirectories('third_party/pkg/file/packages'),
|
|
|
|
...listSubdirectories('third_party/pkg/test/pkgs'),
|
|
|
|
packageDirectory('runtime/observatory'),
|
|
|
|
packageDirectory(
|
|
|
|
'runtime/observatory/tests/service/observatory_test_package'),
|
|
|
|
packageDirectory('runtime/observatory_2'),
|
|
|
|
packageDirectory(
|
2020-10-09 20:02:57 +00:00
|
|
|
'runtime/observatory_2/tests/service_2/observatory_test_package_2'),
|
2022-03-01 18:20:29 +00:00
|
|
|
packageDirectory('pkg/vm_service/test/test_package'),
|
|
|
|
packageDirectory('sdk/lib/_internal/sdk_library_metadata'),
|
|
|
|
packageDirectory('third_party/devtools/devtools_shared'),
|
|
|
|
packageDirectory('third_party/pkg/protobuf/protobuf'),
|
|
|
|
packageDirectory('third_party/pkg/webdev/frontend_server_client'),
|
|
|
|
packageDirectory('tools/package_deps'),
|
2020-02-27 17:52:23 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
var cfePackageDirs = [
|
2022-03-01 18:20:29 +00:00
|
|
|
packageDirectory('pkg/front_end/testcases/'),
|
2020-02-27 17:52:23 +00:00
|
|
|
];
|
|
|
|
|
2020-08-10 08:03:29 +00:00
|
|
|
var feAnalyzerSharedPackageDirs = [
|
2022-03-01 18:20:29 +00:00
|
|
|
packageDirectory(
|
|
|
|
'pkg/_fe_analyzer_shared/test/flow_analysis/assigned_variables/'),
|
|
|
|
packageDirectory(
|
|
|
|
'pkg/_fe_analyzer_shared/test/flow_analysis/definite_assignment/'),
|
|
|
|
packageDirectory(
|
|
|
|
'pkg/_fe_analyzer_shared/test/flow_analysis/definite_unassignment/'),
|
|
|
|
packageDirectory('pkg/_fe_analyzer_shared/test/flow_analysis/nullability/'),
|
|
|
|
packageDirectory(
|
|
|
|
'pkg/_fe_analyzer_shared/test/flow_analysis/reachability/'),
|
|
|
|
packageDirectory(
|
|
|
|
'pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/'),
|
|
|
|
packageDirectory(
|
|
|
|
'pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted//'),
|
|
|
|
packageDirectory('pkg/_fe_analyzer_shared/test/inheritance/'),
|
2020-08-10 08:03:29 +00:00
|
|
|
];
|
|
|
|
|
2022-03-01 18:20:29 +00:00
|
|
|
var packages = [
|
2020-02-27 17:52:23 +00:00
|
|
|
...makePackageConfigs(packageDirs),
|
2020-08-10 08:03:29 +00:00
|
|
|
...makeCfePackageConfigs(cfePackageDirs),
|
|
|
|
...makeFeAnalyzerSharedPackageConfigs(feAnalyzerSharedPackageDirs)
|
2020-02-27 17:52:23 +00:00
|
|
|
];
|
2022-03-01 18:20:29 +00:00
|
|
|
packages.sort((a, b) => a['name']!.compareTo(b['name']!));
|
|
|
|
|
|
|
|
var configFile = File(p.join(repoRoot, '.dart_tool', 'package_config.json'));
|
|
|
|
var json = jsonDecode(configFile.readAsStringSync()) as Map<dynamic, dynamic>;
|
|
|
|
var oldPackages = json['packages'] as List<dynamic>;
|
|
|
|
|
|
|
|
if (checkOnly) {
|
|
|
|
// Validate the packages entry only, to avoid spurious failures from changes
|
|
|
|
// in the dates embedded in the other entries.
|
|
|
|
if (jsonEncode(packages) == jsonEncode(oldPackages)) {
|
|
|
|
print("Package config up to date.");
|
|
|
|
exit(0);
|
|
|
|
} else {
|
|
|
|
print("Package config out of date.");
|
|
|
|
print("Run `gclient sync -D && dart tools/generate_package_config.dart` "
|
|
|
|
"to update.");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var year = DateTime.now().year;
|
|
|
|
var config = <String, dynamic>{
|
|
|
|
'copyright': [
|
|
|
|
'Copyright (c) $year, 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.'
|
|
|
|
],
|
|
|
|
'comment': [
|
|
|
|
'Package configuration for all packages in /pkg, and checked out by DEPS',
|
|
|
|
'into /third_party/pkg and /third_party/pkg_tested.',
|
|
|
|
'If you add a package to DEPS or /pkg or change a package\'s SDK',
|
|
|
|
'constraint, update this by running tools/generate_package_config.dart.'
|
|
|
|
],
|
|
|
|
'configVersion': 2,
|
|
|
|
'generator': 'tools/generate_package_config.dart',
|
|
|
|
'packages': packages,
|
|
|
|
};
|
|
|
|
|
|
|
|
// TODO(rnystrom): Consider using package_config_v2 to generate this instead.
|
|
|
|
var jsonString = JsonEncoder.withIndent(' ').convert(config);
|
|
|
|
configFile.writeAsStringSync('$jsonString\n');
|
|
|
|
|
|
|
|
// Also generate the reop's .packages file.
|
|
|
|
var packagesFile = File(p.join(repoRoot, '.packages'));
|
2022-02-21 19:18:31 +00:00
|
|
|
var buffer = StringBuffer('''
|
|
|
|
# Copyright (c) 2016, 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.
|
|
|
|
#
|
|
|
|
# This file is generated; do not edit. To re-generate, run:
|
|
|
|
# 'dart tools/generate_package_config.dart'.
|
|
|
|
|
|
|
|
''');
|
|
|
|
for (var package in packages) {
|
2022-03-01 18:20:29 +00:00
|
|
|
final name = package['name'];
|
|
|
|
var path = package['rootUri']!;
|
|
|
|
if (path.startsWith('../')) {
|
|
|
|
path = path.substring('../'.length);
|
|
|
|
}
|
|
|
|
var packageUri = package['packageUri'];
|
|
|
|
if (packageUri != null && packageUri.endsWith('/')) {
|
|
|
|
packageUri = packageUri.substring(0, packageUri.length - 1);
|
|
|
|
}
|
2022-02-21 19:18:31 +00:00
|
|
|
if (packageUri != null && packageUri != '.nonexisting') {
|
2022-03-01 18:20:29 +00:00
|
|
|
buffer.writeln('$name:$path/$packageUri');
|
2022-02-21 19:18:31 +00:00
|
|
|
}
|
|
|
|
}
|
2022-03-01 18:20:29 +00:00
|
|
|
packagesFile.writeAsStringSync(buffer.toString());
|
2020-02-27 17:52:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Generates package configurations for each package in [packageDirs].
|
2022-03-01 18:20:29 +00:00
|
|
|
Iterable<Map<String, String>> makePackageConfigs(
|
|
|
|
List<String> packageDirs) sync* {
|
2020-02-27 17:52:23 +00:00
|
|
|
for (var packageDir in packageDirs) {
|
|
|
|
var version = pubspecLanguageVersion(packageDir);
|
2022-03-01 18:20:29 +00:00
|
|
|
var hasLibDirectory = Directory(p.join(packageDir, 'lib')).existsSync();
|
|
|
|
|
|
|
|
yield {
|
|
|
|
'name': p.basename(packageDir),
|
|
|
|
'rootUri': p
|
|
|
|
.toUri(p.relative(packageDir, from: p.dirname(configFilePath)))
|
|
|
|
.toString(),
|
|
|
|
if (hasLibDirectory) 'packageUri': 'lib/',
|
|
|
|
'languageVersion': '${version.major}.${version.minor}'
|
|
|
|
};
|
2020-02-27 17:52:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-01 18:20:29 +00:00
|
|
|
/// Generates package configurations for the special pseudo-packages used by
|
|
|
|
/// the CFE unit tests (`pkg/front_end/test/unit_test_suites.dart`).
|
|
|
|
Iterable<Map<String, String>> makeCfePackageConfigs(
|
|
|
|
List<String> packageDirs) sync* {
|
2020-02-27 17:52:23 +00:00
|
|
|
for (var packageDir in packageDirs) {
|
2022-03-01 18:20:29 +00:00
|
|
|
yield {
|
|
|
|
'name': 'front_end_${p.basename(packageDir)}',
|
|
|
|
'rootUri': p
|
|
|
|
.toUri(p.relative(packageDir, from: p.dirname(configFilePath)))
|
|
|
|
.toString(),
|
|
|
|
'packageUri': '.nonexisting/',
|
|
|
|
};
|
2020-02-27 17:52:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-01 18:20:29 +00:00
|
|
|
/// Generates package configurations for the special pseudo-packages used by
|
|
|
|
/// the _fe_analyzer_shared id tests.
|
|
|
|
Iterable<Map<String, String>> makeFeAnalyzerSharedPackageConfigs(
|
2020-08-10 08:03:29 +00:00
|
|
|
List<String> packageDirs) sync* {
|
|
|
|
for (var packageDir in packageDirs) {
|
2022-03-01 18:20:29 +00:00
|
|
|
yield {
|
|
|
|
'name': '_fe_analyzer_shared_${p.basename(packageDir)}',
|
|
|
|
'rootUri': p
|
|
|
|
.toUri(p.relative(packageDir, from: p.dirname(configFilePath)))
|
|
|
|
.toString(),
|
|
|
|
'packageUri': '.nonexisting/',
|
|
|
|
};
|
2020-08-10 08:03:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-01 18:20:29 +00:00
|
|
|
/// Generates a path to [relativePath] within the repo.
|
|
|
|
String packageDirectory(String relativePath) => p.join(repoRoot, relativePath);
|
|
|
|
|
|
|
|
/// Finds the paths of the immediate subdirectories of [packagesDir] that
|
2020-02-27 17:52:23 +00:00
|
|
|
/// contain pubspecs.
|
2022-03-01 18:20:29 +00:00
|
|
|
Iterable<String> listSubdirectories(String packagesDir) sync* {
|
|
|
|
for (var entry in Directory(p.join(repoRoot, packagesDir)).listSync()) {
|
2020-02-27 17:52:23 +00:00
|
|
|
if (entry is! Directory) continue;
|
2022-03-01 18:20:29 +00:00
|
|
|
if (!File(p.join(entry.path, 'pubspec.yaml')).existsSync()) continue;
|
|
|
|
yield entry.path;
|
2020-02-27 17:52:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Infers the language version from the SDK constraint in the pubspec for
|
|
|
|
/// [packageDir].
|
2022-03-01 18:20:29 +00:00
|
|
|
Version pubspecLanguageVersion(String packageDir) {
|
|
|
|
final dartVersion2 = Version.parse('2.0.0');
|
|
|
|
|
|
|
|
var pubspecFile = File(p.join(packageDir, 'pubspec.yaml'));
|
|
|
|
var relative = p.relative(packageDir, from: repoRoot);
|
2020-02-27 17:52:23 +00:00
|
|
|
|
2020-11-17 00:11:00 +00:00
|
|
|
if (!pubspecFile.existsSync()) {
|
2022-03-01 18:20:29 +00:00
|
|
|
print("Error: Missing pubspec for $relative.");
|
2020-11-17 00:11:00 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
2020-02-27 17:52:23 +00:00
|
|
|
|
2022-03-01 18:20:29 +00:00
|
|
|
var pubspec =
|
|
|
|
loadYaml(pubspecFile.readAsStringSync()) as Map<dynamic, dynamic>;
|
|
|
|
if (!pubspec.containsKey('environment')) {
|
|
|
|
print("Error: Pubspec for $relative has no SDK constraint.");
|
2020-11-17 00:11:00 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
2020-02-27 17:52:23 +00:00
|
|
|
|
2022-03-01 18:20:29 +00:00
|
|
|
var environment = pubspec['environment'] as Map<dynamic, dynamic>;
|
|
|
|
if (!environment.containsKey('sdk')) {
|
|
|
|
print("Error: Pubspec for $relative has no SDK constraint.");
|
2020-11-17 00:11:00 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
2020-02-27 17:52:23 +00:00
|
|
|
|
2022-03-01 18:20:29 +00:00
|
|
|
var sdkConstraint = VersionConstraint.parse(environment['sdk'] as String);
|
|
|
|
if (sdkConstraint is VersionRange) {
|
|
|
|
return sdkConstraint.min ?? dartVersion2;
|
2022-02-21 19:18:31 +00:00
|
|
|
}
|
2020-02-27 17:52:23 +00:00
|
|
|
|
2022-03-01 18:20:29 +00:00
|
|
|
print("Error: SDK constraint $relative is not a version range.");
|
|
|
|
exit(1);
|
2020-02-27 17:52:23 +00:00
|
|
|
}
|