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 a 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 [input] or an empty map. | |
kevmoo
2016/03/10 17:09:39
clarify that the returned value in not modifiable?
nweiz
2016/03/10 20:41:20
Done.
| |
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 |