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 |