321dfea36a
Change the following code paths so that they format Dart code by running `tools/sdks/dart-sdk/bin/dart format` as a subprocess: - `generate_messages.dart` (this is the CFE tool that generates `pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart` and `pkg/front_end/lib/src/codes/cfe_codes_generated.dart`). - `generated_files_up_to_date_git_test.dart` (this is a CFE test that verifies that `pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart` and `pkg/front_end/lib/src/codes/cfe_codes_generated.dart` are up to date). - `GeneratedFile.generate` (this is the common method used by most analyzer code generators). - `GeneratedContentExtension.check` (this is used by analyzer tests to verify that generated files are up to date). - `relevance_table_generator.dart` (this is an `analysis_server` tool that generates `relevance_tables*.g.dart` files). Previously, these tools were inconsistent; some of them invoked the formatter through its Dart API, and some of them ran `dart format` as a subprocess via whatever `dart` executable was currently being used for the parent process. This led to a risk that a generated file might be immediately rejected by its own "up to date" test, or by the presubmit script. Standardizing on the use of `tools/sdks/dart-sdk/bin/dart format` (which is what the presubmit script uses) should address this risk. Addresses code review comments: https://dart-review.googlesource.com/c/sdk/+/447920/comment/e9e1aa39_6fffc7e5/. Change-Id: I6a6a69643a69505dc6e30547e0e784358458c357 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/448161 Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Jens Johansen <jensj@google.com>
134 lines
5.0 KiB
Dart
134 lines
5.0 KiB
Dart
import 'dart:async';
|
|
import 'dart:io';
|
|
|
|
import 'package:analyzer_utilities/tools.dart';
|
|
import 'package:package_config/package_config.dart';
|
|
import 'package:path/path.dart';
|
|
import 'package:pub_semver/pub_semver.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
Future<String> _formatText(String text, {required String pkgPath}) async {
|
|
var packageConfig = await findPackageConfig(Directory(pkgPath));
|
|
if (packageConfig == null) {
|
|
throw StateError(
|
|
'Could not find the shared Dart SDK package_config.json file, for '
|
|
'"$pkgPath"',
|
|
);
|
|
}
|
|
var package = packageConfig.packageOf(
|
|
Uri.file(join(pkgPath, 'pubspec.yaml')),
|
|
);
|
|
if (package == null) {
|
|
throw StateError('Could not find the package for "$pkgPath"');
|
|
}
|
|
var languageVersion = package.languageVersion;
|
|
if (languageVersion == null) {
|
|
throw StateError('Could not find a Dart language version for "$pkgPath"');
|
|
}
|
|
var version = Version(languageVersion.major, languageVersion.minor, 0);
|
|
return DartFormat.formatString(text, languageVersion: version);
|
|
}
|
|
|
|
extension GeneratedContentExtension on GeneratedContent {
|
|
/// Check whether the [output] has the correct contents, and return true if it
|
|
/// does.
|
|
///
|
|
/// [pkgRoot] is the path to the SDK's `pkg` directory.
|
|
Future<bool> check(String pkgRoot) async {
|
|
switch (this) {
|
|
case GeneratedDirectory self:
|
|
var outputDirectory = self.output(pkgRoot);
|
|
var map = self.directoryContentsComputer(pkgRoot);
|
|
try {
|
|
for (var entry in map.entries) {
|
|
var file = entry.key;
|
|
var fileContentsComputer = entry.value;
|
|
var expectedContents = await fileContentsComputer(pkgRoot);
|
|
var outputFile = File(posix.join(outputDirectory.path, file));
|
|
var actualContents = outputFile.readAsStringSync();
|
|
// Normalize Windows line endings to Unix line endings so that the
|
|
// comparison doesn't fail on Windows.
|
|
actualContents = actualContents.replaceAll('\r\n', '\n');
|
|
if (expectedContents != actualContents) {
|
|
return false;
|
|
}
|
|
}
|
|
var nonHiddenFileCount = 0;
|
|
outputDirectory
|
|
.listSync(recursive: false, followLinks: false)
|
|
.forEach((FileSystemEntity fileSystemEntity) {
|
|
if (fileSystemEntity is File &&
|
|
!basename(fileSystemEntity.path).startsWith('.')) {
|
|
nonHiddenFileCount++;
|
|
}
|
|
});
|
|
if (nonHiddenFileCount != map.length) {
|
|
// The number of files generated doesn't match the number we expected to
|
|
// generate.
|
|
return false;
|
|
}
|
|
} catch (e) {
|
|
// There was a problem reading the file (most likely because it didn't
|
|
// exist). Treat that the same as if the file doesn't have the expected
|
|
// contents.
|
|
return false;
|
|
}
|
|
return true;
|
|
case GeneratedFile self:
|
|
var outputFile = self.output(pkgRoot);
|
|
var expectedContents = await self.computeContents(pkgRoot);
|
|
if (self.isDartFile) {
|
|
expectedContents = await _formatText(
|
|
expectedContents,
|
|
pkgPath: dirname(outputFile.path),
|
|
);
|
|
}
|
|
try {
|
|
var actualContents = outputFile.readAsStringSync();
|
|
// Normalize Windows line endings to Unix line endings so that the
|
|
// comparison doesn't fail on Windows.
|
|
actualContents = actualContents.replaceAll('\r\n', '\n');
|
|
expectedContents = expectedContents.replaceAll('\r\n', '\n');
|
|
return expectedContents == actualContents;
|
|
} catch (e) {
|
|
// There was a problem reading the file (most likely because it didn't
|
|
// exist). Treat that the same as if the file doesn't have the expected
|
|
// contents.
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extension GeneratedContentIterable on Iterable<GeneratedContent> {
|
|
/// Check that all of the targets in `this` are up to date. If they are not,
|
|
/// print out a message instructing the user to regenerate them, and exit with
|
|
/// a nonzero error code.
|
|
///
|
|
/// [pkgRoot] is the path to the SDK's `pkg` directory. [generatorPath] is
|
|
/// the path to a .dart script the user may use to regenerate the targets.
|
|
///
|
|
/// To avoid mistakes when run on Windows, [generatorPath] always uses
|
|
/// POSIX directory separators.
|
|
Future<void> check(String pkgRoot, String generatorPath) async {
|
|
var generateNeeded = false;
|
|
for (var target in this) {
|
|
var ok = await target.check(pkgRoot);
|
|
if (!ok) {
|
|
print(
|
|
'${normalize(target.output(pkgRoot).absolute.path)}'
|
|
" doesn't have expected contents.",
|
|
);
|
|
generateNeeded = true;
|
|
}
|
|
}
|
|
if (generateNeeded) {
|
|
print('Please regenerate using:');
|
|
var executable = Platform.executable;
|
|
var generateScript = normalize(joinAll(posix.split(generatorPath)));
|
|
print(' $executable $generateScript');
|
|
fail('Generated content needs to be regenerated');
|
|
}
|
|
}
|
|
}
|