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 |