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 | 14 |
| 15 import 'package:migration/src/log.dart'; | 15 import 'package:migration/src/log.dart'; |
| 16 import 'package:migration/src/validate.dart'; | |
| 16 import 'package:status_file/status_file.dart'; | 17 import 'package:status_file/status_file.dart'; |
| 17 | 18 |
| 18 const simpleDirs = const ["corelib", "language", "lib"]; | 19 const simpleDirs = const ["corelib", "language", "lib"]; |
| 19 | 20 |
| 20 final String sdkRoot = | 21 final String sdkRoot = |
| 21 p.normalize(p.join(p.dirname(p.fromUri(Platform.script)), '../../../')); | 22 p.normalize(p.join(p.dirname(p.fromUri(Platform.script)), '../../../')); |
| 22 | 23 |
| 23 final String testRoot = p.join(sdkRoot, "tests"); | 24 final String testRoot = p.join(sdkRoot, "tests"); |
| 24 | 25 |
| 25 bool dryRun = false; | 26 bool dryRun = false; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 65 | 66 |
| 66 if ((endIndex - startIndex) == 0) { | 67 if ((endIndex - startIndex) == 0) { |
| 67 print(bold("No tests to migrate.")); | 68 print(bold("No tests to migrate.")); |
| 68 return; | 69 return; |
| 69 } | 70 } |
| 70 | 71 |
| 71 print("Migrating ${bold(endIndex - startIndex)} tests from ${bold(first)} " | 72 print("Migrating ${bold(endIndex - startIndex)} tests from ${bold(first)} " |
| 72 "to ${bold(last)}..."); | 73 "to ${bold(last)}..."); |
| 73 print(""); | 74 print(""); |
| 74 | 75 |
| 75 tests = tests.getRange(startIndex, endIndex); | 76 var allTodos = <String, List<String>>{}; |
| 76 var todos = <String>[]; | 77 tests = tests.sublist(startIndex, endIndex); |
| 77 var migratedTests = 0; | 78 var migratedTests = 0; |
| 78 var unmigratedTests = 0; | 79 var unmigratedTests = 0; |
| 79 for (var test in tests) { | 80 for (var test in tests) { |
| 80 if (test.migrate(todos)) { | 81 var todos = test.migrate(); |
| 82 if (todos.isEmpty) { | |
| 81 migratedTests++; | 83 migratedTests++; |
| 82 } else { | 84 } else { |
| 83 unmigratedTests++; | 85 unmigratedTests++; |
| 86 allTodos[test.twoPath] = todos; | |
| 84 } | 87 } |
| 85 } | 88 } |
| 86 | 89 |
| 90 // Print status file entries. | |
| 91 var statusFileEntries = new StringBuffer(); | |
| 92 var statusFiles = loadStatusFiles(); | |
| 93 for (var statusFile in statusFiles) { | |
| 94 printStatusFileEntries(statusFileEntries, tests, statusFile); | |
| 95 } | |
| 96 | |
| 97 new File("statuses.migration") | |
| 98 .writeAsStringSync(statusFileEntries.toString()); | |
| 99 print("Wrote relevant test status file entries to 'statuses.migration'."); | |
| 100 | |
| 101 // Tell the user what's left TODO. | |
| 87 print(""); | 102 print(""); |
| 88 | |
| 89 var summary = ""; | 103 var summary = ""; |
| 90 | 104 |
| 91 if (migratedTests > 0) { | 105 if (migratedTests > 0) { |
| 92 var s = migratedTests == 1 ? "" : "s"; | 106 var s = migratedTests == 1 ? "" : "s"; |
| 93 summary += "Successfully migrated ${green(migratedTests)} test$s. "; | 107 summary += "Successfully migrated ${green(migratedTests)} test$s. "; |
| 94 } | 108 } |
| 95 | 109 |
| 96 if (unmigratedTests > 0) { | 110 if (unmigratedTests > 0) { |
| 97 var s = migratedTests == 1 ? "" : "s"; | 111 var s = unmigratedTests == 1 ? "" : "s"; |
| 98 summary += "Need manual work on ${red(unmigratedTests)} test$s:"; | 112 summary += "Need manual work on ${red(unmigratedTests)} test$s:"; |
| 99 } | 113 } |
| 100 | 114 |
| 101 print(summary); | 115 print(summary); |
| 102 todos.forEach(todo); | 116 var todoTests = allTodos.keys.toList(); |
| 103 | 117 todoTests.sort(); |
| 104 // Print status file entries. | 118 for (var todoTest in todoTests) { |
| 105 var statusFileEntries = new StringBuffer(); | 119 print("- ${bold(todoTest)}:"); |
| 106 var statusFiles = loadStatusFiles(); | 120 allTodos[todoTest].forEach(todo); |
| 107 for (var statusFile in statusFiles) { | |
| 108 printStatusFileEntries(statusFileEntries, tests, statusFile); | |
| 109 } | 121 } |
| 110 | |
| 111 new File("statuses.migration") | |
| 112 .writeAsStringSync(statusFileEntries.toString()); | |
| 113 print( | |
| 114 bold("Wrote relevant test status file entries to 'statuses.migration'")); | |
| 115 } | 122 } |
| 116 | 123 |
| 117 /// Returns a [String] of the relevant status file entries associated with the | 124 /// Returns a [String] of the relevant status file entries associated with the |
| 118 /// tests in [tests] found in [statusFile]. | 125 /// tests in [tests] found in [statusFile]. |
| 119 void printStatusFileEntries( | 126 void printStatusFileEntries( |
| 120 StringBuffer statusFileEntries, List<Fork> tests, StatusFile statusFile) { | 127 StringBuffer statusFileEntries, List<Fork> tests, StatusFile statusFile) { |
| 121 var filteredStatusFile = new StatusFile(statusFile.path); | 128 var filteredStatusFile = new StatusFile(statusFile.path); |
| 122 var testNames = <String>[]; | 129 var testNames = <String>[]; |
| 123 for (var test in tests) { | 130 for (var test in tests) { |
| 124 testNames.add(test.twoPath.split("/").last.split(".")[0]); | 131 testNames.add(test.twoPath.split("/").last.split(".")[0]); |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 234 } | 241 } |
| 235 | 242 |
| 236 /// Moves the file from [from] to [to], which are both assumed to be relative | 243 /// Moves the file from [from] to [to], which are both assumed to be relative |
| 237 /// paths inside "tests". | 244 /// paths inside "tests". |
| 238 void moveFile(String from, String to) { | 245 void moveFile(String from, String to) { |
| 239 if (dryRun) { | 246 if (dryRun) { |
| 240 print(" Dry run: move $from to $to"); | 247 print(" Dry run: move $from to $to"); |
| 241 return; | 248 return; |
| 242 } | 249 } |
| 243 | 250 |
| 251 // Create the directory if needed. | |
| 252 new Directory(p.dirname(p.join(testRoot, to))).createSync(recursive: true); | |
|
bkonyi
2017/07/26 17:59:26
Nice! I just ran into this case.
| |
| 253 | |
| 244 new File(p.join(testRoot, from)).renameSync(p.join(testRoot, to)); | 254 new File(p.join(testRoot, from)).renameSync(p.join(testRoot, to)); |
| 245 } | 255 } |
| 246 | 256 |
| 247 /// Reads the contents of the file at [path], which is assumed to be relative | 257 /// Reads the contents of the file at [path], which is assumed to be relative |
| 248 /// within "tests". | 258 /// within "tests". |
| 249 String readFile(String path) { | 259 String readFile(String path) { |
| 250 return new File(p.join(testRoot, path)).readAsStringSync(); | 260 return new File(p.join(testRoot, path)).readAsStringSync(); |
| 251 } | 261 } |
| 252 | 262 |
| 253 /// Deletes the file at [path], which is assumed to be relative within "tests". | 263 /// Deletes the file at [path], which is assumed to be relative within "tests". |
| 254 void deleteFile(String path) { | 264 void deleteFile(String path) { |
| 255 if (dryRun) { | 265 if (dryRun) { |
| 256 print(" Dry run: delete $path"); | 266 print(" Dry run: delete $path"); |
| 257 return; | 267 return; |
| 258 } | 268 } |
| 259 | 269 |
| 260 new File(p.join(testRoot, path)).deleteSync(); | 270 new File(p.join(testRoot, path)).deleteSync(); |
| 261 } | 271 } |
| 262 | 272 |
| 263 bool checkForUnitTest(String path, String source) { | |
| 264 if (!source.contains("package:unittest")) return false; | |
| 265 | |
| 266 note("${bold(path)} uses unittest package."); | |
| 267 return true; | |
| 268 } | |
| 269 | |
| 270 class Fork { | 273 class Fork { |
| 271 final String twoPath; | 274 final String twoPath; |
| 272 String onePath; | 275 String onePath; |
| 273 String strongPath; | 276 String strongPath; |
| 274 | 277 |
| 275 String get twoSource { | 278 String get twoSource { |
| 276 if (twoPath == null) return null; | 279 if (twoPath == null) return null; |
| 277 if (_twoSource == null) _twoSource = readFile(twoPath); | 280 if (_twoSource == null) _twoSource = readFile(twoPath); |
| 278 return _twoSource; | 281 return _twoSource; |
| 279 } | 282 } |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 291 String get strongSource { | 294 String get strongSource { |
| 292 if (strongPath == null) return null; | 295 if (strongPath == null) return null; |
| 293 if (_strongSource == null) _strongSource = readFile(strongPath); | 296 if (_strongSource == null) _strongSource = readFile(strongPath); |
| 294 return _strongSource; | 297 return _strongSource; |
| 295 } | 298 } |
| 296 | 299 |
| 297 String _strongSource; | 300 String _strongSource; |
| 298 | 301 |
| 299 Fork(this.twoPath); | 302 Fork(this.twoPath); |
| 300 | 303 |
| 301 bool migrate(List<String> todos) { | 304 List<String> migrate() { |
| 302 print("- ${bold(twoPath)}:"); | 305 print("- ${bold(twoPath)}:"); |
| 303 | 306 |
| 304 var todosBefore = todos.length; | 307 var todos = <String>[]; |
| 305 var isMigrated = new File(p.join(testRoot, twoPath)).existsSync(); | 308 var isMigrated = new File(p.join(testRoot, twoPath)).existsSync(); |
| 306 | 309 |
| 307 // If there is a migrated version and it's the same as an unmigrated one, | 310 // If there is a migrated version and it's the same as an unmigrated one, |
| 308 // delete the unmigrated one. | 311 // delete the unmigrated one. |
| 309 if (isMigrated) { | 312 if (isMigrated) { |
| 310 if (onePath != null) { | 313 if (onePath != null) { |
| 311 if (oneSource == twoSource) { | 314 if (oneSource == twoSource) { |
| 312 deleteFile(onePath); | 315 deleteFile(onePath); |
| 313 done("Deleted already-migrated $onePath."); | 316 done("Deleted already-migrated $onePath."); |
| 314 } else { | 317 } else { |
| 315 note("${bold(onePath)} does not match already-migrated " | 318 note("${bold(onePath)} does not match already-migrated " |
| 316 "${bold(twoPath)}."); | 319 "${bold(twoPath)}."); |
| 317 todos.add("Merge ${bold(onePath)} into ${bold(twoPath)}."); | 320 todos.add("Merge from ${bold(onePath)} into this file."); |
| 318 checkForUnitTest(onePath, oneSource); | 321 validateFile(onePath, oneSource); |
| 319 } | 322 } |
| 320 } | 323 } |
| 321 | 324 |
| 322 if (strongPath != null) { | 325 if (strongPath != null) { |
| 323 if (strongSource == twoSource) { | 326 if (strongSource == twoSource) { |
| 324 deleteFile(strongPath); | 327 deleteFile(strongPath); |
| 325 done("Deleted already-migrated ${bold(strongPath)}."); | 328 done("Deleted already-migrated ${bold(strongPath)}."); |
| 326 } else { | 329 } else { |
| 327 note("${bold(strongPath)} does not match already-migrated " | 330 note("${bold(strongPath)} does not match already-migrated " |
| 328 "${bold(twoPath)}."); | 331 "${bold(twoPath)}."); |
| 329 todos.add("Merge ${bold(strongPath)} into ${bold(twoPath)}."); | 332 todos.add("Merge from ${bold(strongPath)} into this file."); |
| 330 checkForUnitTest(strongPath, strongSource); | 333 validateFile(strongPath, strongSource); |
| 331 } | 334 } |
| 332 } | 335 } |
| 333 } else { | 336 } else { |
| 334 // If it only exists in one place, just move it. | 337 // If it only exists in one place, just move it. |
| 335 if (strongPath == null) { | 338 if (strongPath == null) { |
| 336 moveFile(onePath, twoPath); | 339 moveFile(onePath, twoPath); |
| 337 done("Moved from ${bold(onePath)} (no strong mode fork)."); | 340 done("Moved from ${bold(onePath)} (no strong mode fork)."); |
| 338 } else if (onePath == null) { | 341 } else if (onePath == null) { |
| 339 moveFile(strongPath, twoPath); | 342 moveFile(strongPath, twoPath); |
| 340 done("Moved from ${bold(strongPath)} (no 1.0 mode fork)."); | 343 done("Moved from ${bold(strongPath)} (no 1.0 mode fork)."); |
| 341 } else if (oneSource == strongSource) { | 344 } else if (oneSource == strongSource) { |
| 342 // The forks are identical, pick one. | 345 // The forks are identical, pick one. |
| 343 moveFile(onePath, twoPath); | 346 moveFile(onePath, twoPath); |
| 344 deleteFile(strongPath); | 347 deleteFile(strongPath); |
| 345 done("Merged identical forks."); | 348 done("Merged identical forks."); |
| 346 checkForUnitTest(twoPath, oneSource); | 349 validateFile(twoPath, oneSource); |
| 347 } else { | 350 } else { |
| 348 // Otherwise, a manual merge is required. Start with the strong one. | 351 // Otherwise, a manual merge is required. Start with the strong one. |
| 352 print(new File(strongPath).existsSync()); | |
| 349 moveFile(strongPath, twoPath); | 353 moveFile(strongPath, twoPath); |
| 350 done("Moved strong fork, kept 1.0 fork, manual merge required."); | 354 done("Moved strong fork, kept 1.0 fork, manual merge required."); |
| 351 todos.add("Merge ${bold(onePath)} into ${bold(twoPath)}."); | 355 todos.add("Merge from ${bold(onePath)} into this file."); |
| 352 checkForUnitTest(onePath, oneSource); | 356 validateFile(onePath, oneSource); |
| 353 } | 357 } |
| 354 } | 358 } |
| 355 | 359 |
| 356 if (checkForUnitTest(twoPath, twoSource)) { | 360 validateFile(twoPath, twoSource, todos); |
| 357 todos.add("Migrate ${bold(twoPath)} off unittest."); | |
| 358 } | |
| 359 | 361 |
| 360 return todos.length == todosBefore; | 362 return todos; |
| 361 } | 363 } |
| 362 } | 364 } |
| OLD | NEW |