OLD | NEW |
---|---|
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library context.directory.manager; | 5 library context.directory.manager; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:collection'; | 8 import 'dart:collection'; |
9 | 9 |
10 import 'package:analyzer/file_system/file_system.dart'; | 10 import 'package:analyzer/file_system/file_system.dart'; |
(...skipping 18 matching lines...) Expand all Loading... | |
29 */ | 29 */ |
30 const String PUBSPEC_NAME = 'pubspec.yaml'; | 30 const String PUBSPEC_NAME = 'pubspec.yaml'; |
31 | 31 |
32 | 32 |
33 /** | 33 /** |
34 * Class that maintains a mapping from included/excluded paths to a set of | 34 * Class that maintains a mapping from included/excluded paths to a set of |
35 * folders that should correspond to analysis contexts. | 35 * folders that should correspond to analysis contexts. |
36 */ | 36 */ |
37 abstract class ContextManager { | 37 abstract class ContextManager { |
38 /** | 38 /** |
39 * The name of the `lib` directory. | |
40 */ | |
41 static const String LIB_DIR_NAME = 'lib'; | |
42 | |
43 /** | |
39 * [_ContextInfo] object for each included directory in the most | 44 * [_ContextInfo] object for each included directory in the most |
40 * recent successful call to [setRoots]. | 45 * recent successful call to [setRoots]. |
41 */ | 46 */ |
42 Map<Folder, _ContextInfo> _contexts = new HashMap<Folder, _ContextInfo>(); | 47 Map<Folder, _ContextInfo> _contexts = new HashMap<Folder, _ContextInfo>(); |
43 | 48 |
44 /** | 49 /** |
45 * The [ResourceProvider] using which paths are converted into [Resource]s. | 50 * The [ResourceProvider] using which paths are converted into [Resource]s. |
46 */ | 51 */ |
47 final ResourceProvider resourceProvider; | 52 final ResourceProvider resourceProvider; |
48 | 53 |
(...skipping 29 matching lines...) Expand all Loading... | |
78 * Provider which is used to determine the mapping from package name to | 83 * Provider which is used to determine the mapping from package name to |
79 * package folder. | 84 * package folder. |
80 */ | 85 */ |
81 final PackageMapProvider _packageMapProvider; | 86 final PackageMapProvider _packageMapProvider; |
82 | 87 |
83 ContextManager(this.resourceProvider, this._packageMapProvider) { | 88 ContextManager(this.resourceProvider, this._packageMapProvider) { |
84 pathContext = resourceProvider.pathContext; | 89 pathContext = resourceProvider.pathContext; |
85 } | 90 } |
86 | 91 |
87 /** | 92 /** |
88 * Called when a new context needs to be created. | 93 * Create and return a new analysis context. |
89 */ | 94 */ |
90 void addContext(Folder folder, UriResolver packageUriResolver); | 95 AnalysisContext addContext(Folder folder, UriResolver packageUriResolver); |
91 | 96 |
92 /** | 97 /** |
93 * Called when the set of files associated with a context have changed (or | 98 * Called when the set of files associated with a context have changed (or |
94 * some of those files have been modified). [changeSet] is the set of | 99 * some of those files have been modified). [changeSet] is the set of |
95 * changes that need to be applied to the context. | 100 * changes that need to be applied to the context. |
96 */ | 101 */ |
97 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet); | 102 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet); |
98 | 103 |
99 /** | 104 /** |
100 * We are about to start computing the package map. | 105 * We are about to start computing the package map. |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
275 continue; | 280 continue; |
276 } | 281 } |
277 _addPreviouslyExcludedSources(info, changeSet, child, oldExcludedPaths); | 282 _addPreviouslyExcludedSources(info, changeSet, child, oldExcludedPaths); |
278 } | 283 } |
279 } | 284 } |
280 } | 285 } |
281 | 286 |
282 /** | 287 /** |
283 * Resursively adds all Dart and HTML files to the [changeSet]. | 288 * Resursively adds all Dart and HTML files to the [changeSet]. |
284 */ | 289 */ |
285 void _addSourceFiles(ChangeSet changeSet, Folder folder, _ContextInfo info) { | 290 void _addSourceFiles(ChangeSet changeSet, Folder folder, _ContextInfo info, |
291 bool pubspecExists, bool createPackageUri) { | |
286 if (info.excludesResource(folder) || folder.shortName.startsWith('.')) { | 292 if (info.excludesResource(folder) || folder.shortName.startsWith('.')) { |
287 return; | 293 return; |
288 } | 294 } |
289 List<Resource> children = folder.getChildren(); | 295 List<Resource> children = folder.getChildren(); |
290 for (Resource child in children) { | 296 for (Resource child in children) { |
291 String path = child.path; | 297 String path = child.path; |
292 // ignore excluded files or folders | 298 // ignore excluded files or folders |
293 if (_isExcluded(path)) { | 299 if (_isExcluded(path)) { |
294 continue; | 300 continue; |
295 } | 301 } |
296 // add files, recurse into folders | 302 // add files, recurse into folders |
297 if (child is File) { | 303 if (child is File) { |
298 if (_shouldFileBeAnalyzed(child)) { | 304 if (_shouldFileBeAnalyzed(child)) { |
299 Source source = child.createSource(); | 305 Source source = child.createSource(); |
306 if (createPackageUri) { | |
Paul Berry
2015/02/12 21:56:09
I think we could achieve the same effect with less
Brian Wilkerson
2015/02/13 17:46:07
Your comment got me to thinking more deeply about
| |
307 Uri uri = info.context.sourceFactory.restoreUri(source); | |
308 source = child.createSource(uri); | |
309 } | |
300 changeSet.addedSource(source); | 310 changeSet.addedSource(source); |
301 info.sources[path] = source; | 311 info.sources[path] = source; |
302 } | 312 } |
303 } else if (child is Folder) { | 313 } else if (child is Folder) { |
304 if (child.shortName == PACKAGES_NAME) { | 314 String shortName = child.shortName; |
315 if (shortName == PACKAGES_NAME) { | |
305 continue; | 316 continue; |
306 } | 317 } |
307 _addSourceFiles(changeSet, child, info); | 318 if (pubspecExists && |
319 !createPackageUri && | |
320 shortName == LIB_DIR_NAME && | |
321 child.parent == info.folder) { | |
322 createPackageUri = true; | |
323 } | |
324 _addSourceFiles( | |
325 changeSet, | |
326 child, | |
327 info, | |
328 pubspecExists, | |
329 createPackageUri); | |
308 } | 330 } |
309 } | 331 } |
310 } | 332 } |
311 | 333 |
312 /** | 334 /** |
313 * Compute the appropriate package URI resolver for [folder], and store | 335 * Compute the appropriate package URI resolver for [folder], and store |
314 * dependency information in [info]. Return `null` if no package map can | 336 * dependency information in [info]. Return `null` if no package map can |
315 * be computed. | 337 * be computed. |
316 */ | 338 */ |
317 UriResolver _computePackageUriResolver(Folder folder, _ContextInfo info) { | 339 UriResolver _computePackageUriResolver(Folder folder, _ContextInfo info) { |
(...skipping 13 matching lines...) Expand all Loading... | |
331 resourceProvider, | 353 resourceProvider, |
332 packageMapInfo.packageMap); | 354 packageMapInfo.packageMap); |
333 // TODO(paulberry): if any of the dependencies is outside of [folder], | 355 // TODO(paulberry): if any of the dependencies is outside of [folder], |
334 // we'll need to watch their parent folders as well. | 356 // we'll need to watch their parent folders as well. |
335 } | 357 } |
336 } | 358 } |
337 | 359 |
338 /** | 360 /** |
339 * Create a new empty context associated with [folder]. | 361 * Create a new empty context associated with [folder]. |
340 */ | 362 */ |
341 _ContextInfo _createContext(Folder folder, List<_ContextInfo> children) { | 363 _ContextInfo _createContext(Folder folder, File pubspecFile, |
342 _ContextInfo info = | 364 List<_ContextInfo> children) { |
343 new _ContextInfo(folder, children, normalizedPackageRoots[folder.path]); | 365 _ContextInfo info = new _ContextInfo( |
366 folder, | |
367 pubspecFile, | |
368 children, | |
369 normalizedPackageRoots[folder.path]); | |
344 _contexts[folder] = info; | 370 _contexts[folder] = info; |
345 info.changeSubscription = folder.changes.listen((WatchEvent event) { | 371 info.changeSubscription = folder.changes.listen((WatchEvent event) { |
346 _handleWatchEvent(folder, info, event); | 372 _handleWatchEvent(folder, info, event); |
347 }); | 373 }); |
348 UriResolver packageUriResolver = _computePackageUriResolver(folder, info); | 374 UriResolver packageUriResolver = _computePackageUriResolver(folder, info); |
349 addContext(folder, packageUriResolver); | 375 info.context = addContext(folder, packageUriResolver); |
350 return info; | 376 return info; |
351 } | 377 } |
352 | 378 |
353 /** | 379 /** |
354 * Creates a new context associated with [folder]. | 380 * Creates a new context associated with [folder]. |
355 * | 381 * |
356 * If there are subfolders with 'pubspec.yaml' files, separate contexts | 382 * If there are subfolders with 'pubspec.yaml' files, separate contexts |
357 * are created for them, and excluded from the context associated with | 383 * are created for them, and excluded from the context associated with |
358 * [folder]. | 384 * [folder]. |
359 * | 385 * |
360 * If [folder] itself contains a 'pubspec.yaml' file, subfolders are ignored. | 386 * If [folder] itself contains a 'pubspec.yaml' file, subfolders are ignored. |
361 * | 387 * |
362 * If [withPubspecOnly] is `true`, a context will be created only if there | 388 * If [withPubspecOnly] is `true`, a context will be created only if there |
363 * is a 'pubspec.yaml' file in [folder]. | 389 * is a 'pubspec.yaml' file in [folder]. |
364 * | 390 * |
365 * Returns create pubspec-based contexts. | 391 * Returns create pubspec-based contexts. |
366 */ | 392 */ |
367 List<_ContextInfo> _createContexts(Folder folder, bool withPubspecOnly) { | 393 List<_ContextInfo> _createContexts(Folder folder, bool withPubspecOnly) { |
368 // check if there is a pubspec in the folder | 394 // check whether there is a pubspec in the folder |
369 { | 395 File pubspecFile = folder.getChild(PUBSPEC_NAME); |
370 File pubspecFile = folder.getChild(PUBSPEC_NAME); | 396 bool pubspecExists = pubspecFile.exists; |
371 if (pubspecFile.exists) { | 397 if (pubspecExists) { |
372 _ContextInfo info = _createContextWithSources(folder, <_ContextInfo>[]); | 398 _ContextInfo info = _createContextWithSources( |
373 return [info]; | 399 folder, |
374 } | 400 pubspecFile, |
401 pubspecExists, | |
402 <_ContextInfo>[]); | |
403 return [info]; | |
375 } | 404 } |
376 // try to find subfolders with pubspec files | 405 // try to find subfolders with pubspec files |
377 List<_ContextInfo> children = <_ContextInfo>[]; | 406 List<_ContextInfo> children = <_ContextInfo>[]; |
378 for (Resource child in folder.getChildren()) { | 407 for (Resource child in folder.getChildren()) { |
379 if (child is Folder) { | 408 if (child is Folder) { |
380 List<_ContextInfo> childContexts = _createContexts(child, true); | 409 List<_ContextInfo> childContexts = _createContexts(child, true); |
381 children.addAll(childContexts); | 410 children.addAll(childContexts); |
382 } | 411 } |
383 } | 412 } |
384 // no pubspec, done | 413 // no pubspec, done |
385 if (withPubspecOnly) { | 414 if (withPubspecOnly) { |
386 return children; | 415 return children; |
387 } | 416 } |
388 // OK, create a context without a pubspec | 417 // OK, create a context without a pubspec |
389 _createContextWithSources(folder, children); | 418 _createContextWithSources(folder, pubspecFile, pubspecExists, children); |
390 return children; | 419 return children; |
391 } | 420 } |
392 | 421 |
393 /** | 422 /** |
394 * Create a new context associated with [folder] and fills its with sources. | 423 * Create a new context associated with the given [folder]. The [pubspecFile] |
424 * is the `pubspec.yaml` file contained in the folder, and [pubspecExists] is | |
425 * `true` if the file exists. Add any sources that are not included in one of | |
426 * the [children] to the context. | |
395 */ | 427 */ |
396 _ContextInfo _createContextWithSources(Folder folder, | 428 _ContextInfo _createContextWithSources(Folder folder, File pubspecFile, |
397 List<_ContextInfo> children) { | 429 bool pubspecExists, List<_ContextInfo> children) { |
398 _ContextInfo info = _createContext(folder, children); | 430 _ContextInfo info = _createContext(folder, pubspecFile, children); |
399 ChangeSet changeSet = new ChangeSet(); | 431 ChangeSet changeSet = new ChangeSet(); |
400 _addSourceFiles(changeSet, folder, info); | 432 _addSourceFiles(changeSet, folder, info, pubspecExists, false); |
401 applyChangesToContext(folder, changeSet); | 433 applyChangesToContext(folder, changeSet); |
402 return info; | 434 return info; |
403 } | 435 } |
404 | 436 |
405 /** | 437 /** |
406 * Clean up and destroy the context associated with the given folder. | 438 * Clean up and destroy the context associated with the given folder. |
407 */ | 439 */ |
408 void _destroyContext(Folder folder) { | 440 void _destroyContext(Folder folder) { |
409 _contexts[folder].changeSubscription.cancel(); | 441 _contexts[folder].changeSubscription.cancel(); |
410 _contexts.remove(folder); | 442 _contexts.remove(folder); |
411 removeContext(folder); | 443 removeContext(folder); |
412 } | 444 } |
413 | 445 |
414 /** | 446 /** |
415 * Extract a new [pubspecFile]-based context from [oldInfo]. | 447 * Extract a new [pubspecFile]-based context from [oldInfo]. |
416 */ | 448 */ |
417 void _extractContext(_ContextInfo oldInfo, File pubspecFile) { | 449 void _extractContext(_ContextInfo oldInfo, File pubspecFile) { |
418 Folder newFolder = pubspecFile.parent; | 450 Folder newFolder = pubspecFile.parent; |
419 _ContextInfo newInfo = _createContext(newFolder, []); | 451 _ContextInfo newInfo = _createContext(newFolder, pubspecFile, []); |
420 newInfo.parent = oldInfo; | 452 newInfo.parent = oldInfo; |
421 // prepare sources to extract | 453 // prepare sources to extract |
422 Map<String, Source> extractedSources = new HashMap<String, Source>(); | 454 Map<String, Source> extractedSources = new HashMap<String, Source>(); |
423 oldInfo.sources.forEach((path, source) { | 455 oldInfo.sources.forEach((path, source) { |
424 if (newFolder.contains(path)) { | 456 if (newFolder.contains(path)) { |
425 extractedSources[path] = source; | 457 extractedSources[path] = source; |
426 } | 458 } |
427 }); | 459 }); |
428 // update new context | 460 // update new context |
429 { | 461 { |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
622 */ | 654 */ |
623 String pubspecPath; | 655 String pubspecPath; |
624 | 656 |
625 /** | 657 /** |
626 * Stream subscription we are using to watch the context's directory for | 658 * Stream subscription we are using to watch the context's directory for |
627 * changes. | 659 * changes. |
628 */ | 660 */ |
629 StreamSubscription<WatchEvent> changeSubscription; | 661 StreamSubscription<WatchEvent> changeSubscription; |
630 | 662 |
631 /** | 663 /** |
664 * The analysis context that was created for the [folder]. | |
665 */ | |
666 AnalysisContext context; | |
667 | |
668 /** | |
632 * Map from full path to the [Source] object, for each source that has been | 669 * Map from full path to the [Source] object, for each source that has been |
633 * added to the context. | 670 * added to the context. |
634 */ | 671 */ |
635 Map<String, Source> sources = new HashMap<String, Source>(); | 672 Map<String, Source> sources = new HashMap<String, Source>(); |
636 | 673 |
637 /** | 674 /** |
638 * Dependencies of the context's package map. | 675 * Dependencies of the context's package map. |
639 * If any of these files changes, the package map needs to be recomputed. | 676 * If any of these files changes, the package map needs to be recomputed. |
640 */ | 677 */ |
641 Set<String> packageMapDependencies; | 678 Set<String> packageMapDependencies; |
642 | 679 |
643 _ContextInfo(this.folder, this.children, this.packageRoot) { | 680 _ContextInfo(this.folder, File pubspecFile, this.children, this.packageRoot) { |
644 pubspecPath = folder.getChild(PUBSPEC_NAME).path; | 681 pubspecPath = pubspecFile.path; |
645 for (_ContextInfo child in children) { | 682 for (_ContextInfo child in children) { |
646 child.parent = this; | 683 child.parent = this; |
647 } | 684 } |
648 } | 685 } |
649 | 686 |
650 /** | 687 /** |
651 * Returns `true` if this context is root folder based. | 688 * Returns `true` if this context is root folder based. |
652 */ | 689 */ |
653 bool get isRoot => parent == null; | 690 bool get isRoot => parent == null; |
654 | 691 |
(...skipping 13 matching lines...) Expand all Loading... | |
668 return excludes(resource.path); | 705 return excludes(resource.path); |
669 } | 706 } |
670 | 707 |
671 /** | 708 /** |
672 * Returns `true` if [path] is the pubspec file of this context. | 709 * Returns `true` if [path] is the pubspec file of this context. |
673 */ | 710 */ |
674 bool isPubspec(String path) { | 711 bool isPubspec(String path) { |
675 return path == pubspecPath; | 712 return path == pubspecPath; |
676 } | 713 } |
677 } | 714 } |
OLD | NEW |