OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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:collection/collection.dart'; | 8 import 'package:collection/collection.dart'; |
9 import 'package:glob/glob.dart'; | 9 import 'package:glob/glob.dart'; |
10 import 'package:path/path.dart' as p; | 10 import 'package:path/path.dart' as p; |
11 | 11 |
12 import '../backend/metadata.dart'; | 12 import '../backend/metadata.dart'; |
13 import '../backend/platform_selector.dart'; | 13 import '../backend/platform_selector.dart'; |
14 import '../backend/test_platform.dart'; | 14 import '../backend/test_platform.dart'; |
15 import '../frontend/timeout.dart'; | 15 import '../frontend/timeout.dart'; |
16 import '../util/io.dart'; | 16 import '../util/io.dart'; |
17 import '../utils.dart'; | 17 import '../utils.dart'; |
18 import 'configuration/args.dart' as args; | 18 import 'configuration/args.dart' as args; |
19 import 'configuration/load.dart'; | 19 import 'configuration/load.dart'; |
20 import 'configuration/values.dart'; | 20 import 'configuration/values.dart'; |
21 | 21 |
22 /// A class that encapsulates the command-line configuration of the test runner. | 22 /// A class that encapsulates the command-line configuration of the test runner. |
23 class Configuration { | 23 class Configuration { |
| 24 /// An empty configuration with only default values. |
| 25 /// |
| 26 /// Using this is slightly more efficient than manually constructing a new |
| 27 /// configuration with no arguments. |
| 28 static final empty = new Configuration._(); |
| 29 |
24 /// The usage string for the command-line arguments. | 30 /// The usage string for the command-line arguments. |
25 static String get usage => args.usage; | 31 static String get usage => args.usage; |
26 | 32 |
27 /// Whether `--help` was passed. | 33 /// Whether `--help` was passed. |
28 bool get help => _help ?? false; | 34 bool get help => _help ?? false; |
29 final bool _help; | 35 final bool _help; |
30 | 36 |
31 /// Whether `--version` was passed. | 37 /// Whether `--version` was passed. |
32 bool get version => _version ?? false; | 38 bool get version => _version ?? false; |
33 final bool _version; | 39 final bool _version; |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 final Glob _filename; | 106 final Glob _filename; |
101 | 107 |
102 /// The pattern to match against test names to decide which to run, or `null` | 108 /// The pattern to match against test names to decide which to run, or `null` |
103 /// if all tests should be run. | 109 /// if all tests should be run. |
104 final Pattern pattern; | 110 final Pattern pattern; |
105 | 111 |
106 /// The set of platforms on which to run tests. | 112 /// The set of platforms on which to run tests. |
107 List<TestPlatform> get platforms => _platforms ?? [TestPlatform.vm]; | 113 List<TestPlatform> get platforms => _platforms ?? [TestPlatform.vm]; |
108 final List<TestPlatform> _platforms; | 114 final List<TestPlatform> _platforms; |
109 | 115 |
| 116 /// The set of presets to use. |
| 117 /// |
| 118 /// Any chosen presets for the parent configuration are added to the chosen |
| 119 /// preset sets for child configurations as well. |
| 120 /// |
| 121 /// Note that the order of this set matters. |
| 122 final Set<String> chosenPresets; |
| 123 |
110 /// Only run tests whose tags match this selector. | 124 /// Only run tests whose tags match this selector. |
111 /// | 125 /// |
112 /// When [merge]d, this is intersected with the other configuration's included | 126 /// When [merge]d, this is intersected with the other configuration's included |
113 /// tags. | 127 /// tags. |
114 final BooleanSelector includeTags; | 128 final BooleanSelector includeTags; |
115 | 129 |
116 /// Do not run tests whose tags match this selector. | 130 /// Do not run tests whose tags match this selector. |
117 /// | 131 /// |
118 /// When [merge]d, this is unioned with the other configuration's | 132 /// When [merge]d, this is unioned with the other configuration's |
119 /// excluded tags. | 133 /// excluded tags. |
(...skipping 15 matching lines...) Expand all Loading... |
135 Metadata get metadata => new Metadata( | 149 Metadata get metadata => new Metadata( |
136 timeout: timeout, | 150 timeout: timeout, |
137 verboseTrace: verboseTrace, | 151 verboseTrace: verboseTrace, |
138 skip: skip, | 152 skip: skip, |
139 skipReason: skipReason, | 153 skipReason: skipReason, |
140 testOn: testOn, | 154 testOn: testOn, |
141 tags: addTags, | 155 tags: addTags, |
142 forTag: mapMap(tags, value: (_, config) => config.metadata), | 156 forTag: mapMap(tags, value: (_, config) => config.metadata), |
143 onPlatform: mapMap(onPlatform, value: (_, config) => config.metadata)); | 157 onPlatform: mapMap(onPlatform, value: (_, config) => config.metadata)); |
144 | 158 |
145 /// The set of tags that have been declaredin any way in this configuration. | 159 /// The set of tags that have been declared in any way in this configuration. |
146 Set<String> get knownTags { | 160 Set<String> get knownTags { |
147 if (_knownTags != null) return _knownTags; | 161 if (_knownTags != null) return _knownTags; |
148 | 162 |
149 var known = includeTags.variables.toSet() | 163 var known = includeTags.variables.toSet() |
150 ..addAll(excludeTags.variables) | 164 ..addAll(excludeTags.variables) |
151 ..addAll(addTags); | 165 ..addAll(addTags); |
152 tags.forEach((selector, config) { | 166 |
| 167 for (var selector in tags.keys) { |
153 known.addAll(selector.variables); | 168 known.addAll(selector.variables); |
154 known.addAll(config.knownTags); | 169 } |
155 }); | 170 |
| 171 for (var configuration in _children) { |
| 172 known.addAll(configuration.knownTags); |
| 173 } |
156 | 174 |
157 _knownTags = new UnmodifiableSetView(known); | 175 _knownTags = new UnmodifiableSetView(known); |
158 return _knownTags; | 176 return _knownTags; |
159 } | 177 } |
160 Set<String> _knownTags; | 178 Set<String> _knownTags; |
161 | 179 |
162 /// Configuration for particular platforms. | 180 /// Configuration for particular platforms. |
163 /// | 181 /// |
164 /// The keys are platform selectors, and the values are configurations for | 182 /// The keys are platform selectors, and the values are configurations for |
165 /// those platforms. These configuration should only contain test-level | 183 /// those platforms. These configuration should only contain test-level |
166 /// configuration fields, but that isn't enforced. | 184 /// configuration fields, but that isn't enforced. |
167 final Map<PlatformSelector, Configuration> onPlatform; | 185 final Map<PlatformSelector, Configuration> onPlatform; |
168 | 186 |
| 187 /// Configuration presets. |
| 188 /// |
| 189 /// These are configurations that can be explicitly selected by the user via |
| 190 /// the command line. Preset configuration takes precedence over the base |
| 191 /// configuration. |
| 192 /// |
| 193 /// This is guaranteed not to have any keys that match [chosenPresets]; those |
| 194 /// are resolved when the configuration is constructed. |
| 195 final Map<String, Configuration> presets; |
| 196 |
| 197 /// All preset names that are known to be valid. |
| 198 /// |
| 199 /// This includes presets that have already been resolved. |
| 200 Set<String> get knownPresets { |
| 201 if (_knownPresets != null) return _knownPresets; |
| 202 |
| 203 var known = presets.keys.toSet(); |
| 204 for (var configuration in _children) { |
| 205 known.addAll(configuration.knownPresets); |
| 206 } |
| 207 |
| 208 _knownPresets = new UnmodifiableSetView(known); |
| 209 return _knownPresets; |
| 210 } |
| 211 Set<String> _knownPresets; |
| 212 |
| 213 /// All child configurations of [this] that may be selected under various |
| 214 /// circumstances. |
| 215 Iterable<Configuration> get _children sync* { |
| 216 yield* tags.values; |
| 217 yield* onPlatform.values; |
| 218 yield* presets.values; |
| 219 } |
| 220 |
169 /// Parses the configuration from [args]. | 221 /// Parses the configuration from [args]. |
170 /// | 222 /// |
171 /// Throws a [FormatException] if [args] are invalid. | 223 /// Throws a [FormatException] if [args] are invalid. |
172 factory Configuration.parse(List<String> arguments) => args.parse(arguments); | 224 factory Configuration.parse(List<String> arguments) => args.parse(arguments); |
173 | 225 |
174 /// Loads the configuration from [path]. | 226 /// Loads the configuration from [path]. |
175 /// | 227 /// |
176 /// Throws an [IOException] if [path] does not exist or cannot be read. Throws | 228 /// Throws an [IOException] if [path] does not exist or cannot be read. Throws |
177 /// a [FormatException] if its contents are invalid. | 229 /// a [FormatException] if its contents are invalid. |
178 factory Configuration.load(String path) => load(path); | 230 factory Configuration.load(String path) => load(path); |
179 | 231 |
180 Configuration({ | 232 factory Configuration({ |
| 233 bool help, |
| 234 bool version, |
| 235 bool verboseTrace, |
| 236 bool jsTrace, |
| 237 bool skip, |
| 238 String skipReason, |
| 239 PlatformSelector testOn, |
| 240 bool pauseAfterLoad, |
| 241 bool color, |
| 242 String packageRoot, |
| 243 String reporter, |
| 244 int pubServePort, |
| 245 int concurrency, |
| 246 Timeout timeout, |
| 247 Pattern pattern, |
| 248 Iterable<TestPlatform> platforms, |
| 249 Iterable<String> paths, |
| 250 Glob filename, |
| 251 Iterable<String> chosenPresets, |
| 252 BooleanSelector includeTags, |
| 253 BooleanSelector excludeTags, |
| 254 Iterable addTags, |
| 255 Map<BooleanSelector, Configuration> tags, |
| 256 Map<PlatformSelector, Configuration> onPlatform, |
| 257 Map<String, Configuration> presets}) { |
| 258 _unresolved() => new Configuration._( |
| 259 help: help, |
| 260 version: version, |
| 261 verboseTrace: verboseTrace, |
| 262 jsTrace: jsTrace, |
| 263 skip: skip, |
| 264 skipReason: skipReason, |
| 265 testOn: testOn, |
| 266 pauseAfterLoad: pauseAfterLoad, |
| 267 color: color, |
| 268 packageRoot: packageRoot, |
| 269 reporter: reporter, |
| 270 pubServePort: pubServePort, |
| 271 concurrency: concurrency, |
| 272 timeout: timeout, |
| 273 pattern: pattern, |
| 274 platforms: platforms, |
| 275 paths: paths, |
| 276 filename: filename, |
| 277 chosenPresets: chosenPresets, |
| 278 includeTags: includeTags, |
| 279 excludeTags: excludeTags, |
| 280 addTags: addTags, |
| 281 |
| 282 // Make sure we pass [chosenPresets] to the child configurations as |
| 283 // well. This ensures that |
| 284 tags: _withChosenPresets(tags, chosenPresets), |
| 285 onPlatform: _withChosenPresets(onPlatform, chosenPresets), |
| 286 presets: _withChosenPresets(presets, chosenPresets)); |
| 287 |
| 288 if (chosenPresets == null) return _unresolved(); |
| 289 chosenPresets = new Set.from(chosenPresets); |
| 290 |
| 291 if (presets == null) return _unresolved(); |
| 292 presets = new Map.from(presets); |
| 293 |
| 294 var knownPresets = presets.keys.toSet(); |
| 295 |
| 296 var merged = chosenPresets.fold(Configuration.empty, (merged, preset) { |
| 297 if (!presets.containsKey(preset)) return merged; |
| 298 return merged.merge(presets.remove(preset)); |
| 299 }); |
| 300 |
| 301 var result = merged == Configuration.empty |
| 302 ? _unresolved() |
| 303 : _unresolved().merge(merged); |
| 304 |
| 305 // Make sure the configuration knows about presets that were selected and |
| 306 // thus removed from [presets]. |
| 307 result._knownPresets = result.knownPresets.union(knownPresets); |
| 308 |
| 309 return result; |
| 310 } |
| 311 |
| 312 static Map<Object, Configuration> _withChosenPresets( |
| 313 Map<Object, Configuration> map, Set<String> chosenPresets) { |
| 314 if (map == null || chosenPresets == null) return map; |
| 315 return mapMap(map, value: (_, config) => config.change( |
| 316 chosenPresets: config.chosenPresets.union(chosenPresets))); |
| 317 } |
| 318 |
| 319 /// Creates new Configuration. |
| 320 /// |
| 321 /// Unlike [new Configuration], this assumes [presets] is already resolved. |
| 322 Configuration._({ |
181 bool help, | 323 bool help, |
182 bool version, | 324 bool version, |
183 bool verboseTrace, | 325 bool verboseTrace, |
184 bool jsTrace, | 326 bool jsTrace, |
185 bool skip, | 327 bool skip, |
186 this.skipReason, | 328 this.skipReason, |
187 PlatformSelector testOn, | 329 PlatformSelector testOn, |
188 bool pauseAfterLoad, | 330 bool pauseAfterLoad, |
189 bool color, | 331 bool color, |
190 String packageRoot, | 332 String packageRoot, |
191 String reporter, | 333 String reporter, |
192 int pubServePort, | 334 int pubServePort, |
193 int concurrency, | 335 int concurrency, |
194 Timeout timeout, | 336 Timeout timeout, |
195 this.pattern, | 337 this.pattern, |
196 Iterable<TestPlatform> platforms, | 338 Iterable<TestPlatform> platforms, |
197 Iterable<String> paths, | 339 Iterable<String> paths, |
198 Glob filename, | 340 Glob filename, |
| 341 Iterable<String> chosenPresets, |
199 BooleanSelector includeTags, | 342 BooleanSelector includeTags, |
200 BooleanSelector excludeTags, | 343 BooleanSelector excludeTags, |
201 Iterable addTags, | 344 Iterable addTags, |
202 Map<BooleanSelector, Configuration> tags, | 345 Map<BooleanSelector, Configuration> tags, |
203 Map<PlatformSelector, Configuration> onPlatform}) | 346 Map<PlatformSelector, Configuration> onPlatform, |
| 347 Map<String, Configuration> presets}) |
204 : _help = help, | 348 : _help = help, |
205 _version = version, | 349 _version = version, |
206 _verboseTrace = verboseTrace, | 350 _verboseTrace = verboseTrace, |
207 _jsTrace = jsTrace, | 351 _jsTrace = jsTrace, |
208 _skip = skip, | 352 _skip = skip, |
209 testOn = testOn ?? PlatformSelector.all, | 353 testOn = testOn ?? PlatformSelector.all, |
210 _pauseAfterLoad = pauseAfterLoad, | 354 _pauseAfterLoad = pauseAfterLoad, |
211 _color = color, | 355 _color = color, |
212 _packageRoot = packageRoot, | 356 _packageRoot = packageRoot, |
213 _reporter = reporter, | 357 _reporter = reporter, |
214 pubServeUrl = pubServePort == null | 358 pubServeUrl = pubServePort == null |
215 ? null | 359 ? null |
216 : Uri.parse("http://localhost:$pubServePort"), | 360 : Uri.parse("http://localhost:$pubServePort"), |
217 _concurrency = concurrency, | 361 _concurrency = concurrency, |
218 timeout = (pauseAfterLoad ?? false) | 362 timeout = (pauseAfterLoad ?? false) |
219 ? Timeout.none | 363 ? Timeout.none |
220 : (timeout == null ? new Timeout.factor(1) : timeout), | 364 : (timeout == null ? new Timeout.factor(1) : timeout), |
221 _platforms = _list(platforms), | 365 _platforms = _list(platforms), |
222 _paths = _list(paths), | 366 _paths = _list(paths), |
223 _filename = filename, | 367 _filename = filename, |
| 368 chosenPresets = new Set.from(chosenPresets ?? []), |
224 includeTags = includeTags ?? BooleanSelector.all, | 369 includeTags = includeTags ?? BooleanSelector.all, |
225 excludeTags = excludeTags ?? BooleanSelector.none, | 370 excludeTags = excludeTags ?? BooleanSelector.none, |
226 addTags = addTags?.toSet() ?? new Set(), | 371 addTags = new UnmodifiableSetView(addTags?.toSet() ?? new Set()), |
227 tags = tags == null ? const {} : new Map.unmodifiable(tags), | 372 tags = _map(tags), |
228 onPlatform = onPlatform == null | 373 onPlatform = _map(onPlatform), |
229 ? const {} | 374 presets = _map(presets) { |
230 : new Map.unmodifiable(onPlatform) { | |
231 if (_filename != null && _filename.context.style != p.style) { | 375 if (_filename != null && _filename.context.style != p.style) { |
232 throw new ArgumentError( | 376 throw new ArgumentError( |
233 "filename's context must match the current operating system, was " | 377 "filename's context must match the current operating system, was " |
234 "${_filename.context.style}."); | 378 "${_filename.context.style}."); |
235 } | 379 } |
236 } | 380 } |
237 | 381 |
238 /// Returns a [input] as a list or `null`. | 382 /// Returns a [input] as an unmodifiable list or `null`. |
239 /// | 383 /// |
240 /// If [input] is `null` or empty, this returns `null`. Otherwise, it returns | 384 /// If [input] is `null` or empty, this returns `null`. Otherwise, it returns |
241 /// `input.toList()`. | 385 /// `input.toList()`. |
242 static List _list(Iterable input) { | 386 static List _list(Iterable input) { |
243 if (input == null) return null; | 387 if (input == null) return null; |
244 input = input.toList(); | 388 input = new List.unmodifiable(input); |
245 if (input.isEmpty) return null; | 389 if (input.isEmpty) return null; |
246 return input; | 390 return input; |
247 } | 391 } |
248 | 392 |
| 393 /// Returns an modifiable copy of [input] or an empty unmodifiable map. |
| 394 static Map _map(Map input) { |
| 395 if (input == null) return const {}; |
| 396 return new Map.unmodifiable(input); |
| 397 } |
| 398 |
249 /// Merges this with [other]. | 399 /// Merges this with [other]. |
250 /// | 400 /// |
251 /// For most fields, if both configurations have values set, [other]'s value | 401 /// For most fields, if both configurations have values set, [other]'s value |
252 /// takes precedence. However, certain fields are merged together instead. | 402 /// takes precedence. However, certain fields are merged together instead. |
253 /// This is indicated in those fields' documentation. | 403 /// This is indicated in those fields' documentation. |
254 Configuration merge(Configuration other) { | 404 Configuration merge(Configuration other) { |
255 return new Configuration( | 405 if (this == Configuration.empty) return other; |
| 406 if (other == Configuration.empty) return this; |
| 407 |
| 408 var result = new Configuration( |
256 help: other._help ?? _help, | 409 help: other._help ?? _help, |
257 version: other._version ?? _version, | 410 version: other._version ?? _version, |
258 verboseTrace: other._verboseTrace ?? _verboseTrace, | 411 verboseTrace: other._verboseTrace ?? _verboseTrace, |
259 jsTrace: other._jsTrace ?? _jsTrace, | 412 jsTrace: other._jsTrace ?? _jsTrace, |
260 skip: other._skip ?? _skip, | 413 skip: other._skip ?? _skip, |
261 skipReason: other.skipReason ?? skipReason, | 414 skipReason: other.skipReason ?? skipReason, |
262 testOn: testOn.intersection(other.testOn), | 415 testOn: testOn.intersection(other.testOn), |
263 pauseAfterLoad: other._pauseAfterLoad ?? _pauseAfterLoad, | 416 pauseAfterLoad: other._pauseAfterLoad ?? _pauseAfterLoad, |
264 color: other._color ?? _color, | 417 color: other._color ?? _color, |
265 packageRoot: other._packageRoot ?? _packageRoot, | 418 packageRoot: other._packageRoot ?? _packageRoot, |
266 reporter: other._reporter ?? _reporter, | 419 reporter: other._reporter ?? _reporter, |
267 pubServePort: (other.pubServeUrl ?? pubServeUrl)?.port, | 420 pubServePort: (other.pubServeUrl ?? pubServeUrl)?.port, |
268 concurrency: other._concurrency ?? _concurrency, | 421 concurrency: other._concurrency ?? _concurrency, |
269 timeout: timeout.merge(other.timeout), | 422 timeout: timeout.merge(other.timeout), |
270 pattern: other.pattern ?? pattern, | 423 pattern: other.pattern ?? pattern, |
271 platforms: other._platforms ?? _platforms, | 424 platforms: other._platforms ?? _platforms, |
272 paths: other._paths ?? _paths, | 425 paths: other._paths ?? _paths, |
273 filename: other._filename ?? _filename, | 426 filename: other._filename ?? _filename, |
| 427 chosenPresets: chosenPresets.union(other.chosenPresets), |
274 includeTags: includeTags.intersection(other.includeTags), | 428 includeTags: includeTags.intersection(other.includeTags), |
275 excludeTags: excludeTags.union(other.excludeTags), | 429 excludeTags: excludeTags.union(other.excludeTags), |
276 addTags: other.addTags.union(addTags), | 430 addTags: other.addTags.union(addTags), |
277 tags: mergeMaps(tags, other.tags, | 431 tags: _mergeConfigMaps(tags, other.tags), |
278 value: (config1, config2) => config1.merge(config2)), | 432 onPlatform: _mergeConfigMaps(onPlatform, other.onPlatform), |
279 onPlatform: mergeMaps(onPlatform, other.onPlatform, | 433 presets: _mergeConfigMaps(presets, other.presets)); |
280 value: (config1, config2) => config1.merge(config2))); | 434 |
| 435 // Make sure the merged config preserves any presets that were chosen and |
| 436 // discarded. |
| 437 result._knownPresets = knownPresets.union(other.knownPresets); |
| 438 return result; |
281 } | 439 } |
| 440 |
| 441 /// Returns a copy of this configuration with the given fields updated. |
| 442 /// |
| 443 /// Note that unlike [merge], this has no merging behavior—the old value is |
| 444 /// always replaced by the new one. |
| 445 Configuration change({ |
| 446 bool help, |
| 447 bool version, |
| 448 bool verboseTrace, |
| 449 bool jsTrace, |
| 450 bool skip, |
| 451 String skipReason, |
| 452 PlatformSelector testOn, |
| 453 bool pauseAfterLoad, |
| 454 bool color, |
| 455 String packageRoot, |
| 456 String reporter, |
| 457 int pubServePort, |
| 458 int concurrency, |
| 459 Timeout timeout, |
| 460 Pattern pattern, |
| 461 Iterable<TestPlatform> platforms, |
| 462 Iterable<String> paths, |
| 463 Glob filename, |
| 464 Iterable<String> chosenPresets, |
| 465 BooleanSelector includeTags, |
| 466 BooleanSelector excludeTags, |
| 467 Iterable addTags, |
| 468 Map<BooleanSelector, Configuration> tags, |
| 469 Map<PlatformSelector, Configuration> onPlatform, |
| 470 Map<String, Configuration> presets}) { |
| 471 return new Configuration( |
| 472 help: help ?? _help, |
| 473 version: version ?? _version, |
| 474 verboseTrace: verboseTrace ?? _verboseTrace, |
| 475 jsTrace: jsTrace ?? _jsTrace, |
| 476 skip: skip ?? _skip, |
| 477 skipReason: skipReason ?? this.skipReason, |
| 478 testOn: testOn ?? this.testOn, |
| 479 pauseAfterLoad: pauseAfterLoad ?? _pauseAfterLoad, |
| 480 color: color ?? _color, |
| 481 packageRoot: packageRoot ?? _packageRoot, |
| 482 reporter: reporter ?? _reporter, |
| 483 pubServePort: pubServePort ?? pubServeUrl?.port, |
| 484 concurrency: concurrency ?? _concurrency, |
| 485 timeout: timeout ?? this.timeout, |
| 486 pattern: pattern ?? this.pattern, |
| 487 platforms: platforms ?? _platforms, |
| 488 paths: paths ?? _paths, |
| 489 filename: filename ?? _filename, |
| 490 chosenPresets: chosenPresets ?? this.chosenPresets, |
| 491 includeTags: includeTags ?? this.includeTags, |
| 492 excludeTags: excludeTags ?? this.excludeTags, |
| 493 addTags: addTags ?? this.addTags, |
| 494 tags: tags ?? this.tags, |
| 495 onPlatform: onPlatform ?? this.onPlatform, |
| 496 presets: presets ?? this.presets); |
| 497 } |
| 498 |
| 499 /// Merges two maps whose values are [Configuration]s. |
| 500 /// |
| 501 /// Any overlapping keys in the maps have their configurations merged in the |
| 502 /// returned map. |
| 503 Map<Object, Configuration> _mergeConfigMaps(Map<Object, Configuration> map1, |
| 504 Map<Object, Configuration> map2) => |
| 505 mergeMaps(map1, map2, |
| 506 value: (config1, config2) => config1.merge(config2)); |
282 } | 507 } |
OLD | NEW |