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 import 'package:path/path.dart' as p; | 5 import 'package:path/path.dart' as p; |
| 6 | 6 |
| 7 import 'editable_status_file.dart'; | 7 import 'editable_status_file.dart'; |
| 8 import 'fork.dart'; | 8 import 'fork.dart'; |
| 9 import 'io.dart'; | 9 import 'io.dart'; |
| 10 import 'log.dart'; | |
| 10 import 'test_directories.dart'; | 11 import 'test_directories.dart'; |
| 11 | 12 |
| 12 /// Migrates the status file entries that match [files]. | 13 /// Migrates the status file entries that match [files]. |
| 13 void migrateStatusEntries(List<Fork> files) { | 14 void migrateStatusEntries(List<Fork> files, Map<String, List<String>> todos) { |
| 14 var entriesToMove = new EntrySet(); | 15 var entriesToMove = new EntrySet(); |
| 15 | 16 |
| 16 _collectEntries(files, entriesToMove, isOne: true); | 17 _collectEntries(files, entriesToMove, isOne: true); |
| 17 _collectEntries(files, entriesToMove, isOne: false); | 18 _collectEntries(files, entriesToMove, isOne: false); |
| 18 | 19 |
| 19 for (var statusFile in entriesToMove.statusFiles) { | 20 for (var statusFile in entriesToMove.statusFiles) { |
| 20 var sections = entriesToMove.sections(statusFile); | 21 var sections = entriesToMove.sections(statusFile); |
| 21 _addEntries(statusFile, sections); | 22 _addEntries(statusFile, sections); |
| 22 } | 23 } |
| 23 | 24 |
| 24 // TODO(rnystrom): Should this log any output? | 25 // If any entries need manual splitting, let the user know. |
| 26 for (var dir in entriesToMove._todoHeaders.keys) { | |
| 27 var destination = "$dir.status"; | |
| 28 var headers = entriesToMove._todoHeaders[dir]; | |
| 29 var splits = headers.map((header) { | |
| 30 var files = | |
| 31 filesForHeader(header).map((file) => bold("${dir}_$file")).join(", "); | |
| 32 return "Need to manually split status file section in ${bold(destination)} " | |
| 33 " across files $files:\n $header"; | |
| 34 }).toList(); | |
| 35 | |
| 36 if (splits.isNotEmpty) todos[destination] = splits; | |
| 37 } | |
| 38 } | |
| 39 | |
| 40 /// Given the header for a status file section, looks at the condition | |
| 41 /// expression to determine which status files it should go in. | |
| 42 Set<String> filesForHeader(String header) { | |
| 43 // Figure out which status file it goes into. | |
| 44 var result = new Set<String>(); | |
| 45 | |
| 46 // The various compilers are roughly separate products. | |
| 47 const compilers = const { | |
| 48 r"$compiler == dart2analyzer": "analyzer", | |
| 49 r"$compiler == dart2js": "dart2js", | |
| 50 r"$compiler == dartdevc": "dartdevc", | |
| 51 // This deliberately matches both dartk and dartkp. | |
| 52 r"$compiler == dartk": "kernel", | |
| 53 r"$compiler == precompiler": "precompiled" | |
| 54 }; | |
| 55 | |
| 56 // TODO(rnystrom): This is obviously very sensitive to the formatting of | |
| 57 // the expression. Hacky, but hopefully good enough for now. | |
| 58 compilers.forEach((compiler, file) { | |
| 59 if (header.contains(compiler)) result.add(file); | |
| 60 }); | |
| 61 | |
| 62 // If we couldn't figure out where to put it based on the compiler, look at | |
| 63 // the runtime. | |
| 64 if (result.isEmpty) { | |
| 65 const runtimes = const { | |
| 66 r"$runtime == vm": "vm", | |
| 67 r"$runtime == flutter": "flutter", | |
| 68 r"$runtime == dart_precompiled": "precompiled", | |
| 69 }; | |
| 70 | |
| 71 runtimes.forEach((runtime, file) { | |
| 72 if (header.contains(runtime)) result.add(file); | |
| 73 }); | |
| 74 } | |
| 75 | |
| 76 return result; | |
| 25 } | 77 } |
| 26 | 78 |
| 27 /// Tracks a set of entries to add to a set of Dart 2.0 status files. | 79 /// Tracks a set of entries to add to a set of Dart 2.0 status files. |
| 28 class EntrySet { | 80 class EntrySet { |
| 29 /// Keys are the names of the Dart 2.0 status file that will receive the | 81 /// Keys are the names of the Dart 2.0 status file that will receive the |
| 30 /// entries. The value for each key is a map of section headers to the list | 82 /// entries. The value for each key is a map of section headers to the list |
| 31 /// of entries to add under that section. | 83 /// of entries to add under that section. |
| 32 final Map<String, Map<String, List<String>>> _files = {}; | 84 final Map<String, Map<String, List<String>>> _files = {}; |
| 33 | 85 |
| 86 final _todoHeaders = <String, Set<String>>{}; | |
| 87 | |
| 34 Iterable<String> get statusFiles => _files.keys; | 88 Iterable<String> get statusFiles => _files.keys; |
| 35 | 89 |
| 36 void add(String fromDir, String header, String entry) { | 90 bool add(String fromDir, String header, String entry) { |
|
jcollins
2017/08/04 16:55:56
might be nice to have a comment: /// Returns true
Bob Nystrom
2017/08/04 17:33:02
Done.
| |
| 37 var toDir = toTwoDirectory(fromDir); | 91 var toDir = toTwoDirectory(fromDir); |
| 38 var sections = _files.putIfAbsent(p.join(toDir, "$toDir.status"), () => {}); | 92 |
| 93 // Figure out which status file it goes into. | |
| 94 var possibleFiles = filesForHeader(header); | |
| 95 var destination = "$toDir.status"; | |
| 96 | |
| 97 if (possibleFiles.length > 1) { | |
| 98 // The condition matches multiple files, so the user is going to have to | |
| 99 // manually split it up into multiple sections first. | |
| 100 // TODO(rnystrom): Would be good to automate this, though it requires | |
| 101 // being able to work with condition expressions directly. | |
| 102 _todoHeaders.putIfAbsent(toDir, () => new Set()).add(header); | |
| 103 return false; | |
| 104 } | |
| 105 | |
| 106 // If the condition places it directly into one file, put it there. | |
| 107 if (possibleFiles.length == 1) { | |
| 108 destination = "${toDir}_${possibleFiles.single}.status"; | |
| 109 } | |
| 110 | |
| 111 var sections = _files.putIfAbsent(p.join(toDir, destination), () => {}); | |
| 112 | |
| 39 var entries = sections.putIfAbsent(header, () => []); | 113 var entries = sections.putIfAbsent(header, () => []); |
| 40 entries.add(entry); | 114 entries.add(entry); |
| 115 return true; | |
| 41 } | 116 } |
| 42 | 117 |
| 43 Map<String, List<String>> sections(String file) => _files[file]; | 118 Map<String, List<String>> sections(String file) => _files[file]; |
| 44 } | 119 } |
| 45 | 120 |
| 46 /// Removes entries from the 1.0 and strong status files that correspond to | 121 /// Removes entries from the 1.0 and strong status files that correspond to |
| 47 /// the list of [files] being migrated. | 122 /// the list of [files] being migrated. |
| 48 /// | 123 /// |
| 49 /// Adds moved entries to [entriesToMove]. | 124 /// Adds moved entries to [entriesToMove]. |
| 50 void _collectEntries(List<Fork> files, EntrySet entriesToMove, {bool isOne}) { | 125 void _collectEntries(List<Fork> files, EntrySet entriesToMove, {bool isOne}) { |
| 51 // Map the files to the way they will appear in the status file. | 126 // Map the files to the way they will appear in the status file. |
| 52 var filePaths = files | 127 var filePaths = files |
| 53 .map((fork) => p.withoutExtension(isOne ? fork.onePath : fork.strongPath)) | 128 .map((fork) => p.withoutExtension(isOne ? fork.onePath : fork.strongPath)) |
| 54 .toList(); | 129 .toList(); |
| 55 | 130 |
| 56 for (var fromDir in isOne ? oneRootDirs : strongRootDirs) { | 131 for (var fromDir in isOne ? oneRootDirs : strongRootDirs) { |
| 57 for (var path in listFiles(fromDir, extension: ".status")) { | 132 for (var path in listFiles(fromDir, extension: ".statustemp")) { |
|
jcollins
2017/08/04 16:55:56
was this a temporary change?
Bob Nystrom
2017/08/04 17:33:01
Oops, yes! Fixed.
| |
| 58 var editable = new EditableStatusFile(path); | 133 var editable = new EditableStatusFile(path); |
| 59 | 134 |
| 60 var deleteLines = <int>[]; | 135 var deleteLines = <int>[]; |
| 61 for (var section in editable.statusFile.sections) { | 136 for (var section in editable.statusFile.sections) { |
| 62 // TODO(rnystrom): For now, we don't support entries in the initial | 137 // TODO(rnystrom): For now, we don't support entries in the initial |
| 63 // implicit section at the top of the file. Do we need to? | 138 // implicit section at the top of the file. Do we need to? |
| 64 if (section.condition == null) continue; | 139 if (section.condition == null) continue; |
| 65 | 140 |
| 66 for (var entry in section.entries) { | 141 for (var entry in section.entries) { |
| 67 var entryPath = p.join(fromDir, entry.path); | 142 var entryPath = p.join(fromDir, entry.path); |
| 68 | 143 |
| 69 for (var filePath in filePaths) { | 144 for (var filePath in filePaths) { |
| 70 // We only support entries that precisely match the file being | 145 // We only support entries that precisely match the file being |
| 71 // migrated, or a multitest within that. In both cases, the entry | 146 // migrated, or a multitest within that. In both cases, the entry |
| 72 // path will begin with the full path of the file. We don't migrate | 147 // path will begin with the full path of the file. We don't migrate |
| 73 // directory or glob patterns because those may also match other | 148 // directory or glob patterns because those may also match other |
| 74 // files that have not been migrated yet. | 149 // files that have not been migrated yet. |
| 75 // TODO(rnystrom): It would be good to detect when a glob matches | 150 // TODO(rnystrom): It would be good to detect when a glob matches |
| 76 // a migrated file and let the user know that they may need to | 151 // a migrated file and let the user know that they may need to |
| 77 // manually handle it. | 152 // manually handle it. |
| 78 if (!entryPath.startsWith(filePath)) continue; | 153 if (!entryPath.startsWith(filePath)) continue; |
| 79 | 154 |
| 80 // Remove it from this status file. | 155 // Add it to the 2.0 one. |
| 81 deleteLines.add(entry.lineNumber - 1); | 156 if (entriesToMove.add(fromDir, editable.lineAt(section.lineNumber), |
| 82 | 157 editable.lineAt(entry.lineNumber))) { |
| 83 // And add it to the 2.0 one. | 158 // Remove it from the original status file. |
| 84 entriesToMove.add(fromDir, editable.lineAt(section.lineNumber), | 159 deleteLines.add(entry.lineNumber - 1); |
| 85 editable.lineAt(entry.lineNumber)); | 160 } |
| 86 } | 161 } |
| 87 } | 162 } |
| 88 } | 163 } |
| 89 | 164 |
| 90 // TODO(rnystrom): If all of the entries are deleted from a section, it | 165 // TODO(rnystrom): If all of the entries are deleted from a section, it |
| 91 // would be nice to delete the section header too. | 166 // would be nice to delete the section header too. |
| 92 editable.delete(deleteLines); | 167 editable.delete(deleteLines); |
| 93 } | 168 } |
| 94 } | 169 } |
| 95 } | 170 } |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 119 break; | 194 break; |
| 120 } | 195 } |
| 121 } | 196 } |
| 122 | 197 |
| 123 if (!found) { | 198 if (!found) { |
| 124 // This section doesn't exist in the status file, so add it. | 199 // This section doesn't exist in the status file, so add it. |
| 125 editable.append(header, entries[header]); | 200 editable.append(header, entries[header]); |
| 126 } | 201 } |
| 127 } | 202 } |
| 128 } | 203 } |
| OLD | NEW |