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 |