Chromium Code Reviews| 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 'dart:io'; | |
| 6 | |
| 7 import 'path.dart'; | |
| 8 | |
| 9 /// Matches the header that begins a new section, like: | |
|
jcollins
2017/07/24 18:24:51
There should probably be a TODO here to merge this
bkonyi
2017/07/24 19:16:04
Do you mean with tools/testing/dart/status_file.da
| |
| 10 /// | |
| 11 /// [ $compiler == dart2js && $minified ] | |
| 12 final _sectionPattern = new RegExp(r"^\[(.+?)\]"); | |
| 13 | |
| 14 /// Matches an entry that defines the status for a path in the current section, | |
| 15 /// like: | |
| 16 /// | |
| 17 /// some/path/to/some_test: Pass || Fail | |
| 18 final _entryPattern = new RegExp(r"^([^:#]+):(.*)"); | |
| 19 | |
| 20 /// Matches an issue number in a comment, like: | |
| 21 /// | |
| 22 /// blah_test: Fail # Issue 1234 | |
| 23 /// ^^^^ | |
| 24 final _issuePattern = new RegExp(r"[Ii]ssue (\d+)"); | |
| 25 | |
| 26 /// A parsed status file, which describes how a collection of tests are | |
| 27 /// expected to behave under various configurations and conditions. | |
| 28 /// | |
| 29 /// Each status file is made of a series of sections. Each section begins with | |
| 30 /// a header, followed by a series of entries. A header is enclosed in square | |
| 31 /// brackets and contains a Boolean expression. That expression is evaluated in | |
| 32 /// an environment. If it evaluates to true, then the entries after the header | |
| 33 /// take effect. | |
| 34 /// | |
| 35 /// Each entry is a glob-like file path followed by a colon and then a | |
| 36 /// comma-separated list of expectations. The path may point to an individual | |
| 37 /// file, or a directory, in which case it applies to all files under that path. | |
| 38 /// | |
| 39 /// Entries may also appear before any section header, in which case they | |
| 40 /// always apply. | |
| 41 class StatusFile { | |
| 42 final String path; | |
| 43 final List<StatusSection> sections = []; | |
| 44 | |
| 45 bool get isEmpty => sections.isEmpty; | |
| 46 | |
| 47 StatusFile(this.path); | |
| 48 | |
| 49 /// Parses the status file at [_path]. | |
| 50 StatusFile.read(this.path) { | |
| 51 var lines = new File(path).readAsLinesSync(); | |
| 52 | |
| 53 // The current section whose rules are being parsed. | |
| 54 StatusSection section; | |
| 55 | |
| 56 var lineNumber = 0; | |
| 57 | |
| 58 for (var line in lines) { | |
| 59 lineNumber++; | |
| 60 | |
| 61 fail(String message, [List<String> errors]) { | |
| 62 print('$message in "$_shortPath" line $lineNumber:\n$line'); | |
| 63 | |
| 64 if (errors != null) { | |
| 65 for (var error in errors) { | |
| 66 print("- ${error.replaceAll('\n', '\n ')}"); | |
| 67 } | |
| 68 } | |
| 69 exit(1); | |
| 70 } | |
| 71 | |
| 72 // Strip off the comment and whitespace. | |
| 73 var source = line; | |
| 74 var comment = ""; | |
| 75 var hashIndex = line.indexOf('#'); | |
| 76 if (hashIndex >= 0) { | |
| 77 source = line.substring(0, hashIndex); | |
| 78 comment = line.substring(hashIndex); | |
| 79 } | |
| 80 source = source.trim(); | |
| 81 // Ignore empty (or comment-only) lines. | |
| 82 if (source.isEmpty) continue; | |
| 83 | |
| 84 // See if we are starting a new section. | |
| 85 var match = _sectionPattern.firstMatch(source); | |
| 86 if (match != null) { | |
| 87 var condition = match[1].trim(); | |
| 88 section = new StatusSection(condition); | |
| 89 sections.add(section); | |
| 90 continue; | |
| 91 } | |
| 92 | |
| 93 // Otherwise, it should be a new entry under the current section. | |
| 94 match = _entryPattern.firstMatch(source); | |
| 95 if (match != null) { | |
| 96 // If we haven't found a section header yet, create an implicit section | |
| 97 // that matches everything. | |
| 98 if (section == null) { | |
| 99 section = new StatusSection(null); | |
| 100 sections.add(section); | |
| 101 } | |
| 102 if (!comment.isEmpty) { | |
| 103 source += " $comment"; | |
| 104 } | |
| 105 section.entries.add(source); | |
| 106 continue; | |
| 107 } | |
| 108 | |
| 109 fail("Unrecognized input"); | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 /// Gets the path to this status file relative to the Dart repo root. | |
| 114 String get _shortPath { | |
| 115 var repoRoot = new Path(Platform.script | |
| 116 .toFilePath(windows: Platform.operatingSystem == "windows")) | |
| 117 .join(new Path("../../../../")); | |
| 118 return new Path(_path).relativeTo(repoRoot).toString(); | |
| 119 } | |
| 120 | |
| 121 String toString() { | |
| 122 var buffer = new StringBuffer(); | |
| 123 for (var section in sections) { | |
| 124 buffer.writeln("[${section.condition}]"); | |
| 125 for (var entry in section.entries) { | |
| 126 buffer.writeln(entry.replaceAll("\n", " ")); | |
| 127 } | |
| 128 buffer.writeln(); | |
| 129 } | |
| 130 return buffer.toString(); | |
| 131 } | |
| 132 } | |
| 133 | |
| 134 /// One section in a status file. | |
| 135 /// | |
| 136 /// Contains the condition from the header that begins the section, then all of | |
| 137 /// the entries within the section. | |
| 138 class StatusSection { | |
| 139 /// In that case, the section always applies. | |
| 140 final String condition; | |
| 141 final List<String> entries = []; | |
| 142 | |
| 143 StatusSection(this.condition); | |
| 144 | |
| 145 String toString() { | |
| 146 var buffer = new StringBuffer(); | |
| 147 buffer.writeln("[$condition]"); | |
| 148 for (var entry in entries) { | |
| 149 buffer.writeln(entry); | |
| 150 } | |
| 151 buffer.writeln(); | |
| 152 return buffer.toString(); | |
| 153 } | |
| 154 } | |
| OLD | NEW |