Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: tools/migration/bin/migrate_batch.dart

Issue 2987533002: Add simple test migration helper. (Closed)
Patch Set: Merge branch 'master' into migration-tool Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/migration/analysis_options.yaml ('k') | tools/migration/lib/src/log.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
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.
7 ///
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.
10
11 import 'dart:io';
12
13 import 'package:path/path.dart' as p;
14
15 import 'package:migration/src/log.dart';
16
17 const simpleDirs = const ["corelib", "language", "lib"];
18
19 final String sdkRoot =
20 p.normalize(p.join(p.dirname(p.fromUri(Platform.script)), '../../../'));
21
22 final String testRoot = p.join(sdkRoot, "tests");
23
24 bool dryRun = false;
25
26 void main(List<String> arguments) {
27 if (arguments.contains("--dry-run")) {
28 dryRun = true;
29 arguments = arguments.where((argument) => argument != "--dry-run").toList();
30 }
31
32 if (arguments.length != 2) {
33 stderr.writeln(
34 "Usage: dart migrate_batch.dart [--dry-run] <first file> <last file>");
35 stderr.writeln();
36 stderr.writeln("Example:");
37 stderr.writeln();
38 stderr.writeln(
39 " \$ dart migrate_batch.dart corelib/map_to_string corelib/queue");
40 exit(1);
41 }
42
43 var first = toTwoPath(arguments[0]);
44 var last = toTwoPath(arguments[1]);
45
46 var tests = scanTests();
47
48 // Find the range of files in the chunk. We use comparisons here instead of
49 // equality to try to compensate for files that may only appear in one fork
50 // and should be part of the chunk but aren't officially listed as the begin
51 // or end point.
52 var startIndex = -1;
53 var endIndex = 0;
54 for (var i = 0; i < tests.length; i++) {
55 if (startIndex == -1 && tests[i].twoPath.compareTo(first) >= 0) {
56 startIndex = i;
57 }
58
59 if (tests[i].twoPath.compareTo(last) > 0) {
60 endIndex = i;
61 break;
62 }
63 }
64
65 print("Migrating ${bold(endIndex - startIndex)} tests from ${bold(first)} "
66 "to ${bold(last)}...");
67 print("");
68
69 var todos = <String>[];
70 var migratedTests = 0;
71 var unmigratedTests = 0;
72 for (var i = startIndex; i < endIndex; i++) {
73 if (tests[i].migrate(todos)) {
74 migratedTests++;
75 } else {
76 unmigratedTests++;
77 }
78 }
79
80 print("");
81
82 var summary = "";
83
84 if (migratedTests > 0) {
85 var s = migratedTests == 1 ? "" : "s";
86 summary += "Successfully migrated ${green(migratedTests)} test$s. ";
87 }
88
89 if (unmigratedTests > 0) {
90 var s = migratedTests == 1 ? "" : "s";
91 summary += "Need manual work on ${red(unmigratedTests)} test$s:";
92 }
93
94 print(summary);
95 todos.forEach(todo);
96 }
97
98 String toTwoPath(String path) {
99 // Allow eliding "_test" and/or ".dart" to make things more command-line
100 // friendly.
101 if (!path.endsWith("_test.dart")) path += "_test.dart";
102 if (!path.endsWith(".dart")) path += ".dart";
103
104 for (var dir in simpleDirs) {
105 if (p.isWithin(dir, path)) {
106 return p.join("${dir}_2", p.relative(path, from: dir));
107 }
108
109 if (p.isWithin("${dir}_strong", path)) {
110 return p.join("${dir}_2", p.relative(path, from: dir));
111 }
112 }
113
114 if (p.isWithin("html", path)) {
115 return p.join("lib_2/html", p.relative(path, from: "html"));
116 }
117
118 if (p.isWithin("isolate", path)) {
119 return p.join("lib_2/isolate", p.relative(path, from: "isolate"));
120 }
121
122 // Guess it's already a two path.
123 return path;
124 }
125
126 /// Loads all of the unforked test files.
127 ///
128 /// Creates an list of [Fork]s, ordered by their destination paths. Handles
129 /// tests that only appear in one fork or the other, or both.
130 List<Fork> scanTests() {
131 var tests = <String, Fork>{};
132
133 addTestDirectory(String fromDir, String twoDir) {
134 for (var entry
135 in new Directory(p.join(testRoot, fromDir)).listSync(recursive: true)) {
136 if (!entry.path.endsWith("_test.dart")) continue;
137
138 var fromPath = p.relative(entry.path, from: testRoot);
139 var twoPath = p.join(twoDir, p.relative(fromPath, from: fromDir));
140
141 var fork = tests.putIfAbsent(twoPath, () => new Fork(twoPath));
142 if (fromDir.contains("_strong")) {
143 fork.strongPath = fromPath;
144 } else {
145 fork.onePath = fromPath;
146 }
147 }
148 }
149
150 addTestDirectory("corelib", "corelib_2");
151 addTestDirectory("corelib_strong", "corelib_2");
152 addTestDirectory("html", "lib_2/html");
153 addTestDirectory("isolate", "lib_2/isolate");
154 addTestDirectory("language", "language_2");
155 addTestDirectory("language_strong", "language_2");
156 addTestDirectory("lib", "lib_2");
157 addTestDirectory("lib_strong", "lib_2");
158
159 var sorted = tests.values.toList();
160 sorted.sort((a, b) => a.twoPath.compareTo(b.twoPath));
161 return sorted;
162 }
163
164 /// Moves the file from [from] to [to], which are both assumed to be relative
165 /// paths inside "tests".
166 void moveFile(String from, String to) {
167 if (dryRun) {
168 print(" Dry run: move $from to $to");
169 return;
170 }
171
172 new File(p.join(testRoot, from)).renameSync(p.join(testRoot, to));
173 }
174
175 /// Reads the contents of the file at [path], which is assumed to be relative
176 /// within "tests".
177 String readFile(String path) {
178 return new File(p.join(testRoot, path)).readAsStringSync();
179 }
180
181 /// Deletes the file at [path], which is assumed to be relative within "tests".
182 void deleteFile(String path) {
183 if (dryRun) {
184 print(" Dry run: delete $path");
185 return;
186 }
187
188 new File(p.join(testRoot, path)).deleteSync();
189 }
190
191 bool checkForUnitTest(String path, String source) {
192 if (!source.contains("package:unittest")) return false;
193
194 note("${bold(path)} uses unittest package.");
195 return true;
196 }
197
198 class Fork {
199 final String twoPath;
200 String onePath;
201 String strongPath;
202
203 String get twoSource {
204 if (twoPath == null) return null;
205 if (_twoSource == null) _twoSource = readFile(twoPath);
206 return _twoSource;
207 }
208
209 String _twoSource;
210
211 String get oneSource {
212 if (onePath == null) return null;
213 if (_oneSource == null) _oneSource = readFile(onePath);
214 return _oneSource;
215 }
216
217 String _oneSource;
218
219 String get strongSource {
220 if (strongPath == null) return null;
221 if (_strongSource == null) _strongSource = readFile(strongPath);
222 return _strongSource;
223 }
224
225 String _strongSource;
226
227 Fork(this.twoPath);
228
229 bool migrate(List<String> todos) {
230 print("- ${bold(twoPath)}:");
231
232 var todosBefore = todos.length;
233 var isMigrated = new File(p.join(testRoot, twoPath)).existsSync();
234
235 // If there is a migrated version and it's the same as an unmigrated one,
236 // delete the unmigrated one.
237 if (isMigrated) {
238 if (onePath != null) {
239 if (oneSource == twoSource) {
240 deleteFile(onePath);
241 done("Deleted already-migrated $onePath.");
242 } else {
243 note("${bold(onePath)} does not match already-migrated "
244 "${bold(twoPath)}.");
245 todos.add("Merge ${bold(onePath)} into ${bold(twoPath)}.");
246 checkForUnitTest(onePath, oneSource);
247 }
248 }
249
250 if (strongPath != null) {
251 if (strongSource == twoSource) {
252 deleteFile(strongPath);
253 done("Deleted already-migrated ${bold(strongPath)}.");
254 } else {
255 note("${bold(strongPath)} does not match already-migrated "
256 "${bold(twoPath)}.");
257 todos.add("Merge ${bold(strongPath)} into ${bold(twoPath)}.");
258 checkForUnitTest(strongPath, strongSource);
259 }
260 }
261 } else {
262 // If it only exists in one place, just move it.
263 if (strongPath == null) {
264 moveFile(onePath, twoPath);
265 done("Moved from ${bold(onePath)} (no strong mode fork).");
266 } else if (onePath == null) {
267 moveFile(strongPath, twoPath);
268 done("Moved from ${bold(strongPath)} (no 1.0 mode fork).");
269 } else if (oneSource == strongSource) {
270 // The forks are identical, pick one.
271 moveFile(onePath, twoPath);
272 deleteFile(strongPath);
273 done("Merged identical forks.");
274 checkForUnitTest(twoPath, oneSource);
275 } else {
276 // Otherwise, a manual merge is required. Start with the strong one.
277 moveFile(strongPath, twoPath);
278 done("Moved strong fork, kept 1.0 fork, manual merge required.");
279 todos.add("Merge ${bold(onePath)} into ${bold(twoPath)}.");
280 checkForUnitTest(onePath, oneSource);
281 }
282 }
283
284 if (checkForUnitTest(twoPath, twoSource)) {
285 todos.add("Migrate ${bold(twoPath)} off unittest.");
286 }
287
288 return todos.length == todosBefore;
289 }
290 }
OLDNEW
« no previous file with comments | « tools/migration/analysis_options.yaml ('k') | tools/migration/lib/src/log.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698