OLD | NEW |
(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 import 'package:path/path.dart' as p; |
| 6 |
| 7 import 'editable_status_file.dart'; |
| 8 import 'fork.dart'; |
| 9 import 'io.dart'; |
| 10 import 'test_directories.dart'; |
| 11 |
| 12 /// Migrates the status file entries that match [files]. |
| 13 void migrateStatusEntries(List<Fork> files) { |
| 14 var entriesToMove = new EntrySet(); |
| 15 |
| 16 _collectEntries(files, entriesToMove, isOne: true); |
| 17 _collectEntries(files, entriesToMove, isOne: false); |
| 18 |
| 19 for (var statusFile in entriesToMove.statusFiles) { |
| 20 var sections = entriesToMove.sections(statusFile); |
| 21 _addEntries(statusFile, sections); |
| 22 } |
| 23 |
| 24 // TODO(rnystrom): Should this log any output? |
| 25 } |
| 26 |
| 27 /// Tracks a set of entries to add to a set of Dart 2.0 status files. |
| 28 class EntrySet { |
| 29 /// 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 |
| 31 /// of entries to add under that section. |
| 32 final Map<String, Map<String, List<String>>> _files = {}; |
| 33 |
| 34 Iterable<String> get statusFiles => _files.keys; |
| 35 |
| 36 void add(String fromDir, String header, String entry) { |
| 37 var toDir = toTwoDirectory(fromDir); |
| 38 var sections = _files.putIfAbsent(p.join(toDir, "$toDir.status"), () => {}); |
| 39 var entries = sections.putIfAbsent(header, () => []); |
| 40 entries.add(entry); |
| 41 } |
| 42 |
| 43 Map<String, List<String>> sections(String file) => _files[file]; |
| 44 } |
| 45 |
| 46 /// Removes entries from the 1.0 and strong status files that correspond to |
| 47 /// the list of [files] being migrated. |
| 48 /// |
| 49 /// Adds moved entries to [entriesToMove]. |
| 50 void _collectEntries(List<Fork> files, EntrySet entriesToMove, {bool isOne}) { |
| 51 // Map the files to the way they will appear in the status file. |
| 52 var filePaths = files |
| 53 .map((fork) => p.withoutExtension(isOne ? fork.onePath : fork.strongPath)) |
| 54 .toList(); |
| 55 |
| 56 for (var fromDir in isOne ? oneRootDirs : strongRootDirs) { |
| 57 for (var path in listFiles(fromDir, extension: ".status")) { |
| 58 var editable = new EditableStatusFile(path); |
| 59 |
| 60 var deleteLines = <int>[]; |
| 61 for (var section in editable.statusFile.sections) { |
| 62 // 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? |
| 64 if (section.condition == null) continue; |
| 65 |
| 66 for (var entry in section.entries) { |
| 67 var entryPath = p.join(fromDir, entry.path); |
| 68 |
| 69 for (var filePath in filePaths) { |
| 70 // We only support entries that precisely match the file being |
| 71 // 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 |
| 73 // directory or glob patterns because those may also match other |
| 74 // files that have not been migrated yet. |
| 75 // 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 |
| 77 // manually handle it. |
| 78 if (!entryPath.startsWith(filePath)) continue; |
| 79 |
| 80 // Remove it from this status file. |
| 81 deleteLines.add(entry.lineNumber - 1); |
| 82 |
| 83 // And add it to the 2.0 one. |
| 84 entriesToMove.add(fromDir, editable.lineAt(section.lineNumber), |
| 85 editable.lineAt(entry.lineNumber)); |
| 86 } |
| 87 } |
| 88 } |
| 89 |
| 90 // TODO(rnystrom): If all of the entries are deleted from a section, it |
| 91 // would be nice to delete the section header too. |
| 92 editable.delete(deleteLines); |
| 93 } |
| 94 } |
| 95 } |
| 96 |
| 97 /// Adds all of [entries] to the status file at [path]. |
| 98 /// |
| 99 /// If the status file already has a section that matches a header in [entries], |
| 100 /// then adds those entries to the end of that section. Otherwise, appends a |
| 101 /// new section to the end of the file. |
| 102 void _addEntries(String path, Map<String, List<String>> entries) { |
| 103 var editable = new EditableStatusFile(p.join(testRoot, path)); |
| 104 |
| 105 for (var header in entries.keys) { |
| 106 var found = false; |
| 107 |
| 108 // Look for an existing section with the same header to add it to. |
| 109 for (var section in editable.statusFile.sections) { |
| 110 if (header == editable.lineAt(section.lineNumber)) { |
| 111 var line = section.lineNumber; |
| 112 // Add after existing entries, if there are any. |
| 113 if (section.entries.isNotEmpty) { |
| 114 line = section.entries.last.lineNumber; |
| 115 } |
| 116 |
| 117 editable.insert(line, entries[header]); |
| 118 found = true; |
| 119 break; |
| 120 } |
| 121 } |
| 122 |
| 123 if (!found) { |
| 124 // This section doesn't exist in the status file, so add it. |
| 125 editable.append(header, entries[header]); |
| 126 } |
| 127 } |
| 128 } |
OLD | NEW |