| Index: tools/migration/lib/src/migrate_statuses.dart
|
| diff --git a/tools/migration/lib/src/migrate_statuses.dart b/tools/migration/lib/src/migrate_statuses.dart
|
| index dead6ef88e88527308d65c1b5e747fadb6b81e6c..49816481c9e76d988264f6e5f4d50de72ea1d207 100644
|
| --- a/tools/migration/lib/src/migrate_statuses.dart
|
| +++ b/tools/migration/lib/src/migrate_statuses.dart
|
| @@ -7,10 +7,11 @@ import 'package:path/path.dart' as p;
|
| import 'editable_status_file.dart';
|
| import 'fork.dart';
|
| import 'io.dart';
|
| +import 'log.dart';
|
| import 'test_directories.dart';
|
|
|
| /// Migrates the status file entries that match [files].
|
| -void migrateStatusEntries(List<Fork> files) {
|
| +void migrateStatusEntries(List<Fork> files, Map<String, List<String>> todos) {
|
| var entriesToMove = new EntrySet();
|
|
|
| _collectEntries(files, entriesToMove, isOne: true);
|
| @@ -21,7 +22,58 @@ void migrateStatusEntries(List<Fork> files) {
|
| _addEntries(statusFile, sections);
|
| }
|
|
|
| - // TODO(rnystrom): Should this log any output?
|
| + // If any entries need manual splitting, let the user know.
|
| + for (var dir in entriesToMove._todoHeaders.keys) {
|
| + var destination = "$dir.status";
|
| + var headers = entriesToMove._todoHeaders[dir];
|
| + var splits = headers.map((header) {
|
| + var files =
|
| + filesForHeader(header).map((file) => bold("${dir}_$file")).join(", ");
|
| + return "Need to manually split status file section in ${bold(destination)}"
|
| + " across files $files:\n $header";
|
| + }).toList();
|
| +
|
| + if (splits.isNotEmpty) todos[destination] = splits;
|
| + }
|
| +}
|
| +
|
| +/// Given the header for a status file section, looks at the condition
|
| +/// expression to determine which status files it should go in.
|
| +Set<String> filesForHeader(String header) {
|
| + // Figure out which status file it goes into.
|
| + var result = new Set<String>();
|
| +
|
| + // The various compilers are roughly separate products.
|
| + const compilers = const {
|
| + r"$compiler == dart2analyzer": "analyzer",
|
| + r"$compiler == dart2js": "dart2js",
|
| + r"$compiler == dartdevc": "dartdevc",
|
| + // This deliberately matches both dartk and dartkp.
|
| + r"$compiler == dartk": "kernel",
|
| + r"$compiler == precompiler": "precompiled"
|
| + };
|
| +
|
| + // TODO(rnystrom): This is obviously very sensitive to the formatting of
|
| + // the expression. Hacky, but hopefully good enough for now.
|
| + compilers.forEach((compiler, file) {
|
| + if (header.contains(compiler)) result.add(file);
|
| + });
|
| +
|
| + // If we couldn't figure out where to put it based on the compiler, look at
|
| + // the runtime.
|
| + if (result.isEmpty) {
|
| + const runtimes = const {
|
| + r"$runtime == vm": "vm",
|
| + r"$runtime == flutter": "flutter",
|
| + r"$runtime == dart_precompiled": "precompiled",
|
| + };
|
| +
|
| + runtimes.forEach((runtime, file) {
|
| + if (header.contains(runtime)) result.add(file);
|
| + });
|
| + }
|
| +
|
| + return result;
|
| }
|
|
|
| /// Tracks a set of entries to add to a set of Dart 2.0 status files.
|
| @@ -31,13 +83,41 @@ class EntrySet {
|
| /// of entries to add under that section.
|
| final Map<String, Map<String, List<String>>> _files = {};
|
|
|
| + final _todoHeaders = <String, Set<String>>{};
|
| +
|
| Iterable<String> get statusFiles => _files.keys;
|
|
|
| - void add(String fromDir, String header, String entry) {
|
| + /// Attempts to add the [entry] under [header] in a status file in [fromDir]
|
| + /// to this EntrySet.
|
| + ///
|
| + /// Returns true if successful or false if the header's condition doesn't fit
|
| + /// into a single status file and needs to be manually split by the user.
|
| + bool add(String fromDir, String header, String entry) {
|
| var toDir = toTwoDirectory(fromDir);
|
| - var sections = _files.putIfAbsent(p.join(toDir, "$toDir.status"), () => {});
|
| +
|
| + // Figure out which status file it goes into.
|
| + var possibleFiles = filesForHeader(header);
|
| + var destination = "$toDir.status";
|
| +
|
| + if (possibleFiles.length > 1) {
|
| + // The condition matches multiple files, so the user is going to have to
|
| + // manually split it up into multiple sections first.
|
| + // TODO(rnystrom): Would be good to automate this, though it requires
|
| + // being able to work with condition expressions directly.
|
| + _todoHeaders.putIfAbsent(toDir, () => new Set()).add(header);
|
| + return false;
|
| + }
|
| +
|
| + // If the condition places it directly into one file, put it there.
|
| + if (possibleFiles.length == 1) {
|
| + destination = "${toDir}_${possibleFiles.single}.status";
|
| + }
|
| +
|
| + var sections = _files.putIfAbsent(p.join(toDir, destination), () => {});
|
| +
|
| var entries = sections.putIfAbsent(header, () => []);
|
| entries.add(entry);
|
| + return true;
|
| }
|
|
|
| Map<String, List<String>> sections(String file) => _files[file];
|
| @@ -77,12 +157,12 @@ void _collectEntries(List<Fork> files, EntrySet entriesToMove, {bool isOne}) {
|
| // manually handle it.
|
| if (!entryPath.startsWith(filePath)) continue;
|
|
|
| - // Remove it from this status file.
|
| - deleteLines.add(entry.lineNumber - 1);
|
| -
|
| - // And add it to the 2.0 one.
|
| - entriesToMove.add(fromDir, editable.lineAt(section.lineNumber),
|
| - editable.lineAt(entry.lineNumber));
|
| + // Add it to the 2.0 one.
|
| + if (entriesToMove.add(fromDir, editable.lineAt(section.lineNumber),
|
| + editable.lineAt(entry.lineNumber))) {
|
| + // Remove it from the original status file.
|
| + deleteLines.add(entry.lineNumber - 1);
|
| + }
|
| }
|
| }
|
| }
|
|
|