| 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 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 237 * created, destroyed or updated, (b) inform the client when "pub list" | 237 * created, destroyed or updated, (b) inform the client when "pub list" |
| 238 * operations are in progress, and (c) determine which files should be | 238 * operations are in progress, and (c) determine which files should be |
| 239 * analyzed. | 239 * analyzed. |
| 240 * | 240 * |
| 241 * TODO(paulberry): eliminate this interface, and instead have [ContextManager] | 241 * TODO(paulberry): eliminate this interface, and instead have [ContextManager] |
| 242 * operations return data structures describing how context state should be | 242 * operations return data structures describing how context state should be |
| 243 * modified. | 243 * modified. |
| 244 */ | 244 */ |
| 245 abstract class ContextManagerCallbacks { | 245 abstract class ContextManagerCallbacks { |
| 246 /** | 246 /** |
| 247 * Create and return a new analysis context. | 247 * Create and return a new analysis context, allowing [disposition] to govern |
| 248 * details of how the context is to be created. |
| 248 */ | 249 */ |
| 249 AnalysisContext addContext( | 250 AnalysisContext addContext(Folder folder, FolderDisposition disposition); |
| 250 Folder folder, UriResolver packageUriResolver, Packages packages); | |
| 251 | 251 |
| 252 /** | 252 /** |
| 253 * Called when the set of files associated with a context have changed (or | 253 * Called when the set of files associated with a context have changed (or |
| 254 * some of those files have been modified). [changeSet] is the set of | 254 * some of those files have been modified). [changeSet] is the set of |
| 255 * changes that need to be applied to the context. | 255 * changes that need to be applied to the context. |
| 256 */ | 256 */ |
| 257 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet); | 257 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet); |
| 258 | 258 |
| 259 /** | 259 /** |
| 260 * Called when the ContextManager is about to start computing the package | 260 * Called when the ContextManager is about to start computing the package |
| (...skipping 16 matching lines...) Expand all Loading... |
| 277 * (they will no longer be analyzed by any context). | 277 * (they will no longer be analyzed by any context). |
| 278 */ | 278 */ |
| 279 void removeContext(Folder folder, List<String> flushedFiles); | 279 void removeContext(Folder folder, List<String> flushedFiles); |
| 280 | 280 |
| 281 /** | 281 /** |
| 282 * Return `true` if the given [file] should be analyzed. | 282 * Return `true` if the given [file] should be analyzed. |
| 283 */ | 283 */ |
| 284 bool shouldFileBeAnalyzed(File file); | 284 bool shouldFileBeAnalyzed(File file); |
| 285 | 285 |
| 286 /** | 286 /** |
| 287 * Called when the package map for a context has changed. | 287 * Called when the disposition for a context has changed. |
| 288 */ | 288 */ |
| 289 void updateContextPackageUriResolver( | 289 void updateContextPackageUriResolver( |
| 290 Folder contextFolder, UriResolver packageUriResolver, Packages packages); | 290 Folder contextFolder, FolderDisposition disposition); |
| 291 } | 291 } |
| 292 | 292 |
| 293 /** | 293 /** |
| 294 * Class that maintains a mapping from included/excluded paths to a set of | 294 * Class that maintains a mapping from included/excluded paths to a set of |
| 295 * folders that should correspond to analysis contexts. | 295 * folders that should correspond to analysis contexts. |
| 296 */ | 296 */ |
| 297 class ContextManagerImpl implements ContextManager { | 297 class ContextManagerImpl implements ContextManager { |
| 298 /** | 298 /** |
| 299 * Temporary flag to hide WIP .packages support (DEP 5). | 299 * Temporary flag to hide WIP .packages support (DEP 5). |
| 300 */ | 300 */ |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 526 }); | 526 }); |
| 527 if (!isIncluded) { | 527 if (!isIncluded) { |
| 528 _destroyContext(contextInfo); | 528 _destroyContext(contextInfo); |
| 529 } | 529 } |
| 530 } | 530 } |
| 531 // Update package roots for existing contexts | 531 // Update package roots for existing contexts |
| 532 for (ContextInfo info in _rootInfo.descendants) { | 532 for (ContextInfo info in _rootInfo.descendants) { |
| 533 String newPackageRoot = normalizedPackageRoots[info.folder.path]; | 533 String newPackageRoot = normalizedPackageRoots[info.folder.path]; |
| 534 if (info.packageRoot != newPackageRoot) { | 534 if (info.packageRoot != newPackageRoot) { |
| 535 info.packageRoot = newPackageRoot; | 535 info.packageRoot = newPackageRoot; |
| 536 _recomputePackageUriResolver(info); | 536 _recomputeFolderDisposition(info); |
| 537 } | 537 } |
| 538 } | 538 } |
| 539 // create new contexts | 539 // create new contexts |
| 540 for (Folder includedFolder in includedFolders) { | 540 for (Folder includedFolder in includedFolders) { |
| 541 bool wasIncluded = contextInfos.any((info) { | 541 bool wasIncluded = contextInfos.any((info) { |
| 542 return info.folder.isOrContains(includedFolder.path); | 542 return info.folder.isOrContains(includedFolder.path); |
| 543 }); | 543 }); |
| 544 if (!wasIncluded) { | 544 if (!wasIncluded) { |
| 545 _createContexts(_rootInfo, includedFolder, false); | 545 _createContexts(_rootInfo, includedFolder, false); |
| 546 } | 546 } |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 670 void _checkForPackagespecUpdate( | 670 void _checkForPackagespecUpdate( |
| 671 String path, ContextInfo info, Folder folder) { | 671 String path, ContextInfo info, Folder folder) { |
| 672 // Check to see if this is the .packages file for this context and if so, | 672 // Check to see if this is the .packages file for this context and if so, |
| 673 // update the context's source factory. | 673 // update the context's source factory. |
| 674 if (pathContext.basename(path) == PACKAGE_SPEC_NAME && | 674 if (pathContext.basename(path) == PACKAGE_SPEC_NAME && |
| 675 info.isPathToPackageDescription(path)) { | 675 info.isPathToPackageDescription(path)) { |
| 676 File packagespec = resourceProvider.getFile(path); | 676 File packagespec = resourceProvider.getFile(path); |
| 677 if (packagespec.exists) { | 677 if (packagespec.exists) { |
| 678 Packages packages = _readPackagespec(packagespec); | 678 Packages packages = _readPackagespec(packagespec); |
| 679 if (packages != null) { | 679 if (packages != null) { |
| 680 callbacks.updateContextPackageUriResolver(folder, null, packages); | 680 callbacks.updateContextPackageUriResolver( |
| 681 folder, new PackagesFileDisposition(packages)); |
| 681 } | 682 } |
| 682 } | 683 } |
| 683 } | 684 } |
| 684 } | 685 } |
| 685 | 686 |
| 686 /** | 687 /** |
| 687 * Compute the set of files that are being flushed, this is defined as | 688 * Compute the set of files that are being flushed, this is defined as |
| 688 * the set of sources in the removed context (context.sources), that are | 689 * the set of sources in the removed context (context.sources), that are |
| 689 * orphaned by this context being removed (no other context includes this | 690 * orphaned by this context being removed (no other context includes this |
| 690 * file.) | 691 * file.) |
| 691 */ | 692 */ |
| 692 List<String> _computeFlushedFiles(ContextInfo info) { | 693 List<String> _computeFlushedFiles(ContextInfo info) { |
| 693 AnalysisContext context = info.context; | 694 AnalysisContext context = info.context; |
| 694 HashSet<String> flushedFiles = new HashSet<String>(); | 695 HashSet<String> flushedFiles = new HashSet<String>(); |
| 695 for (Source source in context.sources) { | 696 for (Source source in context.sources) { |
| 696 flushedFiles.add(source.fullName); | 697 flushedFiles.add(source.fullName); |
| 697 } | 698 } |
| 698 for (ContextInfo contextInfo in _rootInfo.descendants) { | 699 for (ContextInfo contextInfo in _rootInfo.descendants) { |
| 699 AnalysisContext contextN = contextInfo.context; | 700 AnalysisContext contextN = contextInfo.context; |
| 700 if (context != contextN) { | 701 if (context != contextN) { |
| 701 for (Source source in contextN.sources) { | 702 for (Source source in contextN.sources) { |
| 702 flushedFiles.remove(source.fullName); | 703 flushedFiles.remove(source.fullName); |
| 703 } | 704 } |
| 704 } | 705 } |
| 705 } | 706 } |
| 706 return flushedFiles.toList(growable: false); | 707 return flushedFiles.toList(growable: false); |
| 707 } | 708 } |
| 708 | 709 |
| 709 /** | 710 /** |
| 710 * Compute the appropriate package URI resolver for [folder], and store | 711 * Compute the appropriate [FolderDisposition] for [folder], and store |
| 711 * dependency information in [info]. Return `null` if no package map can | 712 * dependency information in [info]. |
| 712 * be computed. | |
| 713 */ | 713 */ |
| 714 UriResolver _computePackageUriResolver(Folder folder, ContextInfo info) { | 714 FolderDisposition _computeFolderDisposition(Folder folder, ContextInfo info) { |
| 715 _cancelDependencySubscriptions(info); | 715 _cancelDependencySubscriptions(info); |
| 716 if (info.packageRoot != null) { | 716 if (info.packageRoot != null) { |
| 717 info.packageMapInfo = null; | 717 info.packageMapInfo = null; |
| 718 // TODO(paulberry): We shouldn't be using JavaFile here because it | 718 // TODO(paulberry): We shouldn't be using JavaFile here because it |
| 719 // makes the code untestable (see dartbug.com/23909). | 719 // makes the code untestable (see dartbug.com/23909). |
| 720 JavaFile packagesDir = new JavaFile(info.packageRoot); | 720 JavaFile packagesDir = new JavaFile(info.packageRoot); |
| 721 Map<String, List<Folder>> packageMap = new Map<String, List<Folder>>(); | 721 Map<String, List<Folder>> packageMap = new Map<String, List<Folder>>(); |
| 722 if (packagesDir.isDirectory()) { | 722 if (packagesDir.isDirectory()) { |
| 723 for (JavaFile file in packagesDir.listFiles()) { | 723 for (JavaFile file in packagesDir.listFiles()) { |
| 724 // Ensure symlinks in packages directory are canonicalized | 724 // Ensure symlinks in packages directory are canonicalized |
| 725 // to prevent 'type X cannot be assigned to type X' warnings | 725 // to prevent 'type X cannot be assigned to type X' warnings |
| 726 String path; | 726 String path; |
| 727 try { | 727 try { |
| 728 path = file.getCanonicalPath(); | 728 path = file.getCanonicalPath(); |
| 729 } catch (e, s) { | 729 } catch (e, s) { |
| 730 // Ignore packages that do not exist | 730 // Ignore packages that do not exist |
| 731 _instrumentationService.logException(e, s); | 731 _instrumentationService.logException(e, s); |
| 732 continue; | 732 continue; |
| 733 } | 733 } |
| 734 Resource res = resourceProvider.getResource(path); | 734 Resource res = resourceProvider.getResource(path); |
| 735 if (res is Folder) { | 735 if (res is Folder) { |
| 736 packageMap[file.getName()] = <Folder>[res]; | 736 packageMap[file.getName()] = <Folder>[res]; |
| 737 } | 737 } |
| 738 } | 738 } |
| 739 return new PackageMapUriResolver(resourceProvider, packageMap); | 739 return new PackageMapDisposition(packageMap); |
| 740 } | 740 } |
| 741 // The package root does not exist (or is not a folder). Since | 741 // The package root does not exist (or is not a folder). Since |
| 742 // [setRoots] ignores any package roots that don't exist (or aren't | 742 // [setRoots] ignores any package roots that don't exist (or aren't |
| 743 // folders), the only way we should be able to get here is due to a race | 743 // folders), the only way we should be able to get here is due to a race |
| 744 // condition. In any case, the package root folder is gone, so we can't | 744 // condition. In any case, the package root folder is gone, so we can't |
| 745 // resolve packages. | 745 // resolve packages. |
| 746 return null; | 746 return new NoPackageFolderDisposition(); |
| 747 } else { | 747 } else { |
| 748 callbacks.beginComputePackageMap(); | 748 callbacks.beginComputePackageMap(); |
| 749 if (packageResolverProvider != null) { | 749 if (packageResolverProvider != null) { |
| 750 UriResolver resolver = packageResolverProvider(folder); | 750 UriResolver resolver = packageResolverProvider(folder); |
| 751 if (resolver != null) { | 751 if (resolver != null) { |
| 752 return resolver; | 752 return new CustomPackageResolverDisposition(resolver); |
| 753 } | 753 } |
| 754 } | 754 } |
| 755 OptimizingPubPackageMapInfo packageMapInfo; | 755 OptimizingPubPackageMapInfo packageMapInfo; |
| 756 ServerPerformanceStatistics.pub.makeCurrentWhile(() { | 756 ServerPerformanceStatistics.pub.makeCurrentWhile(() { |
| 757 packageMapInfo = | 757 packageMapInfo = |
| 758 _packageMapProvider.computePackageMap(folder, info.packageMapInfo); | 758 _packageMapProvider.computePackageMap(folder, info.packageMapInfo); |
| 759 }); | 759 }); |
| 760 callbacks.endComputePackageMap(); | 760 callbacks.endComputePackageMap(); |
| 761 for (String dependencyPath in packageMapInfo.dependencies) { | 761 for (String dependencyPath in packageMapInfo.dependencies) { |
| 762 Resource resource = resourceProvider.getResource(dependencyPath); | 762 Resource resource = resourceProvider.getResource(dependencyPath); |
| 763 if (resource is File) { | 763 if (resource is File) { |
| 764 StreamSubscription<WatchEvent> subscription; | 764 StreamSubscription<WatchEvent> subscription; |
| 765 subscription = resource.changes.listen((WatchEvent event) { | 765 subscription = resource.changes.listen((WatchEvent event) { |
| 766 if (info.packageMapInfo != null && | 766 if (info.packageMapInfo != null && |
| 767 info.packageMapInfo.isChangedDependency( | 767 info.packageMapInfo.isChangedDependency( |
| 768 dependencyPath, resourceProvider)) { | 768 dependencyPath, resourceProvider)) { |
| 769 _recomputePackageUriResolver(info); | 769 _recomputeFolderDisposition(info); |
| 770 } | 770 } |
| 771 }, onError: (error, StackTrace stackTrace) { | 771 }, onError: (error, StackTrace stackTrace) { |
| 772 // Gracefully degrade if file is or becomes unwatchable | 772 // Gracefully degrade if file is or becomes unwatchable |
| 773 _instrumentationService.logException(error, stackTrace); | 773 _instrumentationService.logException(error, stackTrace); |
| 774 subscription.cancel(); | 774 subscription.cancel(); |
| 775 info.dependencySubscriptions.remove(subscription); | 775 info.dependencySubscriptions.remove(subscription); |
| 776 }); | 776 }); |
| 777 info.dependencySubscriptions.add(subscription); | 777 info.dependencySubscriptions.add(subscription); |
| 778 } | 778 } |
| 779 } | 779 } |
| 780 info.packageMapInfo = packageMapInfo; | 780 info.packageMapInfo = packageMapInfo; |
| 781 if (packageMapInfo.packageMap == null) { | 781 if (packageMapInfo.packageMap == null) { |
| 782 return null; | 782 return new NoPackageFolderDisposition(); |
| 783 } | 783 } |
| 784 return new PackageMapUriResolver( | 784 return new PackageMapDisposition(packageMapInfo.packageMap); |
| 785 resourceProvider, packageMapInfo.packageMap); | |
| 786 // TODO(paulberry): if any of the dependencies is outside of [folder], | |
| 787 // we'll need to watch their parent folders as well. | |
| 788 } | 785 } |
| 789 } | 786 } |
| 790 | 787 |
| 791 /** | 788 /** |
| 792 * Create a new empty context associated with [folder], having parent | 789 * Create a new empty context associated with [folder], having parent |
| 793 * [parent] and using [packagespecFile] to resolve package URI's. | 790 * [parent] and using [packagespecFile] to resolve package URI's. |
| 794 */ | 791 */ |
| 795 ContextInfo _createContext( | 792 ContextInfo _createContext( |
| 796 ContextInfo parent, Folder folder, File packagespecFile) { | 793 ContextInfo parent, Folder folder, File packagespecFile) { |
| 797 ContextInfo info = new ContextInfo( | 794 ContextInfo info = new ContextInfo( |
| 798 parent, folder, packagespecFile, normalizedPackageRoots[folder.path]); | 795 parent, folder, packagespecFile, normalizedPackageRoots[folder.path]); |
| 799 Map<String, YamlNode> options = analysisOptionsProvider.getOptions(folder); | 796 Map<String, YamlNode> options = analysisOptionsProvider.getOptions(folder); |
| 800 processOptionsForContext(info, options); | 797 processOptionsForContext(info, options); |
| 801 info.changeSubscription = folder.changes.listen((WatchEvent event) { | 798 info.changeSubscription = folder.changes.listen((WatchEvent event) { |
| 802 _handleWatchEvent(folder, info, event); | 799 _handleWatchEvent(folder, info, event); |
| 803 }); | 800 }); |
| 804 try { | 801 try { |
| 805 Packages packages; | 802 FolderDisposition disposition; |
| 806 UriResolver packageUriResolver; | |
| 807 | 803 |
| 808 if (ENABLE_PACKAGESPEC_SUPPORT) { | 804 if (ENABLE_PACKAGESPEC_SUPPORT) { |
| 809 // Try .packages first. | 805 // Try .packages first. |
| 810 if (pathos.basename(packagespecFile.path) == PACKAGE_SPEC_NAME) { | 806 if (pathos.basename(packagespecFile.path) == PACKAGE_SPEC_NAME) { |
| 811 packages = _readPackagespec(packagespecFile); | 807 Packages packages = _readPackagespec(packagespecFile); |
| 808 disposition = new PackagesFileDisposition(packages); |
| 812 } | 809 } |
| 813 } | 810 } |
| 814 | 811 |
| 815 // Next resort to a package uri resolver. | 812 // Next resort to a package uri resolver. |
| 816 if (packages == null) { | 813 if (disposition == null) { |
| 817 packageUriResolver = _computePackageUriResolver(folder, info); | 814 disposition = _computeFolderDisposition(folder, info); |
| 818 } | 815 } |
| 819 | 816 |
| 820 info.context = callbacks.addContext(folder, packageUriResolver, packages); | 817 info.context = callbacks.addContext(folder, disposition); |
| 821 info.context.name = folder.path; | 818 info.context.name = folder.path; |
| 822 } catch (_) { | 819 } catch (_) { |
| 823 info.changeSubscription.cancel(); | 820 info.changeSubscription.cancel(); |
| 824 rethrow; | 821 rethrow; |
| 825 } | 822 } |
| 826 return info; | 823 return info; |
| 827 } | 824 } |
| 828 | 825 |
| 829 /** | 826 /** |
| 830 * Potentially create a new context associated with the given [folder]. | 827 * Potentially create a new context associated with the given [folder]. |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1086 callbacks.applyChangesToContext(folder, changeSet); | 1083 callbacks.applyChangesToContext(folder, changeSet); |
| 1087 } | 1084 } |
| 1088 break; | 1085 break; |
| 1089 } | 1086 } |
| 1090 | 1087 |
| 1091 //TODO(pquitslund): find the right place for this | 1088 //TODO(pquitslund): find the right place for this |
| 1092 _checkForPackagespecUpdate(path, info, folder); | 1089 _checkForPackagespecUpdate(path, info, folder); |
| 1093 | 1090 |
| 1094 if (info.packageMapInfo != null && | 1091 if (info.packageMapInfo != null && |
| 1095 info.packageMapInfo.isChangedDependency(path, resourceProvider)) { | 1092 info.packageMapInfo.isChangedDependency(path, resourceProvider)) { |
| 1096 _recomputePackageUriResolver(info); | 1093 _recomputeFolderDisposition(info); |
| 1097 } | 1094 } |
| 1098 } | 1095 } |
| 1099 | 1096 |
| 1100 /** | 1097 /** |
| 1101 * Returns `true` if the given [path] is excluded by [excludedPaths]. | 1098 * Returns `true` if the given [path] is excluded by [excludedPaths]. |
| 1102 */ | 1099 */ |
| 1103 bool _isExcluded(String path) => _isExcludedBy(excludedPaths, path); | 1100 bool _isExcluded(String path) => _isExcludedBy(excludedPaths, path); |
| 1104 | 1101 |
| 1105 /** | 1102 /** |
| 1106 * Returns `true` if the given [path] is excluded by [excludedPaths]. | 1103 * Returns `true` if the given [path] is excluded by [excludedPaths]. |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1154 Map<String, Uri> map = | 1151 Map<String, Uri> map = |
| 1155 pkgfile.parse(UTF8.encode(contents), new Uri.file(specFile.path)); | 1152 pkgfile.parse(UTF8.encode(contents), new Uri.file(specFile.path)); |
| 1156 return new MapPackages(map); | 1153 return new MapPackages(map); |
| 1157 } catch (_) { | 1154 } catch (_) { |
| 1158 //TODO(pquitslund): consider creating an error for the spec file. | 1155 //TODO(pquitslund): consider creating an error for the spec file. |
| 1159 return null; | 1156 return null; |
| 1160 } | 1157 } |
| 1161 } | 1158 } |
| 1162 | 1159 |
| 1163 /** | 1160 /** |
| 1164 * Recompute the package URI resolver for the context described by [info], | 1161 * Recompute the [FolderDisposition] for the context described by [info], |
| 1165 * and update the client appropriately. | 1162 * and update the client appropriately. |
| 1166 */ | 1163 */ |
| 1167 void _recomputePackageUriResolver(ContextInfo info) { | 1164 void _recomputeFolderDisposition(ContextInfo info) { |
| 1168 // TODO(paulberry): when computePackageMap is changed into an | 1165 // TODO(paulberry): when computePackageMap is changed into an |
| 1169 // asynchronous API call, we'll want to suspend analysis for this context | 1166 // asynchronous API call, we'll want to suspend analysis for this context |
| 1170 // while we're rerunning "pub list", since any analysis we complete while | 1167 // while we're rerunning "pub list", since any analysis we complete while |
| 1171 // "pub list" is in progress is just going to get thrown away anyhow. | 1168 // "pub list" is in progress is just going to get thrown away anyhow. |
| 1172 UriResolver packageUriResolver = | 1169 FolderDisposition disposition = |
| 1173 _computePackageUriResolver(info.folder, info); | 1170 _computeFolderDisposition(info.folder, info); |
| 1174 callbacks.updateContextPackageUriResolver( | 1171 callbacks.updateContextPackageUriResolver(info.folder, disposition); |
| 1175 info.folder, packageUriResolver, null); | |
| 1176 } | 1172 } |
| 1177 | 1173 |
| 1178 /** | 1174 /** |
| 1179 * Create and return a source representing the given [file] within the given | 1175 * Create and return a source representing the given [file] within the given |
| 1180 * [context]. | 1176 * [context]. |
| 1181 */ | 1177 */ |
| 1182 static Source createSourceInContext(AnalysisContext context, File file) { | 1178 static Source createSourceInContext(AnalysisContext context, File file) { |
| 1183 // TODO(brianwilkerson) Optimize this, by allowing support for source | 1179 // TODO(brianwilkerson) Optimize this, by allowing support for source |
| 1184 // factories to restore URI's from a file path rather than a source. | 1180 // factories to restore URI's from a file path rather than a source. |
| 1185 Source source = file.createSource(); | 1181 Source source = file.createSource(); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1215 */ | 1211 */ |
| 1216 final List<AnalysisContext> removed; | 1212 final List<AnalysisContext> removed; |
| 1217 | 1213 |
| 1218 /** | 1214 /** |
| 1219 * Initialize a newly created event to indicate which contexts have changed. | 1215 * Initialize a newly created event to indicate which contexts have changed. |
| 1220 */ | 1216 */ |
| 1221 ContextsChangedEvent({this.added: AnalysisContext.EMPTY_LIST, | 1217 ContextsChangedEvent({this.added: AnalysisContext.EMPTY_LIST, |
| 1222 this.changed: AnalysisContext.EMPTY_LIST, | 1218 this.changed: AnalysisContext.EMPTY_LIST, |
| 1223 this.removed: AnalysisContext.EMPTY_LIST}); | 1219 this.removed: AnalysisContext.EMPTY_LIST}); |
| 1224 } | 1220 } |
| 1221 |
| 1222 /** |
| 1223 * Concrete [FolderDisposition] object indicating that the context for a given |
| 1224 * folder should resolve package URIs using a custom URI resolver. |
| 1225 */ |
| 1226 class CustomPackageResolverDisposition extends FolderDisposition { |
| 1227 /** |
| 1228 * The [UriResolver] that should be used to resolve package URIs. |
| 1229 */ |
| 1230 UriResolver resolver; |
| 1231 |
| 1232 CustomPackageResolverDisposition(this.resolver); |
| 1233 |
| 1234 @override |
| 1235 Packages get packages => null; |
| 1236 |
| 1237 @override |
| 1238 Iterable<UriResolver> createPackageUriResolvers( |
| 1239 ResourceProvider resourceProvider) => <UriResolver>[resolver]; |
| 1240 } |
| 1241 |
| 1242 /** |
| 1243 * An instance of the class [FolderDisposition] represents the information |
| 1244 * gathered by the [ContextManagerImpl] to determine how to create an |
| 1245 * [AnalysisContext] for a given folder. |
| 1246 * |
| 1247 * Note: [ContextManagerImpl] may use equality testing and hash codes to |
| 1248 * determine when two folders should share the same context, so derived classes |
| 1249 * may need to override operator== and hashCode() if object identity is |
| 1250 * insufficient. |
| 1251 * |
| 1252 * TODO(paulberry): consider adding a flag to indicate that it is not necessary |
| 1253 * to recurse into the given folder looking for additional contexts to create |
| 1254 * or files to analyze (this could help avoid unnecessarily weighing down the |
| 1255 * system with file watchers). |
| 1256 */ |
| 1257 abstract class FolderDisposition { |
| 1258 /** |
| 1259 * If contexts governed by this [FolderDisposition] should resolve packages |
| 1260 * using the ".packages" file mechanism (DEP 5), retrieve the [Packages] |
| 1261 * object that resulted from parsing the ".packages" file. |
| 1262 */ |
| 1263 Packages get packages; |
| 1264 |
| 1265 /** |
| 1266 * Create all the [UriResolver]s which should be used to resolve packages in |
| 1267 * contexts governed by this [FolderDisposition]. |
| 1268 * |
| 1269 * [resourceProvider] is provided since it is needed to construct most |
| 1270 * [UriResolver]s. |
| 1271 */ |
| 1272 Iterable<UriResolver> createPackageUriResolvers( |
| 1273 ResourceProvider resourceProvider); |
| 1274 } |
| 1275 |
| 1276 /** |
| 1277 * Concrete [FolderDisposition] object indicating that the context for a given |
| 1278 * folder should not resolve "package:" URIs at all. |
| 1279 * |
| 1280 * TODO(paulberry): consider making this a singleton object (which would cause |
| 1281 * all folders that don't resolve "package:" URIs to share the same context). |
| 1282 */ |
| 1283 class NoPackageFolderDisposition extends FolderDisposition { |
| 1284 @override |
| 1285 Packages get packages => null; |
| 1286 |
| 1287 @override |
| 1288 Iterable<UriResolver> createPackageUriResolvers( |
| 1289 ResourceProvider resourceProvider) => const <UriResolver>[]; |
| 1290 } |
| 1291 |
| 1292 /** |
| 1293 * Concrete [FolderDisposition] object indicating that the context for a given |
| 1294 * folder should resolve packages using a package map. |
| 1295 */ |
| 1296 class PackageMapDisposition extends FolderDisposition { |
| 1297 final Map<String, List<Folder>> packageMap; |
| 1298 |
| 1299 PackageMapDisposition(this.packageMap); |
| 1300 |
| 1301 @override |
| 1302 Packages get packages => null; |
| 1303 |
| 1304 @override |
| 1305 Iterable<UriResolver> createPackageUriResolvers( |
| 1306 ResourceProvider resourceProvider) => |
| 1307 <UriResolver>[new PackageMapUriResolver(resourceProvider, packageMap)]; |
| 1308 } |
| 1309 |
| 1310 /** |
| 1311 * Concrete [FolderDisposition] object indicating that the context for a given |
| 1312 * folder should resolve packages using a ".packages" file. |
| 1313 */ |
| 1314 class PackagesFileDisposition extends FolderDisposition { |
| 1315 @override |
| 1316 final Packages packages; |
| 1317 |
| 1318 PackagesFileDisposition(this.packages) {} |
| 1319 |
| 1320 @override |
| 1321 Iterable<UriResolver> createPackageUriResolvers( |
| 1322 ResourceProvider resourceProvider) => const <UriResolver>[]; |
| 1323 } |
| OLD | NEW |