| 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 |