| 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 'dart:io'; | 5 import 'dart:io'; |
| 6 | 6 |
| 7 import 'package:path/path.dart' as p; | 7 import 'package:path/path.dart' as p; |
| 8 | 8 |
| 9 import 'environment.dart'; | 9 import 'environment.dart'; |
| 10 import 'expectation.dart'; | 10 import 'expectation.dart'; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 /// an environment. If it evaluates to true, then the entries after the header | 36 /// an environment. If it evaluates to true, then the entries after the header |
| 37 /// take effect. | 37 /// take effect. |
| 38 /// | 38 /// |
| 39 /// Each entry is a glob-like file path followed by a colon and then a | 39 /// Each entry is a glob-like file path followed by a colon and then a |
| 40 /// comma-separated list of [Expectation]s. The path may point to an individual | 40 /// comma-separated list of [Expectation]s. The path may point to an individual |
| 41 /// file, or a directory, in which case it applies to all files under that path. | 41 /// file, or a directory, in which case it applies to all files under that path. |
| 42 /// | 42 /// |
| 43 /// Entries may also appear before any section header, in which case they | 43 /// Entries may also appear before any section header, in which case they |
| 44 /// always apply. | 44 /// always apply. |
| 45 class StatusFile { | 45 class StatusFile { |
| 46 final String _path; | 46 final String path; |
| 47 final List<StatusSection> sections = []; | 47 final List<StatusSection> sections = []; |
| 48 | 48 |
| 49 /// Parses the status file at [_path]. | 49 StatusFile(this.path); |
| 50 |
| 51 /// Parses the status file at [path]. |
| 50 /// | 52 /// |
| 51 /// Throws a [SyntaxError] if the file could not be parsed. | 53 /// Throws a [SyntaxError] if the file could not be parsed. |
| 52 StatusFile.read(this._path) { | 54 StatusFile.read(this.path) { |
| 53 var lines = new File(_path).readAsLinesSync(); | 55 var lines = new File(path).readAsLinesSync(); |
| 54 | 56 |
| 55 // The current section whose rules are being parsed. | 57 // The current section whose rules are being parsed. |
| 56 StatusSection section; | 58 StatusSection section; |
| 57 | 59 |
| 58 var lineNumber = 0; | 60 var lineNumber = 0; |
| 59 | 61 |
| 60 for (var line in lines) { | 62 for (var line in lines) { |
| 61 lineNumber++; | 63 lineNumber++; |
| 62 | 64 |
| 63 fail(String message, [List<String> errors]) { | 65 fail(String message, [List<String> errors]) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 } | 116 } |
| 115 | 117 |
| 116 section.entries.add(new StatusEntry(path, expectations, issue)); | 118 section.entries.add(new StatusEntry(path, expectations, issue)); |
| 117 continue; | 119 continue; |
| 118 } | 120 } |
| 119 | 121 |
| 120 fail("Unrecognized input"); | 122 fail("Unrecognized input"); |
| 121 } | 123 } |
| 122 } | 124 } |
| 123 | 125 |
| 126 bool get isEmpty => sections.isEmpty; |
| 127 |
| 124 /// Validates that the variables and values used in all of the section | 128 /// Validates that the variables and values used in all of the section |
| 125 /// condition expressions are defined in [environment]. | 129 /// condition expressions are defined in [environment]. |
| 126 /// | 130 /// |
| 127 /// Throws a [SyntaxError] on the first found error. | 131 /// Throws a [SyntaxError] on the first found error. |
| 128 void validate(Environment environment) { | 132 void validate(Environment environment) { |
| 129 // TODO(rnystrom): It would be more useful if it reported all of the errors | 133 // TODO(rnystrom): It would be more useful if it reported all of the errors |
| 130 // instead of stopping on the first. | 134 // instead of stopping on the first. |
| 131 for (var section in sections) { | 135 for (var section in sections) { |
| 132 if (section._condition == null) continue; | 136 if (section.condition == null) continue; |
| 133 | 137 |
| 134 var errors = <String>[]; | 138 var errors = <String>[]; |
| 135 section._condition.validate(environment, errors); | 139 section.condition.validate(environment, errors); |
| 136 | 140 |
| 137 if (errors.isNotEmpty) { | 141 if (errors.isNotEmpty) { |
| 138 var s = errors.length > 1 ? "s" : ""; | 142 var s = errors.length > 1 ? "s" : ""; |
| 139 throw new SyntaxError(_shortPath, section.lineNumber, | 143 throw new SyntaxError(_shortPath, section.lineNumber, |
| 140 "[ ${section._condition} ]", 'Validation error$s', errors); | 144 "[ ${section.condition} ]", 'Validation error$s', errors); |
| 141 } | 145 } |
| 142 } | 146 } |
| 143 } | 147 } |
| 144 | 148 |
| 145 /// Gets the path to this status file relative to the Dart repo root. | 149 /// Gets the path to this status file relative to the Dart repo root. |
| 146 String get _shortPath { | 150 String get _shortPath { |
| 147 var repoRoot = p.join(p.dirname(p.fromUri(Platform.script)), "../../../"); | 151 var repoRoot = p.join(p.dirname(p.fromUri(Platform.script)), "../../../"); |
| 148 return p.normalize(p.relative(_path, from: repoRoot)); | 152 return p.normalize(p.relative(path, from: repoRoot)); |
| 149 } | 153 } |
| 150 | 154 |
| 151 /// Returns the issue number embedded in [comment] or `null` if there is none. | 155 /// Returns the issue number embedded in [comment] or `null` if there is none. |
| 152 int _issueNumber(String comment) { | 156 int _issueNumber(String comment) { |
| 153 var match = _issuePattern.firstMatch(comment); | 157 var match = _issuePattern.firstMatch(comment); |
| 154 if (match == null) return null; | 158 if (match == null) return null; |
| 155 | 159 |
| 156 return int.parse(match[1]); | 160 return int.parse(match[1]); |
| 157 } | 161 } |
| 158 | 162 |
| 159 String toString() { | 163 String toString() { |
| 160 var buffer = new StringBuffer(); | 164 var buffer = new StringBuffer(); |
| 161 for (var section in sections) { | 165 for (var section in sections) { |
| 162 buffer.writeln("[ ${section._condition} ]"); | 166 buffer.writeln("[ ${section.condition} ]"); |
| 163 | 167 |
| 164 for (var entry in section.entries) { | 168 for (var entry in section.entries) { |
| 165 buffer.write("${entry.path}: ${entry.expectations.join(', ')}"); | 169 buffer.write("${entry.path}: ${entry.expectations.join(', ')}"); |
| 166 if (entry.issue != null) buffer.write(" # Issue ${entry.issue}"); | 170 if (entry.issue != null) buffer.write(" # Issue ${entry.issue}"); |
| 167 buffer.writeln(); | 171 buffer.writeln(); |
| 168 } | 172 } |
| 169 | 173 |
| 170 buffer.writeln(); | 174 buffer.writeln(); |
| 171 } | 175 } |
| 172 | 176 |
| 173 return buffer.toString(); | 177 return buffer.toString(); |
| 174 } | 178 } |
| 175 } | 179 } |
| 176 | 180 |
| 177 /// One section in a status file. | 181 /// One section in a status file. |
| 178 /// | 182 /// |
| 179 /// Contains the condition from the header that begins the section, then all of | 183 /// Contains the condition from the header that begins the section, then all of |
| 180 /// the entries within the section. | 184 /// the entries within the section. |
| 181 class StatusSection { | 185 class StatusSection { |
| 182 /// The expression that determines when this section is applied. | 186 /// The expression that determines when this section is applied. |
| 183 /// | 187 /// |
| 184 /// May be `null` for paths that appear before any section header in the file. | 188 /// May be `null` for paths that appear before any section header in the file. |
| 185 /// In that case, the section always applies. | 189 /// In that case, the section always applies. |
| 186 final Expression _condition; | 190 final Expression condition; |
| 187 final List<StatusEntry> entries = []; | 191 final List<StatusEntry> entries = []; |
| 188 | 192 |
| 189 /// Returns true if this section should apply in the given [environment]. | 193 /// Returns true if this section should apply in the given [environment]. |
| 190 bool isEnabled(Environment environment) => | 194 bool isEnabled(Environment environment) => |
| 191 _condition == null || _condition.evaluate(environment); | 195 condition == null || condition.evaluate(environment); |
| 192 | 196 |
| 193 StatusSection(this._condition); | 197 StatusSection(this.condition); |
| 194 } | 198 } |
| 195 | 199 |
| 196 /// Describes the test status of the file or files at a given path. | 200 /// Describes the test status of the file or files at a given path. |
| 197 class StatusEntry { | 201 class StatusEntry { |
| 198 final String path; | 202 final String path; |
| 199 final List<Expectation> expectations; | 203 final List<Expectation> expectations; |
| 200 final int issue; | 204 final int issue; |
| 201 | 205 |
| 202 StatusEntry(this.path, this.expectations, this.issue); | 206 StatusEntry(this.path, this.expectations, this.issue); |
| 203 } | 207 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 219 | 223 |
| 220 if (errors != null) { | 224 if (errors != null) { |
| 221 for (var error in errors) { | 225 for (var error in errors) { |
| 222 buffer.writeln("- ${error.replaceAll('\n', '\n ')}"); | 226 buffer.writeln("- ${error.replaceAll('\n', '\n ')}"); |
| 223 } | 227 } |
| 224 } | 228 } |
| 225 | 229 |
| 226 return buffer.toString().trimRight(); | 230 return buffer.toString().trimRight(); |
| 227 } | 231 } |
| 228 } | 232 } |
| OLD | NEW |