Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /// Given the beginning and ending file names in a batch, does as much automated | 5 /// Given the beginning and ending file names in a batch, does as much automated |
| 6 /// migration and possible and prints out the remaining manual steps required. | 6 /// migration and possible and prints out the remaining manual steps required. |
| 7 /// | 7 /// |
| 8 /// This should be safe to run, and safe to re-run on an in-progress chunk. | 8 /// This should be safe to run, and safe to re-run on an in-progress chunk. |
| 9 /// However, it has not been thoroughly tested, so run at your own risk. | 9 /// However, it has not been thoroughly tested, so run at your own risk. |
| 10 | 10 |
| 11 import 'dart:io'; | 11 import 'dart:io'; |
| 12 | 12 |
| 13 import 'package:path/path.dart' as p; | 13 import 'package:path/path.dart' as p; |
| 14 import 'package:status_file/status_file.dart'; | |
| 15 | 14 |
| 16 import 'package:migration/src/fork.dart'; | 15 import 'package:migration/src/fork.dart'; |
| 17 import 'package:migration/src/io.dart'; | 16 import 'package:migration/src/io.dart'; |
| 18 import 'package:migration/src/log.dart'; | 17 import 'package:migration/src/log.dart'; |
| 18 import 'package:migration/src/migrate_statuses.dart'; | |
| 19 import 'package:migration/src/test_directories.dart'; | |
| 19 | 20 |
| 20 const simpleDirs = const ["corelib", "language", "lib"]; | 21 const simpleDirs = const ["corelib", "language", "lib"]; |
| 21 | 22 |
| 22 void main(List<String> arguments) { | 23 void main(List<String> arguments) { |
| 23 if (arguments.contains("--dry-run")) { | 24 if (arguments.contains("--dry-run")) { |
| 24 dryRun = true; | 25 dryRun = true; |
| 25 arguments = arguments.where((argument) => argument != "--dry-run").toList(); | 26 arguments = arguments.where((argument) => argument != "--dry-run").toList(); |
| 26 } | 27 } |
| 27 | 28 |
| 28 if (arguments.length != 2) { | 29 if (arguments.length != 2) { |
| 29 stderr.writeln( | 30 stderr.writeln( |
| 30 "Usage: dart migrate_batch.dart [--dry-run] <first file> <last file>"); | 31 "Usage: dart migrate_batch.dart [--dry-run] <first file> <last file>"); |
| 31 stderr.writeln(); | 32 stderr.writeln(); |
| 32 stderr.writeln("Example:"); | 33 stderr.writeln("Example:"); |
| 33 stderr.writeln(); | 34 stderr.writeln(); |
| 34 stderr.writeln( | 35 stderr.writeln( |
| 35 " \$ dart migrate_batch.dart corelib/map_to_string corelib/queue"); | 36 " \$ dart migrate_batch.dart corelib/map_to_string corelib/queue"); |
| 36 exit(1); | 37 exit(1); |
| 37 } | 38 } |
| 38 | 39 |
| 39 var tests = scanTests(); | 40 var tests = scanTests(); |
| 40 | 41 |
| 41 var startIndex = findFork(tests, arguments[0]); | 42 var startIndex = findFork(tests, arguments[0]); |
| 42 var endIndex = findFork(tests, arguments[1]); | 43 var endIndex = findFork(tests, arguments[1]); |
| 43 | 44 |
| 44 if (startIndex == null || endIndex == null) exit(1); | 45 if (startIndex == null || endIndex == null) exit(1); |
| 45 | 46 |
| 46 var first = tests[startIndex].twoPath; | 47 tests = tests.sublist(startIndex, endIndex + 1); |
| 47 var last = tests[endIndex].twoPath; | |
| 48 | 48 |
| 49 // Make the range half-inclusive to simplify the math below. | 49 if (tests.isEmpty) { |
| 50 endIndex++; | |
| 51 | |
| 52 if (endIndex - startIndex == 0) { | |
| 53 print(bold("No tests in range.")); | 50 print(bold("No tests in range.")); |
| 54 return; | 51 return; |
| 55 } | 52 } |
| 56 | 53 |
| 57 print("Migrating ${bold(endIndex - startIndex)} tests from ${bold(first)} " | 54 var s = tests.length == 1 ? "" : "s"; |
| 55 var first = tests.first.twoPath; | |
| 56 var last = tests.last.twoPath; | |
| 57 print("Migrating ${bold(tests.length)} test$s from ${bold(first)} " | |
|
bkonyi
2017/07/27 22:02:00
Did you mean to put 'test$s'?
Bob Nystrom
2017/07/27 22:58:19
Yup. See the "s" variable above. It will print "te
| |
| 58 "to ${bold(last)}..."); | 58 "to ${bold(last)}..."); |
| 59 print(""); | 59 print(""); |
| 60 | 60 |
| 61 var allTodos = <String, List<String>>{}; | 61 var allTodos = <String, List<String>>{}; |
| 62 tests = tests.sublist(startIndex, endIndex); | |
| 63 var migratedTests = 0; | 62 var migratedTests = 0; |
| 64 var unmigratedTests = 0; | 63 var unmigratedTests = 0; |
| 65 for (var test in tests) { | 64 for (var test in tests) { |
| 66 var todos = test.migrate(); | 65 var todos = test.migrate(); |
| 67 if (todos.isEmpty) { | 66 if (todos.isEmpty) { |
| 68 migratedTests++; | 67 migratedTests++; |
| 69 } else { | 68 } else { |
| 70 unmigratedTests++; | 69 unmigratedTests++; |
| 71 allTodos[test.twoPath] = todos; | 70 allTodos[test.twoPath] = todos; |
| 72 } | 71 } |
| 73 } | 72 } |
| 74 | 73 |
| 75 // Print status file entries. | 74 migrateStatusEntries(tests); |
| 76 var statusFileEntries = new StringBuffer(); | |
| 77 var statusFiles = loadStatusFiles(); | |
| 78 for (var statusFile in statusFiles) { | |
| 79 printStatusFileEntries(statusFileEntries, tests, statusFile); | |
| 80 } | |
| 81 | 75 |
| 82 new File("statuses.migration") | 76 // Tell the user what's left to do. |
| 83 .writeAsStringSync(statusFileEntries.toString()); | |
| 84 print("Wrote relevant test status file entries to 'statuses.migration'."); | |
| 85 | |
| 86 // Tell the user what's left TODO. | |
| 87 print(""); | 77 print(""); |
| 88 var summary = ""; | 78 var summary = ""; |
| 89 | 79 |
| 90 if (migratedTests > 0) { | 80 if (migratedTests > 0) { |
| 91 var s = migratedTests == 1 ? "" : "s"; | 81 var s = migratedTests == 1 ? "" : "s"; |
| 92 summary += "Successfully migrated ${green(migratedTests)} test$s. "; | 82 summary += "Successfully migrated ${green(migratedTests)} test$s. "; |
| 93 } | 83 } |
| 94 | 84 |
| 95 if (unmigratedTests > 0) { | 85 if (unmigratedTests > 0) { |
| 96 var s = unmigratedTests == 1 ? "" : "s"; | 86 var s = unmigratedTests == 1 ? "" : "s"; |
| 97 summary += "Need manual work on ${red(unmigratedTests)} test$s:"; | 87 summary += "Need manual work on ${red(unmigratedTests)} test$s:"; |
| 98 } | 88 } |
| 99 | 89 |
| 100 print(summary); | 90 print(summary); |
| 101 var todoTests = allTodos.keys.toList(); | 91 var todoTests = allTodos.keys.toList(); |
| 102 todoTests.sort(); | 92 todoTests.sort(); |
| 103 for (var todoTest in todoTests) { | 93 for (var todoTest in todoTests) { |
| 104 print("- ${bold(todoTest)}:"); | 94 print("- ${bold(todoTest)}:"); |
| 105 allTodos[todoTest].forEach(todo); | 95 allTodos[todoTest].forEach(todo); |
| 106 } | 96 } |
| 107 } | 97 } |
| 108 | 98 |
| 109 /// Returns a [String] of the relevant status file entries associated with the | |
| 110 /// tests in [tests] found in [statusFile]. | |
| 111 void printStatusFileEntries( | |
| 112 StringBuffer statusFileEntries, List<Fork> tests, StatusFile statusFile) { | |
| 113 var filteredStatusFile = new StatusFile(statusFile.path); | |
| 114 var testNames = <String>[]; | |
| 115 for (var test in tests) { | |
| 116 testNames.add(test.twoPath.split("/").last.split(".")[0]); | |
| 117 } | |
| 118 for (var section in statusFile.sections) { | |
| 119 StatusSection currentSection; | |
| 120 for (var entry in section.entries) { | |
| 121 for (var testName in testNames) { | |
| 122 if (entry.path.contains(testName)) { | |
| 123 if (currentSection == null) { | |
| 124 currentSection = new StatusSection(section.condition); | |
| 125 } | |
| 126 currentSection.entries.add(entry); | |
| 127 } | |
| 128 } | |
| 129 } | |
| 130 if (currentSection != null) { | |
| 131 filteredStatusFile.sections.add(currentSection); | |
| 132 } | |
| 133 } | |
| 134 if (!filteredStatusFile.isEmpty) { | |
| 135 statusFileEntries.writeln("Entries for status file ${statusFile.path}:"); | |
| 136 statusFileEntries.writeln(filteredStatusFile); | |
| 137 } | |
| 138 } | |
| 139 | |
| 140 int findFork(List<Fork> forks, String description) { | 99 int findFork(List<Fork> forks, String description) { |
| 141 var matches = <int>[]; | 100 var matches = <int>[]; |
| 142 | 101 |
| 143 for (var i = 0; i < forks.length; i++) { | 102 for (var i = 0; i < forks.length; i++) { |
| 144 if (forks[i].twoPath.contains(description)) matches.add(i); | 103 if (forks[i].twoPath.contains(description)) matches.add(i); |
| 145 } | 104 } |
| 146 | 105 |
| 147 if (matches.isEmpty) { | 106 if (matches.isEmpty) { |
| 148 print('Could not find a test matching "${bold(description)}".'); | 107 print('Could not find a test matching "${bold(description)}".'); |
| 149 return null; | 108 return null; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 160 } | 119 } |
| 161 } | 120 } |
| 162 | 121 |
| 163 /// Loads all of the unforked test files. | 122 /// Loads all of the unforked test files. |
| 164 /// | 123 /// |
| 165 /// Creates an list of [Fork]s, ordered by their destination paths. Handles | 124 /// Creates an list of [Fork]s, ordered by their destination paths. Handles |
| 166 /// tests that only appear in one fork or the other, or both. | 125 /// tests that only appear in one fork or the other, or both. |
| 167 List<Fork> scanTests() { | 126 List<Fork> scanTests() { |
| 168 var tests = <String, Fork>{}; | 127 var tests = <String, Fork>{}; |
| 169 | 128 |
| 170 addFromDirectory(String fromDir, String twoDir) { | 129 for (var fromDir in fromRootDirs) { |
| 130 var twoDir = toTwoDirectory(fromDir); | |
| 171 for (var path in listFiles(fromDir)) { | 131 for (var path in listFiles(fromDir)) { |
| 172 var fromPath = p.relative(path, from: testRoot); | 132 var fromPath = p.relative(path, from: testRoot); |
| 173 var twoPath = p.join(twoDir, p.relative(fromPath, from: fromDir)); | 133 var twoPath = p.join(twoDir, p.relative(fromPath, from: fromDir)); |
| 174 | 134 |
| 175 var fork = tests.putIfAbsent(twoPath, () => new Fork(twoPath)); | 135 tests.putIfAbsent(twoPath, () => new Fork(twoPath)); |
| 176 if (fromDir.contains("_strong")) { | |
| 177 fork.strongPath = fromPath; | |
| 178 } else { | |
| 179 fork.onePath = fromPath; | |
| 180 } | |
| 181 } | 136 } |
| 182 } | 137 } |
| 183 | 138 |
| 184 addFromDirectory("corelib", "corelib_2"); | |
| 185 addFromDirectory("corelib_strong", "corelib_2"); | |
| 186 addFromDirectory("html", "lib_2/html"); | |
| 187 addFromDirectory("isolate", "lib_2/isolate"); | |
| 188 addFromDirectory("language", "language_2"); | |
| 189 addFromDirectory("language_strong", "language_2"); | |
| 190 addFromDirectory("lib", "lib_2"); | |
| 191 addFromDirectory("lib_strong", "lib_2"); | |
| 192 | |
| 193 // Include tests that have already been migrated too so we can show what | 139 // Include tests that have already been migrated too so we can show what |
| 194 // works remains to be done in them. | 140 // works remains to be done in them. |
| 195 const twoDirs = const [ | 141 for (var dir in twoRootDirs) { |
| 196 "corelib_2", | |
| 197 "lib_2", | |
| 198 "language_2", | |
| 199 ]; | |
| 200 | |
| 201 for (var dir in twoDirs) { | |
| 202 for (var path in listFiles(dir)) { | 142 for (var path in listFiles(dir)) { |
| 203 var twoPath = p.relative(path, from: testRoot); | 143 var twoPath = p.relative(path, from: testRoot); |
| 204 tests.putIfAbsent(twoPath, () => new Fork(twoPath)); | 144 tests.putIfAbsent(twoPath, () => new Fork(twoPath)); |
| 205 } | 145 } |
| 206 } | 146 } |
| 207 | 147 |
| 208 var sorted = tests.values.toList(); | 148 var sorted = tests.values.toList(); |
| 209 sorted.sort((a, b) => a.twoPath.compareTo(b.twoPath)); | 149 sorted.sort((a, b) => a.twoPath.compareTo(b.twoPath)); |
| 210 return sorted; | 150 return sorted; |
| 211 } | 151 } |
| 212 | |
| 213 List<StatusFile> loadStatusFiles() { | |
| 214 var statusFiles = <StatusFile>[]; | |
| 215 | |
| 216 addStatusFile(String fromDir) { | |
| 217 for (var path in listFiles(fromDir, extension: ".status")) { | |
| 218 statusFiles.add(new StatusFile.read(path)); | |
| 219 } | |
| 220 } | |
| 221 | |
| 222 addStatusFile("corelib"); | |
| 223 addStatusFile("corelib_strong"); | |
| 224 addStatusFile("html"); | |
| 225 addStatusFile("isolate"); | |
| 226 addStatusFile("language"); | |
| 227 addStatusFile("language_strong"); | |
| 228 addStatusFile("lib"); | |
| 229 addStatusFile("lib_strong"); | |
| 230 return statusFiles; | |
| 231 } | |
| OLD | NEW |