blob: 82136035a82d61fa89676dfd434467b5c56aa5c1 [file] [log] [blame] [edit]
// Copyright (c) 2025, 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:args/args.dart';
import 'package:native_test_helpers/native_test_helpers.dart';
void main(List<String> args) {
final stopwatch = Stopwatch()..start();
final parser = ArgParser()
..addFlag(
'set-exit-if-changed',
negatable: false,
help: 'Return a non-zero exit code if any files were changed.',
);
final argResults = parser.parse(args);
final setExitIfChanged = argResults['set-exit-if-changed'] as bool;
final counts = Counts();
updateManifests(counts);
stopwatch.stop();
final duration = stopwatch.elapsedMilliseconds / 1000.0;
print(
'Generated ${counts.generated} files (${counts.changed} changed) in '
'${duration.toStringAsFixed(2)} seconds.',
);
if (setExitIfChanged && counts.changed > 0) {
exit(1);
}
}
class Counts {
int generated = 0;
int changed = 0;
}
void updateManifests(Counts counts) async {
final packageUri = findPackageRoot('hooks_runner');
final testDataUri = packageUri.resolve('test_data/');
final testDataDirectory = Directory.fromUri(testDataUri);
updateManifest(testDataDirectory, counts, allowPartialProjects: false);
final all = testDataDirectory.listSync(recursive: true);
all.whereType<Directory>().forEach(
(e) => updateManifest(e, counts, allowPartialProjects: true),
);
}
const denyList = [
'.dart_tool',
'pubspec.lock',
'manifest',
'README.md',
'.gitignore',
];
/// These just modify other test projects.
///
/// Don't add pubspecs to manifests, they contain a different name due to all
/// being part of a big workspace. They have a pubspec to enable analysis of
/// the Dart code in them.
const partialProjects = [
'native_add_add_source',
'native_add_add_symbol',
'native_add_break_build',
'native_add_fix_build',
'simple_link_change_asset',
];
void updateManifest(
Directory directory,
Counts counts, {
required bool allowPartialProjects,
}) {
final manifestFile = File.fromUri(directory.uri.resolve('manifest.yaml'));
if (!manifestFile.existsSync()) {
return;
}
final all = directory.listSync(recursive: true);
final dirPath = directory.uri.toFilePath(windows: false);
final files =
all
.whereType<File>()
.where((f) {
for (final denyString in [
...denyList,
if (!allowPartialProjects) ...partialProjects,
for (final partialProject in partialProjects) ...[
'$partialProject/pubspec.yaml',
],
]) {
if (f.uri.toFilePath(windows: false).contains(denyString)) {
return false;
}
}
return true;
})
.map(
(e) => e.uri.toFilePath(windows: false).replaceFirst(dirPath, ''),
)
.toList()
..sort();
var oldContent = '';
if (manifestFile.existsSync()) {
oldContent = manifestFile.readAsStringSync();
}
final newContent = header + files.map((e) => '- $e\n').join();
final newContentNormalized = newContent.replaceAll('\r\n', '\n');
final oldContentNormalized = oldContent.replaceAll('\r\n', '\n');
if (newContentNormalized != oldContentNormalized) {
manifestFile.writeAsStringSync(newContent);
print('Generated ${manifestFile.uri} (content changed)');
counts.changed++;
}
counts.generated++;
}
const header = '''
# The list of files to copy to a temporary folder to ensure running tests from
# a completely clean setup.
# Automatically generated by manifest_generator.dart.
''';