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 import 'dart:convert'; | 9 import 'dart:convert'; |
10 import 'dart:core' hide Resource; | 10 import 'dart:core' hide Resource; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 * objects. | 62 * objects. |
63 */ | 63 */ |
64 ContextInfo parent; | 64 ContextInfo parent; |
65 | 65 |
66 /** | 66 /** |
67 * The package description file path for this context. | 67 * The package description file path for this context. |
68 */ | 68 */ |
69 String packageDescriptionPath; | 69 String packageDescriptionPath; |
70 | 70 |
71 /** | 71 /** |
72 * Stream subscription we are using to watch the context's directory for | 72 * Paths to files which determine the folder disposition and package map. |
73 * changes. | 73 * |
| 74 * TODO(paulberry): if any of these files are outside of [folder], they won't |
| 75 * be watched for changes. I believe the use case for watching these files |
| 76 * is no longer relevant. |
74 */ | 77 */ |
75 StreamSubscription<WatchEvent> changeSubscription; | 78 Set<String> _dependencies = new Set<String>(); |
76 | |
77 /** | |
78 * Stream subscriptions we are using to watch the files | |
79 * used to determine the package map. Organized as a map from path to | |
80 * subscription. | |
81 * | |
82 * For paths that are inside [folder], the subscription is null, since the | |
83 * entire contents of the folder are automatically being watched. | |
84 */ | |
85 final Map<String, StreamSubscription<WatchEvent>> _dependencySubscriptions = | |
86 <String, StreamSubscription<WatchEvent>>{}; | |
87 | 79 |
88 /** | 80 /** |
89 * The analysis context that was created for the [folder]. | 81 * The analysis context that was created for the [folder]. |
90 */ | 82 */ |
91 AnalysisContext context; | 83 AnalysisContext context; |
92 | 84 |
93 /** | 85 /** |
94 * Map from full path to the [Source] object, for each source that has been | 86 * Map from full path to the [Source] object, for each source that has been |
95 * added to the context. | 87 * added to the context. |
96 */ | 88 */ |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 return info; | 146 return info; |
155 } | 147 } |
156 } | 148 } |
157 return null; | 149 return null; |
158 } | 150 } |
159 | 151 |
160 /** | 152 /** |
161 * Determine if the given [path] is one of the dependencies most recently | 153 * Determine if the given [path] is one of the dependencies most recently |
162 * passed to [setDependencies]. | 154 * passed to [setDependencies]. |
163 */ | 155 */ |
164 bool hasDependency(String path) => _dependencySubscriptions.containsKey(path); | 156 bool hasDependency(String path) => _dependencies.contains(path); |
165 | 157 |
166 /// Returns `true` if [path] should be ignored. | 158 /// Returns `true` if [path] should be ignored. |
167 bool ignored(String path) => pathFilter.ignored(path); | 159 bool ignored(String path) => pathFilter.ignored(path); |
168 | 160 |
169 /** | 161 /** |
170 * Returns `true` if [path] is the package description file for this context | 162 * Returns `true` if [path] is the package description file for this context |
171 * (pubspec.yaml or .packages). | 163 * (pubspec.yaml or .packages). |
172 */ | 164 */ |
173 bool isPathToPackageDescription(String path) => | 165 bool isPathToPackageDescription(String path) => |
174 path == packageDescriptionPath; | 166 path == packageDescriptionPath; |
175 | 167 |
176 /** | 168 /** |
177 * Update the set of dependencies for this context. Watchers are | 169 * Update the set of dependencies for this context. |
178 * automatically set up for the dependencies (if necessary) to ensure that | |
179 * [ContextManagerImpl._handleWatchEvent] is called when they are modified. | |
180 */ | 170 */ |
181 void setDependencies(Iterable<String> newDependencies) { | 171 void setDependencies(Iterable<String> newDependencies) { |
182 for (String oldDependency in _dependencySubscriptions.keys.toList()) { | 172 _dependencies = newDependencies.toSet(); |
183 if (!newDependencies.contains(oldDependency)) { | |
184 StreamSubscription<WatchEvent> subscription = | |
185 _dependencySubscriptions[oldDependency]; | |
186 if (subscription != null) { | |
187 subscription.cancel(); | |
188 } | |
189 _dependencySubscriptions.remove(oldDependency); | |
190 } | |
191 } | |
192 for (String newDependency in newDependencies) { | |
193 if (!_dependencySubscriptions.containsKey(newDependency)) { | |
194 StreamSubscription<WatchEvent> subscription; | |
195 if (!folder.contains(newDependency)) { | |
196 Resource resource = | |
197 contextManager.resourceProvider.getResource(newDependency); | |
198 if (resource is File) { | |
199 subscription = resource.changes.listen((WatchEvent event) { | |
200 contextManager._handleWatchEvent(folder, this, event); | |
201 }, onError: (error, StackTrace stackTrace) { | |
202 // Gracefully degrade if file is or becomes unwatchable | |
203 contextManager._instrumentationService.logException( | |
204 error, stackTrace); | |
205 subscription.cancel(); | |
206 _dependencySubscriptions[newDependency] = null; | |
207 }); | |
208 } | |
209 } | |
210 _dependencySubscriptions[newDependency] = subscription; | |
211 } | |
212 } | |
213 } | 173 } |
214 } | 174 } |
215 | 175 |
216 /** | 176 /** |
217 * Class that maintains a mapping from included/excluded paths to a set of | 177 * Class that maintains a mapping from included/excluded paths to a set of |
218 * folders that should correspond to analysis contexts. | 178 * folders that should correspond to analysis contexts. |
219 */ | 179 */ |
220 abstract class ContextManager { | 180 abstract class ContextManager { |
221 // TODO(brianwilkerson) Support: | 181 // TODO(brianwilkerson) Support: |
222 // setting the default analysis options | 182 // setting the default analysis options |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
426 | 386 |
427 @override | 387 @override |
428 ContextManagerCallbacks callbacks; | 388 ContextManagerCallbacks callbacks; |
429 | 389 |
430 /** | 390 /** |
431 * Virtual [ContextInfo] which acts as the ancestor of all other | 391 * Virtual [ContextInfo] which acts as the ancestor of all other |
432 * [ContextInfo]s. | 392 * [ContextInfo]s. |
433 */ | 393 */ |
434 final ContextInfo _rootInfo = new ContextInfo._root(); | 394 final ContextInfo _rootInfo = new ContextInfo._root(); |
435 | 395 |
| 396 /** |
| 397 * Stream subscription we are using to watch each analysis root directory for |
| 398 * changes. |
| 399 */ |
| 400 final Map<Folder, StreamSubscription<WatchEvent>> _changeSubscriptions = |
| 401 <Folder, StreamSubscription<WatchEvent>>{}; |
| 402 |
436 ContextManagerImpl(this.resourceProvider, this.packageResolverProvider, | 403 ContextManagerImpl(this.resourceProvider, this.packageResolverProvider, |
437 this._packageMapProvider, this._instrumentationService) { | 404 this._packageMapProvider, this._instrumentationService) { |
438 pathContext = resourceProvider.pathContext; | 405 pathContext = resourceProvider.pathContext; |
439 } | 406 } |
440 | 407 |
441 @override | 408 @override |
442 List<AnalysisContext> contextsInAnalysisRoot(Folder analysisRoot) { | 409 List<AnalysisContext> contextsInAnalysisRoot(Folder analysisRoot) { |
443 List<AnalysisContext> contexts = <AnalysisContext>[]; | 410 List<AnalysisContext> contexts = <AnalysisContext>[]; |
444 ContextInfo innermostContainingInfo = | 411 ContextInfo innermostContainingInfo = |
445 _getInnermostContextInfoFor(analysisRoot.path); | 412 _getInnermostContextInfoFor(analysisRoot.path); |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
584 info.packageRoot = newPackageRoot; | 551 info.packageRoot = newPackageRoot; |
585 _recomputeFolderDisposition(info); | 552 _recomputeFolderDisposition(info); |
586 } | 553 } |
587 } | 554 } |
588 // create new contexts | 555 // create new contexts |
589 for (Folder includedFolder in includedFolders) { | 556 for (Folder includedFolder in includedFolders) { |
590 bool wasIncluded = contextInfos.any((info) { | 557 bool wasIncluded = contextInfos.any((info) { |
591 return info.folder.isOrContains(includedFolder.path); | 558 return info.folder.isOrContains(includedFolder.path); |
592 }); | 559 }); |
593 if (!wasIncluded) { | 560 if (!wasIncluded) { |
| 561 _changeSubscriptions[includedFolder] = |
| 562 includedFolder.changes.listen(_handleWatchEvent); |
594 _createContexts(_rootInfo, includedFolder, false); | 563 _createContexts(_rootInfo, includedFolder, false); |
595 } | 564 } |
596 } | 565 } |
597 // remove newly excluded sources | 566 // remove newly excluded sources |
598 for (ContextInfo info in _rootInfo.descendants) { | 567 for (ContextInfo info in _rootInfo.descendants) { |
599 // prepare excluded sources | 568 // prepare excluded sources |
600 Map<String, Source> excludedSources = new HashMap<String, Source>(); | 569 Map<String, Source> excludedSources = new HashMap<String, Source>(); |
601 info.sources.forEach((String path, Source source) { | 570 info.sources.forEach((String path, Source source) { |
602 if (_isExcludedBy(excludedPaths, path) && | 571 if (_isExcludedBy(excludedPaths, path) && |
603 !_isExcludedBy(oldExcludedPaths, path)) { | 572 !_isExcludedBy(oldExcludedPaths, path)) { |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
699 } else if (child is Folder) { | 668 } else if (child is Folder) { |
700 String shortName = child.shortName; | 669 String shortName = child.shortName; |
701 if (shortName == PACKAGES_NAME) { | 670 if (shortName == PACKAGES_NAME) { |
702 continue; | 671 continue; |
703 } | 672 } |
704 _addSourceFiles(changeSet, child, info); | 673 _addSourceFiles(changeSet, child, info); |
705 } | 674 } |
706 } | 675 } |
707 } | 676 } |
708 | 677 |
709 /** | |
710 * Cancel all dependency subscriptions for the given context. | |
711 */ | |
712 void _cancelDependencySubscriptions(ContextInfo info) { | |
713 info.setDependencies(const <String>[]); | |
714 } | |
715 | |
716 void _checkForPackagespecUpdate( | 678 void _checkForPackagespecUpdate( |
717 String path, ContextInfo info, Folder folder) { | 679 String path, ContextInfo info, Folder folder) { |
718 // Check to see if this is the .packages file for this context and if so, | 680 // Check to see if this is the .packages file for this context and if so, |
719 // update the context's source factory. | 681 // update the context's source factory. |
720 if (pathContext.basename(path) == PACKAGE_SPEC_NAME && | 682 if (pathContext.basename(path) == PACKAGE_SPEC_NAME && |
721 info.isPathToPackageDescription(path)) { | 683 info.isPathToPackageDescription(path)) { |
722 File packagespec = resourceProvider.getFile(path); | 684 File packagespec = resourceProvider.getFile(path); |
723 if (packagespec.exists) { | 685 if (packagespec.exists) { |
724 Packages packages = _readPackagespec(packagespec); | 686 Packages packages = _readPackagespec(packagespec); |
725 if (packages != null) { | 687 if (packages != null) { |
(...skipping 21 matching lines...) Expand all Loading... |
747 if (context != contextN) { | 709 if (context != contextN) { |
748 for (Source source in contextN.sources) { | 710 for (Source source in contextN.sources) { |
749 flushedFiles.remove(source.fullName); | 711 flushedFiles.remove(source.fullName); |
750 } | 712 } |
751 } | 713 } |
752 } | 714 } |
753 return flushedFiles.toList(growable: false); | 715 return flushedFiles.toList(growable: false); |
754 } | 716 } |
755 | 717 |
756 /** | 718 /** |
757 * Compute the appropriate [FolderDisposition] for [info]. Use | 719 * Compute the appropriate [FolderDisposition] for [folder]. Use |
758 * [addDependency] to indicate which files needed to be consulted in order to | 720 * [addDependency] to indicate which files needed to be consulted in order to |
759 * figure out the [FolderDisposition]; these dependencies will be watched in | 721 * figure out the [FolderDisposition]; these dependencies will be watched in |
760 * order to determine when it is necessary to call this function again. | 722 * order to determine when it is necessary to call this function again. |
761 * | 723 * |
762 * TODO(paulberry): use [addDependency] for tracking all folder disposition | 724 * TODO(paulberry): use [addDependency] for tracking all folder disposition |
763 * dependencies (currently we only use it to track "pub list" dependencies). | 725 * dependencies (currently we only use it to track "pub list" dependencies). |
764 */ | 726 */ |
765 FolderDisposition _computeFolderDisposition( | 727 FolderDisposition _computeFolderDisposition( |
766 Folder folder, ContextInfo info, void addDependency(String path)) { | 728 Folder folder, void addDependency(String path)) { |
767 if (info.packageRoot != null) { | 729 String packageRoot = normalizedPackageRoots[folder.path]; |
| 730 if (packageRoot != null) { |
768 // TODO(paulberry): We shouldn't be using JavaFile here because it | 731 // TODO(paulberry): We shouldn't be using JavaFile here because it |
769 // makes the code untestable (see dartbug.com/23909). | 732 // makes the code untestable (see dartbug.com/23909). |
770 JavaFile packagesDir = new JavaFile(info.packageRoot); | 733 JavaFile packagesDir = new JavaFile(packageRoot); |
771 Map<String, List<Folder>> packageMap = new Map<String, List<Folder>>(); | 734 Map<String, List<Folder>> packageMap = new Map<String, List<Folder>>(); |
772 if (packagesDir.isDirectory()) { | 735 if (packagesDir.isDirectory()) { |
773 for (JavaFile file in packagesDir.listFiles()) { | 736 for (JavaFile file in packagesDir.listFiles()) { |
774 // Ensure symlinks in packages directory are canonicalized | 737 // Ensure symlinks in packages directory are canonicalized |
775 // to prevent 'type X cannot be assigned to type X' warnings | 738 // to prevent 'type X cannot be assigned to type X' warnings |
776 String path; | 739 String path; |
777 try { | 740 try { |
778 path = file.getCanonicalPath(); | 741 path = file.getCanonicalPath(); |
779 } catch (e, s) { | 742 } catch (e, s) { |
780 // Ignore packages that do not exist | 743 // Ignore packages that do not exist |
781 _instrumentationService.logException(e, s); | 744 _instrumentationService.logException(e, s); |
782 continue; | 745 continue; |
783 } | 746 } |
784 Resource res = resourceProvider.getResource(path); | 747 Resource res = resourceProvider.getResource(path); |
785 if (res is Folder) { | 748 if (res is Folder) { |
786 packageMap[file.getName()] = <Folder>[res]; | 749 packageMap[file.getName()] = <Folder>[res]; |
787 } | 750 } |
788 } | 751 } |
789 return new PackageMapDisposition(packageMap, | 752 return new PackageMapDisposition(packageMap, packageRoot: packageRoot); |
790 packageRoot: info.packageRoot); | |
791 } | 753 } |
792 // The package root does not exist (or is not a folder). Since | 754 // The package root does not exist (or is not a folder). Since |
793 // [setRoots] ignores any package roots that don't exist (or aren't | 755 // [setRoots] ignores any package roots that don't exist (or aren't |
794 // folders), the only way we should be able to get here is due to a race | 756 // folders), the only way we should be able to get here is due to a race |
795 // condition. In any case, the package root folder is gone, so we can't | 757 // condition. In any case, the package root folder is gone, so we can't |
796 // resolve packages. | 758 // resolve packages. |
797 return new NoPackageFolderDisposition(packageRoot: info.packageRoot); | 759 return new NoPackageFolderDisposition(packageRoot: packageRoot); |
798 } else { | 760 } else { |
799 callbacks.beginComputePackageMap(); | 761 callbacks.beginComputePackageMap(); |
800 if (packageResolverProvider != null) { | 762 if (packageResolverProvider != null) { |
801 UriResolver resolver = packageResolverProvider(folder); | 763 UriResolver resolver = packageResolverProvider(folder); |
802 if (resolver != null) { | 764 if (resolver != null) { |
803 return new CustomPackageResolverDisposition(resolver); | 765 return new CustomPackageResolverDisposition(resolver); |
804 } | 766 } |
805 } | 767 } |
806 PackageMapInfo packageMapInfo; | 768 PackageMapInfo packageMapInfo; |
807 ServerPerformanceStatistics.pub.makeCurrentWhile(() { | 769 ServerPerformanceStatistics.pub.makeCurrentWhile(() { |
(...skipping 13 matching lines...) Expand all Loading... |
821 /** | 783 /** |
822 * Create a new empty context associated with [folder], having parent | 784 * Create a new empty context associated with [folder], having parent |
823 * [parent] and using [packagespecFile] to resolve package URI's. | 785 * [parent] and using [packagespecFile] to resolve package URI's. |
824 */ | 786 */ |
825 ContextInfo _createContext( | 787 ContextInfo _createContext( |
826 ContextInfo parent, Folder folder, File packagespecFile) { | 788 ContextInfo parent, Folder folder, File packagespecFile) { |
827 ContextInfo info = new ContextInfo(this, parent, folder, packagespecFile, | 789 ContextInfo info = new ContextInfo(this, parent, folder, packagespecFile, |
828 normalizedPackageRoots[folder.path]); | 790 normalizedPackageRoots[folder.path]); |
829 Map<String, YamlNode> options = analysisOptionsProvider.getOptions(folder); | 791 Map<String, YamlNode> options = analysisOptionsProvider.getOptions(folder); |
830 processOptionsForContext(info, options); | 792 processOptionsForContext(info, options); |
831 info.changeSubscription = folder.changes.listen((WatchEvent event) { | 793 FolderDisposition disposition; |
832 _handleWatchEvent(folder, info, event); | 794 List<String> dependencies = <String>[]; |
833 }); | |
834 try { | |
835 FolderDisposition disposition; | |
836 List<String> dependencies = <String>[]; | |
837 | 795 |
838 if (ENABLE_PACKAGESPEC_SUPPORT) { | 796 if (ENABLE_PACKAGESPEC_SUPPORT) { |
839 // Try .packages first. | 797 // Try .packages first. |
840 if (pathos.basename(packagespecFile.path) == PACKAGE_SPEC_NAME) { | 798 if (pathos.basename(packagespecFile.path) == PACKAGE_SPEC_NAME) { |
841 Packages packages = _readPackagespec(packagespecFile); | 799 Packages packages = _readPackagespec(packagespecFile); |
842 disposition = new PackagesFileDisposition(packages); | 800 disposition = new PackagesFileDisposition(packages); |
843 } | |
844 } | 801 } |
| 802 } |
845 | 803 |
846 // Next resort to a package uri resolver. | 804 // Next resort to a package uri resolver. |
847 if (disposition == null) { | 805 if (disposition == null) { |
848 disposition = _computeFolderDisposition(folder, info, dependencies.add); | 806 disposition = _computeFolderDisposition(folder, dependencies.add); |
849 } | 807 } |
850 | 808 |
851 info.setDependencies(dependencies); | 809 info.setDependencies(dependencies); |
852 info.context = callbacks.addContext(folder, disposition); | 810 info.context = callbacks.addContext(folder, disposition); |
853 info.context.name = folder.path; | 811 info.context.name = folder.path; |
854 } catch (_) { | |
855 info.changeSubscription.cancel(); | |
856 rethrow; | |
857 } | |
858 return info; | 812 return info; |
859 } | 813 } |
860 | 814 |
861 /** | 815 /** |
862 * Potentially create a new context associated with the given [folder]. | 816 * Potentially create a new context associated with the given [folder]. |
863 * | 817 * |
864 * If there are subfolders with 'pubspec.yaml' files, separate contexts are | 818 * If there are subfolders with 'pubspec.yaml' files, separate contexts are |
865 * created for them and excluded from the context associated with the | 819 * created for them and excluded from the context associated with the |
866 * [folder]. | 820 * [folder]. |
867 * | 821 * |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
910 ChangeSet changeSet = new ChangeSet(); | 864 ChangeSet changeSet = new ChangeSet(); |
911 _addSourceFiles(changeSet, folder, parent); | 865 _addSourceFiles(changeSet, folder, parent); |
912 callbacks.applyChangesToContext(folder, changeSet); | 866 callbacks.applyChangesToContext(folder, changeSet); |
913 } | 867 } |
914 } | 868 } |
915 | 869 |
916 /** | 870 /** |
917 * Clean up and destroy the context associated with the given folder. | 871 * Clean up and destroy the context associated with the given folder. |
918 */ | 872 */ |
919 void _destroyContext(ContextInfo info) { | 873 void _destroyContext(ContextInfo info) { |
920 info.changeSubscription.cancel(); | 874 if (_changeSubscriptions.containsKey(info.folder)) { |
921 _cancelDependencySubscriptions(info); | 875 _changeSubscriptions[info.folder].cancel(); |
| 876 } |
922 callbacks.removeContext(info.folder, _computeFlushedFiles(info)); | 877 callbacks.removeContext(info.folder, _computeFlushedFiles(info)); |
923 bool wasRemoved = info.parent.children.remove(info); | 878 bool wasRemoved = info.parent.children.remove(info); |
924 assert(wasRemoved); | 879 assert(wasRemoved); |
925 } | 880 } |
926 | 881 |
927 /** | 882 /** |
928 * Extract a new [packagespecFile]-based context from [oldInfo]. | 883 * Extract a new [packagespecFile]-based context from [oldInfo]. |
929 */ | 884 */ |
930 void _extractContext(ContextInfo oldInfo, File packagespecFile) { | 885 void _extractContext(ContextInfo oldInfo, File packagespecFile) { |
931 Folder newFolder = packagespecFile.parent; | 886 Folder newFolder = packagespecFile.parent; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
976 } | 931 } |
977 while (true) { | 932 while (true) { |
978 ContextInfo childInfo = info.findChildInfoFor(path); | 933 ContextInfo childInfo = info.findChildInfoFor(path); |
979 if (childInfo == null) { | 934 if (childInfo == null) { |
980 return info; | 935 return info; |
981 } | 936 } |
982 info = childInfo; | 937 info = childInfo; |
983 } | 938 } |
984 } | 939 } |
985 | 940 |
986 void _handleWatchEvent(Folder folder, ContextInfo info, WatchEvent event) { | 941 void _handleWatchEvent(WatchEvent event) { |
| 942 // Figure out which context this event applies to. |
987 // TODO(brianwilkerson) If a file is explicitly included in one context | 943 // TODO(brianwilkerson) If a file is explicitly included in one context |
988 // but implicitly referenced in another context, we will only send a | 944 // but implicitly referenced in another context, we will only send a |
989 // changeSet to the context that explicitly includes the file (because | 945 // changeSet to the context that explicitly includes the file (because |
990 // that's the only context that's watching the file). | 946 // that's the only context that's watching the file). |
| 947 ContextInfo info = _getInnermostContextInfoFor(event.path); |
| 948 if (info == null) { |
| 949 // This event doesn't apply to any context. This could happen due to a |
| 950 // race condition (e.g. a context was removed while one of its events was |
| 951 // in the event loop). The event is inapplicable now, so just ignore it. |
| 952 return; |
| 953 } |
991 _instrumentationService.logWatchEvent( | 954 _instrumentationService.logWatchEvent( |
992 folder.path, event.path, event.type.toString()); | 955 info.folder.path, event.path, event.type.toString()); |
993 String path = event.path; | 956 String path = event.path; |
994 // First handle changes that affect folderDisposition (since these need to | 957 // First handle changes that affect folderDisposition (since these need to |
995 // be processed regardless of whether they are part of an excluded/ignored | 958 // be processed regardless of whether they are part of an excluded/ignored |
996 // path). | 959 // path). |
997 if (info.hasDependency(path)) { | 960 if (info.hasDependency(path)) { |
998 _recomputeFolderDisposition(info); | 961 _recomputeFolderDisposition(info); |
999 } | 962 } |
1000 // maybe excluded globally | 963 // maybe excluded globally |
1001 if (_isExcluded(path)) { | 964 if (_isExcluded(path)) { |
1002 return; | 965 return; |
1003 } | 966 } |
1004 // maybe excluded from the context, so other context will handle it | 967 // maybe excluded from the context, so other context will handle it |
1005 if (info.excludes(path)) { | 968 if (info.excludes(path)) { |
1006 return; | 969 return; |
1007 } | 970 } |
1008 if (info.ignored(path)) { | 971 if (info.ignored(path)) { |
1009 return; | 972 return; |
1010 } | 973 } |
1011 // handle the change | 974 // handle the change |
1012 switch (event.type) { | 975 switch (event.type) { |
1013 case ChangeType.ADD: | 976 case ChangeType.ADD: |
1014 if (_isInPackagesDir(path, folder)) { | 977 if (_isInPackagesDir(path, info.folder)) { |
1015 return; | 978 return; |
1016 } | 979 } |
1017 | 980 |
1018 Resource resource = resourceProvider.getResource(path); | 981 Resource resource = resourceProvider.getResource(path); |
1019 | 982 |
1020 if (ENABLE_PACKAGESPEC_SUPPORT) { | 983 if (ENABLE_PACKAGESPEC_SUPPORT) { |
1021 String directoryPath = pathContext.dirname(path); | 984 String directoryPath = pathContext.dirname(path); |
1022 | 985 |
1023 // Check to see if we need to create a new context. | 986 // Check to see if we need to create a new context. |
1024 if (info.isTopLevel) { | 987 if (info.isTopLevel) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1056 | 1019 |
1057 // If the file went away and was replaced by a folder before we | 1020 // If the file went away and was replaced by a folder before we |
1058 // had a chance to process the event, resource might be a Folder. In | 1021 // had a chance to process the event, resource might be a Folder. In |
1059 // that case don't add it. | 1022 // that case don't add it. |
1060 if (resource is File) { | 1023 if (resource is File) { |
1061 File file = resource; | 1024 File file = resource; |
1062 if (callbacks.shouldFileBeAnalyzed(file)) { | 1025 if (callbacks.shouldFileBeAnalyzed(file)) { |
1063 ChangeSet changeSet = new ChangeSet(); | 1026 ChangeSet changeSet = new ChangeSet(); |
1064 Source source = createSourceInContext(info.context, file); | 1027 Source source = createSourceInContext(info.context, file); |
1065 changeSet.addedSource(source); | 1028 changeSet.addedSource(source); |
1066 callbacks.applyChangesToContext(folder, changeSet); | 1029 callbacks.applyChangesToContext(info.folder, changeSet); |
1067 info.sources[path] = source; | 1030 info.sources[path] = source; |
1068 } | 1031 } |
1069 } | 1032 } |
1070 break; | 1033 break; |
1071 case ChangeType.REMOVE: | 1034 case ChangeType.REMOVE: |
1072 | 1035 |
1073 // If package spec info is removed, check to see if we can merge context
s. | 1036 // If package spec info is removed, check to see if we can merge context
s. |
1074 // Note that it's important to verify that there is NEITHER a .packages
nor a | 1037 // Note that it's important to verify that there is NEITHER a .packages
nor a |
1075 // lingering pubspec.yaml before merging. | 1038 // lingering pubspec.yaml before merging. |
1076 if (!info.isTopLevel) { | 1039 if (!info.isTopLevel) { |
(...skipping 26 matching lines...) Expand all Loading... |
1103 } | 1066 } |
1104 } | 1067 } |
1105 } | 1068 } |
1106 | 1069 |
1107 List<Source> sources = info.context.getSourcesWithFullName(path); | 1070 List<Source> sources = info.context.getSourcesWithFullName(path); |
1108 if (!sources.isEmpty) { | 1071 if (!sources.isEmpty) { |
1109 ChangeSet changeSet = new ChangeSet(); | 1072 ChangeSet changeSet = new ChangeSet(); |
1110 sources.forEach((Source source) { | 1073 sources.forEach((Source source) { |
1111 changeSet.removedSource(source); | 1074 changeSet.removedSource(source); |
1112 }); | 1075 }); |
1113 callbacks.applyChangesToContext(folder, changeSet); | 1076 callbacks.applyChangesToContext(info.folder, changeSet); |
1114 info.sources.remove(path); | 1077 info.sources.remove(path); |
1115 } | 1078 } |
1116 break; | 1079 break; |
1117 case ChangeType.MODIFY: | 1080 case ChangeType.MODIFY: |
1118 List<Source> sources = info.context.getSourcesWithFullName(path); | 1081 List<Source> sources = info.context.getSourcesWithFullName(path); |
1119 if (!sources.isEmpty) { | 1082 if (!sources.isEmpty) { |
1120 ChangeSet changeSet = new ChangeSet(); | 1083 ChangeSet changeSet = new ChangeSet(); |
1121 sources.forEach((Source source) { | 1084 sources.forEach((Source source) { |
1122 changeSet.changedSource(source); | 1085 changeSet.changedSource(source); |
1123 }); | 1086 }); |
1124 callbacks.applyChangesToContext(folder, changeSet); | 1087 callbacks.applyChangesToContext(info.folder, changeSet); |
1125 } | 1088 } |
1126 break; | 1089 break; |
1127 } | 1090 } |
1128 | 1091 |
1129 //TODO(pquitslund): find the right place for this | 1092 //TODO(pquitslund): find the right place for this |
1130 _checkForPackagespecUpdate(path, info, folder); | 1093 _checkForPackagespecUpdate(path, info, info.folder); |
1131 } | 1094 } |
1132 | 1095 |
1133 /** | 1096 /** |
1134 * Returns `true` if the given [path] is excluded by [excludedPaths]. | 1097 * Returns `true` if the given [path] is excluded by [excludedPaths]. |
1135 */ | 1098 */ |
1136 bool _isExcluded(String path) => _isExcludedBy(excludedPaths, path); | 1099 bool _isExcluded(String path) => _isExcludedBy(excludedPaths, path); |
1137 | 1100 |
1138 /** | 1101 /** |
1139 * Returns `true` if the given [path] is excluded by [excludedPaths]. | 1102 * Returns `true` if the given [path] is excluded by [excludedPaths]. |
1140 */ | 1103 */ |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1197 * Recompute the [FolderDisposition] for the context described by [info], | 1160 * Recompute the [FolderDisposition] for the context described by [info], |
1198 * and update the client appropriately. | 1161 * and update the client appropriately. |
1199 */ | 1162 */ |
1200 void _recomputeFolderDisposition(ContextInfo info) { | 1163 void _recomputeFolderDisposition(ContextInfo info) { |
1201 // TODO(paulberry): when computePackageMap is changed into an | 1164 // TODO(paulberry): when computePackageMap is changed into an |
1202 // asynchronous API call, we'll want to suspend analysis for this context | 1165 // asynchronous API call, we'll want to suspend analysis for this context |
1203 // while we're rerunning "pub list", since any analysis we complete while | 1166 // while we're rerunning "pub list", since any analysis we complete while |
1204 // "pub list" is in progress is just going to get thrown away anyhow. | 1167 // "pub list" is in progress is just going to get thrown away anyhow. |
1205 List<String> dependencies = <String>[]; | 1168 List<String> dependencies = <String>[]; |
1206 FolderDisposition disposition = | 1169 FolderDisposition disposition = |
1207 _computeFolderDisposition(info.folder, info, dependencies.add); | 1170 _computeFolderDisposition(info.folder, dependencies.add); |
1208 info.setDependencies(dependencies); | 1171 info.setDependencies(dependencies); |
1209 callbacks.updateContextPackageUriResolver(info.folder, disposition); | 1172 callbacks.updateContextPackageUriResolver(info.folder, disposition); |
1210 } | 1173 } |
1211 | 1174 |
1212 /** | 1175 /** |
1213 * Create and return a source representing the given [file] within the given | 1176 * Create and return a source representing the given [file] within the given |
1214 * [context]. | 1177 * [context]. |
1215 */ | 1178 */ |
1216 static Source createSourceInContext(AnalysisContext context, File file) { | 1179 static Source createSourceInContext(AnalysisContext context, File file) { |
1217 // TODO(brianwilkerson) Optimize this, by allowing support for source | 1180 // TODO(brianwilkerson) Optimize this, by allowing support for source |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1369 | 1332 |
1370 PackagesFileDisposition(this.packages) {} | 1333 PackagesFileDisposition(this.packages) {} |
1371 | 1334 |
1372 @override | 1335 @override |
1373 String get packageRoot => null; | 1336 String get packageRoot => null; |
1374 | 1337 |
1375 @override | 1338 @override |
1376 Iterable<UriResolver> createPackageUriResolvers( | 1339 Iterable<UriResolver> createPackageUriResolvers( |
1377 ResourceProvider resourceProvider) => const <UriResolver>[]; | 1340 ResourceProvider resourceProvider) => const <UriResolver>[]; |
1378 } | 1341 } |
OLD | NEW |