| OLD | NEW | 
|---|
| 1 // Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file | 1 // Copyright (c) 2016, 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:boolean_selector/boolean_selector.dart'; | 7 import 'package:boolean_selector/boolean_selector.dart'; | 
| 8 import 'package:glob/glob.dart'; | 8 import 'package:glob/glob.dart'; | 
| 9 import 'package:path/path.dart' as p; | 9 import 'package:path/path.dart' as p; | 
| 10 import 'package:source_span/source_span.dart'; | 10 import 'package:source_span/source_span.dart'; | 
| 11 import 'package:yaml/yaml.dart'; | 11 import 'package:yaml/yaml.dart'; | 
| 12 | 12 | 
| 13 import '../../backend/operating_system.dart'; | 13 import '../../backend/operating_system.dart'; | 
| 14 import '../../backend/platform_selector.dart'; | 14 import '../../backend/platform_selector.dart'; | 
| 15 import '../../backend/test_platform.dart'; | 15 import '../../backend/test_platform.dart'; | 
| 16 import '../../frontend/timeout.dart'; | 16 import '../../frontend/timeout.dart'; | 
| 17 import '../../utils.dart'; | 17 import '../../utils.dart'; | 
| 18 import '../../util/io.dart'; | 18 import '../../util/io.dart'; | 
| 19 import '../configuration.dart'; | 19 import '../configuration.dart'; | 
| 20 import 'values.dart'; | 20 import 'values.dart'; | 
| 21 | 21 | 
| 22 /// Loads configuration information from a YAML file at [path]. | 22 /// Loads configuration information from a YAML file at [path]. | 
| 23 /// | 23 /// | 
| 24 /// Throws a [FormatException] if the configuration is invalid, and a | 24 /// Throws a [FormatException] if the configuration is invalid, and a | 
| 25 /// [FileSystemException] if it can't be read. | 25 /// [FileSystemException] if it can't be read. | 
| 26 Configuration load(String path) { | 26 Configuration load(String path) { | 
| 27   var source = new File(path).readAsStringSync(); | 27   var source = new File(path).readAsStringSync(); | 
| 28   var document = loadYamlNode(source, sourceUrl: p.toUri(path)); | 28   var document = loadYamlNode(source, sourceUrl: p.toUri(path)); | 
| 29 | 29 | 
| 30   if (document.value == null) return new Configuration(); | 30   if (document.value == null) return Configuration.empty; | 
| 31 | 31 | 
| 32   if (document is! Map) { | 32   if (document is! Map) { | 
| 33     throw new SourceSpanFormatException( | 33     throw new SourceSpanFormatException( | 
| 34         "The configuration must be a YAML map.", document.span, source); | 34         "The configuration must be a YAML map.", document.span, source); | 
| 35   } | 35   } | 
| 36 | 36 | 
| 37   var loader = new _ConfigurationLoader(document, source); | 37   var loader = new _ConfigurationLoader(document, source); | 
| 38   return loader.load(); | 38   return loader.load(); | 
| 39 } | 39 } | 
| 40 | 40 | 
| (...skipping 27 matching lines...) Expand all  Loading... | 
| 68     if (skip is String) { | 68     if (skip is String) { | 
| 69       skipReason = skip; | 69       skipReason = skip; | 
| 70       skip = true; | 70       skip = true; | 
| 71     } | 71     } | 
| 72 | 72 | 
| 73     var testOn = _parseValue("test_on", | 73     var testOn = _parseValue("test_on", | 
| 74         (value) => new PlatformSelector.parse(value)); | 74         (value) => new PlatformSelector.parse(value)); | 
| 75 | 75 | 
| 76     var timeout = _parseValue("timeout", (value) => new Timeout.parse(value)); | 76     var timeout = _parseValue("timeout", (value) => new Timeout.parse(value)); | 
| 77 | 77 | 
| 78     var addTags = _getList("add_tags", (tagNode) { | 78     var addTags = _getList("add_tags", | 
| 79       _validate(tagNode, "Tags must be strings.", (value) => value is String); | 79         (tagNode) => _parseIdentifierLike(tagNode, "Tag name")); | 
| 80       _validate( |  | 
| 81           tagNode, |  | 
| 82           "Invalid tag. Tags must be (optionally hyphenated) Dart identifiers.", |  | 
| 83           (value) => value.contains(anchoredHyphenatedIdentifier)); |  | 
| 84       return tagNode.value; |  | 
| 85     }); |  | 
| 86 | 80 | 
| 87     var tags = _getMap("tags", | 81     var tags = _getMap("tags", | 
| 88         key: (keyNode) => _parseNode(keyNode, "tags key", | 82         key: (keyNode) => _parseNode(keyNode, "tags key", | 
| 89             (value) => new BooleanSelector.parse(value)), | 83             (value) => new BooleanSelector.parse(value)), | 
| 90         value: (valueNode) => | 84         value: (valueNode) => | 
| 91             _nestedConfig(valueNode, "tag value", runnerConfig: false)); | 85             _nestedConfig(valueNode, "tag value", runnerConfig: false)); | 
| 92 | 86 | 
| 93     var onPlatform = _getMap("on_platform", | 87     var onPlatform = _getMap("on_platform", | 
| 94         key: (keyNode) => _parseNode(keyNode, "on_platform key", | 88         key: (keyNode) => _parseNode(keyNode, "on_platform key", | 
| 95             (value) => new PlatformSelector.parse(value)), | 89             (value) => new PlatformSelector.parse(value)), | 
| 96         value: (valueNode) => | 90         value: (valueNode) => | 
| 97             _nestedConfig(valueNode, "on_platform value", runnerConfig: false)); | 91             _nestedConfig(valueNode, "on_platform value", runnerConfig: false)); | 
| 98 | 92 | 
| 99     var onOS = _getMap("on_os", key: (keyNode) { | 93     var onOS = _getMap("on_os", key: (keyNode) { | 
| 100       _validate(keyNode, "on_os key must be a string.", | 94       _validate(keyNode, "on_os key must be a string.", | 
| 101           (value) => value is String); | 95           (value) => value is String); | 
| 102 | 96 | 
| 103       var os = OperatingSystem.find(keyNode.value); | 97       var os = OperatingSystem.find(keyNode.value); | 
| 104       if (os != null) return os; | 98       if (os != null) return os; | 
| 105 | 99 | 
| 106       throw new SourceSpanFormatException( | 100       throw new SourceSpanFormatException( | 
| 107           'Invalid on_os key: No such operating system.', | 101           'Invalid on_os key: No such operating system.', | 
| 108           keyNode.span, _source); | 102           keyNode.span, _source); | 
| 109     }, value: (valueNode) => _nestedConfig(valueNode, "on_os value")); | 103     }, value: (valueNode) => _nestedConfig(valueNode, "on_os value")); | 
| 110 | 104 | 
|  | 105     var presets = _getMap("presets", | 
|  | 106         key: (keyNode) => _parseIdentifierLike(keyNode, "presets key"), | 
|  | 107         value: (valueNode) => _nestedConfig(valueNode, "presets value")); | 
|  | 108 | 
| 111     var config = new Configuration( | 109     var config = new Configuration( | 
| 112         verboseTrace: verboseTrace, | 110         verboseTrace: verboseTrace, | 
| 113         jsTrace: jsTrace, | 111         jsTrace: jsTrace, | 
| 114         skip: skip, | 112         skip: skip, | 
| 115         skipReason: skipReason, | 113         skipReason: skipReason, | 
| 116         testOn: testOn, | 114         testOn: testOn, | 
| 117         timeout: timeout, | 115         timeout: timeout, | 
| 118         addTags: addTags, | 116         addTags: addTags, | 
| 119         tags: tags, | 117         tags: tags, | 
| 120         onPlatform: onPlatform); | 118         onPlatform: onPlatform, | 
|  | 119         presets: presets); | 
| 121 | 120 | 
| 122     var osConfig = onOS[currentOS]; | 121     var osConfig = onOS[currentOS]; | 
| 123     return osConfig == null ? config : config.merge(osConfig); | 122     return osConfig == null ? config : config.merge(osConfig); | 
| 124   } | 123   } | 
| 125 | 124 | 
| 126   /// Loads runner configuration (but not test configuration). | 125   /// Loads runner configuration (but not test configuration). | 
| 127   /// | 126   /// | 
| 128   /// If [_runnerConfig] is `false`, this will error if there are any | 127   /// If [_runnerConfig] is `false`, this will error if there are any | 
| 129   /// runner-level configuration fields. | 128   /// runner-level configuration fields. | 
| 130   Configuration _loadRunnerConfig() { | 129   Configuration _loadRunnerConfig() { | 
| 131     if (!_runnerConfig) { | 130     if (!_runnerConfig) { | 
| 132       _disallow("reporter"); | 131       _disallow("reporter"); | 
| 133       _disallow("pub_serve"); | 132       _disallow("pub_serve"); | 
| 134       _disallow("concurrency"); | 133       _disallow("concurrency"); | 
| 135       _disallow("platforms"); | 134       _disallow("platforms"); | 
| 136       _disallow("paths"); | 135       _disallow("paths"); | 
| 137       _disallow("filename"); | 136       _disallow("filename"); | 
| 138       return new Configuration(); | 137       _disallow("add_presets"); | 
|  | 138       return Configuration.empty; | 
| 139     } | 139     } | 
| 140 | 140 | 
| 141     var reporter = _getString("reporter"); | 141     var reporter = _getString("reporter"); | 
| 142     if (reporter != null && !allReporters.contains(reporter)) { | 142     if (reporter != null && !allReporters.contains(reporter)) { | 
| 143       _error('Unknown reporter "$reporter".', "reporter"); | 143       _error('Unknown reporter "$reporter".', "reporter"); | 
| 144     } | 144     } | 
| 145 | 145 | 
| 146     var pubServePort = _getInt("pub_serve"); | 146     var pubServePort = _getInt("pub_serve"); | 
| 147     var concurrency = _getInt("concurrency"); | 147     var concurrency = _getInt("concurrency"); | 
| 148 | 148 | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
| 159 | 159 | 
| 160     var paths = _getList("paths", (pathNode) { | 160     var paths = _getList("paths", (pathNode) { | 
| 161       _validate(pathNode, "Paths must be strings.", (value) => value is String); | 161       _validate(pathNode, "Paths must be strings.", (value) => value is String); | 
| 162       _validate(pathNode, "Paths must be relative.", p.url.isRelative); | 162       _validate(pathNode, "Paths must be relative.", p.url.isRelative); | 
| 163 | 163 | 
| 164       return _parseNode(pathNode, "path", p.fromUri); | 164       return _parseNode(pathNode, "path", p.fromUri); | 
| 165     }); | 165     }); | 
| 166 | 166 | 
| 167     var filename = _parseValue("filename", (value) => new Glob(value)); | 167     var filename = _parseValue("filename", (value) => new Glob(value)); | 
| 168 | 168 | 
|  | 169     var chosenPresets = _getList("add_presets", | 
|  | 170         (presetNode) => _parseIdentifierLike(presetNode, "Preset name")); | 
|  | 171 | 
| 169     return new Configuration( | 172     return new Configuration( | 
| 170         reporter: reporter, | 173         reporter: reporter, | 
| 171         pubServePort: pubServePort, | 174         pubServePort: pubServePort, | 
| 172         concurrency: concurrency, | 175         concurrency: concurrency, | 
| 173         platforms: platforms, | 176         platforms: platforms, | 
| 174         paths: paths, | 177         paths: paths, | 
| 175         filename: filename); | 178         filename: filename, | 
|  | 179         chosenPresets: chosenPresets); | 
| 176   } | 180   } | 
| 177 | 181 | 
| 178   /// Throws an exception with [message] if [test] returns `false` when passed | 182   /// Throws an exception with [message] if [test] returns `false` when passed | 
| 179   /// [node]'s value. | 183   /// [node]'s value. | 
| 180   void _validate(YamlNode node, String message, bool test(value)) { | 184   void _validate(YamlNode node, String message, bool test(value)) { | 
| 181     if (test(node.value)) return; | 185     if (test(node.value)) return; | 
| 182     throw new SourceSpanFormatException(message, node.span, _source); | 186     throw new SourceSpanFormatException(message, node.span, _source); | 
| 183   } | 187   } | 
| 184 | 188 | 
| 185   /// Returns the value of the node at [field]. | 189   /// Returns the value of the node at [field]. | 
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 246           (value) => value is String); | 250           (value) => value is String); | 
| 247 | 251 | 
| 248       return valueNode.value; | 252       return valueNode.value; | 
| 249     }; | 253     }; | 
| 250 | 254 | 
| 251     return mapMap(node.nodes, | 255     return mapMap(node.nodes, | 
| 252         key: (keyNode, _) => key(keyNode), | 256         key: (keyNode, _) => key(keyNode), | 
| 253         value: (_, valueNode) => value(valueNode)); | 257         value: (_, valueNode) => value(valueNode)); | 
| 254   } | 258   } | 
| 255 | 259 | 
|  | 260   String _parseIdentifierLike(YamlNode node, String name) { | 
|  | 261     _validate(node, "$name must be a string.", (value) => value is String); | 
|  | 262     _validate( | 
|  | 263         node, | 
|  | 264         "$name must be an (optionally hyphenated) Dart identifier.", | 
|  | 265         (value) => value.contains(anchoredHyphenatedIdentifier)); | 
|  | 266     return node.value; | 
|  | 267   } | 
|  | 268 | 
| 256   /// Asserts that [node] is a string, passes its value to [parse], and returns | 269   /// Asserts that [node] is a string, passes its value to [parse], and returns | 
| 257   /// the result. | 270   /// the result. | 
| 258   /// | 271   /// | 
| 259   /// If [parse] throws a [FormatException], it's wrapped to include [node]'s | 272   /// If [parse] throws a [FormatException], it's wrapped to include [node]'s | 
| 260   /// span. | 273   /// span. | 
| 261   _parseNode(YamlNode node, String name, parse(String value)) { | 274   _parseNode(YamlNode node, String name, parse(String value)) { | 
| 262     _validate(node, "$name must be a string.", (value) => value is String); | 275     _validate(node, "$name must be a string.", (value) => value is String); | 
| 263 | 276 | 
| 264     try { | 277     try { | 
| 265       return parse(node.value); | 278       return parse(node.value); | 
| (...skipping 14 matching lines...) Expand all  Loading... | 
| 280     return _parseNode(node, field, parse); | 293     return _parseNode(node, field, parse); | 
| 281   } | 294   } | 
| 282 | 295 | 
| 283   /// Parses a nested configuration document. | 296   /// Parses a nested configuration document. | 
| 284   /// | 297   /// | 
| 285   /// [name] is the name of the field, which is used for error-handling. | 298   /// [name] is the name of the field, which is used for error-handling. | 
| 286   /// [runnerConfig] controls whether runner configuration is allowed in the | 299   /// [runnerConfig] controls whether runner configuration is allowed in the | 
| 287   /// nested configuration. It defaults to [_runnerConfig]. | 300   /// nested configuration. It defaults to [_runnerConfig]. | 
| 288   Configuration _nestedConfig(YamlNode node, String name, | 301   Configuration _nestedConfig(YamlNode node, String name, | 
| 289       {bool runnerConfig}) { | 302       {bool runnerConfig}) { | 
| 290     if (node == null || node.value == null) return new Configuration(); | 303     if (node == null || node.value == null) return Configuration.empty; | 
| 291 | 304 | 
| 292     _validate(node, "$name must be a map.", (value) => value is Map); | 305     _validate(node, "$name must be a map.", (value) => value is Map); | 
| 293     var loader = new _ConfigurationLoader(node, _source, | 306     var loader = new _ConfigurationLoader(node, _source, | 
| 294         runnerConfig: runnerConfig ?? _runnerConfig); | 307         runnerConfig: runnerConfig ?? _runnerConfig); | 
| 295     return loader.load(); | 308     return loader.load(); | 
| 296   } | 309   } | 
| 297 | 310 | 
| 298   /// Throws an error if a field named [field] exists at this level. | 311   /// Throws an error if a field named [field] exists at this level. | 
| 299   void _disallow(String field) { | 312   void _disallow(String field) { | 
| 300     if (!_document.containsKey(field)) return; | 313     if (!_document.containsKey(field)) return; | 
| 301     _error("$field isn't supported here.", field); | 314     _error("$field isn't supported here.", field); | 
| 302   } | 315   } | 
| 303 | 316 | 
| 304   /// Throws a [SourceSpanFormatException] with [message] about [field]. | 317   /// Throws a [SourceSpanFormatException] with [message] about [field]. | 
| 305   void _error(String message, String field) { | 318   void _error(String message, String field) { | 
| 306     throw new SourceSpanFormatException( | 319     throw new SourceSpanFormatException( | 
| 307         message, _document.nodes[field].span, _source); | 320         message, _document.nodes[field].span, _source); | 
| 308   } | 321   } | 
| 309 } | 322 } | 
| OLD | NEW | 
|---|