| 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 712 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 723 /** | 723 /** |
| 724 * Compute the appropriate [FolderDisposition] for [folder]. Use | 724 * Compute the appropriate [FolderDisposition] for [folder]. Use |
| 725 * [addDependency] to indicate which files needed to be consulted in order to | 725 * [addDependency] to indicate which files needed to be consulted in order to |
| 726 * figure out the [FolderDisposition]; these dependencies will be watched in | 726 * figure out the [FolderDisposition]; these dependencies will be watched in |
| 727 * order to determine when it is necessary to call this function again. | 727 * order to determine when it is necessary to call this function again. |
| 728 * | 728 * |
| 729 * TODO(paulberry): use [addDependency] for tracking all folder disposition | 729 * TODO(paulberry): use [addDependency] for tracking all folder disposition |
| 730 * dependencies (currently we only use it to track "pub list" dependencies). | 730 * dependencies (currently we only use it to track "pub list" dependencies). |
| 731 */ | 731 */ |
| 732 FolderDisposition _computeFolderDisposition( | 732 FolderDisposition _computeFolderDisposition( |
| 733 Folder folder, void addDependency(String path)) { | 733 Folder folder, void addDependency(String path), File packagespecFile) { |
| 734 String packageRoot = normalizedPackageRoots[folder.path]; | 734 String packageRoot = normalizedPackageRoots[folder.path]; |
| 735 if (packageRoot != null) { | 735 if (packageRoot != null) { |
| 736 // TODO(paulberry): We shouldn't be using JavaFile here because it | 736 // TODO(paulberry): We shouldn't be using JavaFile here because it |
| 737 // makes the code untestable (see dartbug.com/23909). | 737 // makes the code untestable (see dartbug.com/23909). |
| 738 JavaFile packagesDir = new JavaFile(packageRoot); | 738 JavaFile packagesDir = new JavaFile(packageRoot); |
| 739 Map<String, List<Folder>> packageMap = new Map<String, List<Folder>>(); | 739 Map<String, List<Folder>> packageMap = new Map<String, List<Folder>>(); |
| 740 if (packagesDir.isDirectory()) { | 740 if (packagesDir.isDirectory()) { |
| 741 for (JavaFile file in packagesDir.listFiles()) { | 741 for (JavaFile file in packagesDir.listFiles()) { |
| 742 // Ensure symlinks in packages directory are canonicalized | 742 // Ensure symlinks in packages directory are canonicalized |
| 743 // to prevent 'type X cannot be assigned to type X' warnings | 743 // to prevent 'type X cannot be assigned to type X' warnings |
| (...skipping 12 matching lines...) Expand all Loading... |
| 756 } | 756 } |
| 757 return new PackageMapDisposition(packageMap, packageRoot: packageRoot); | 757 return new PackageMapDisposition(packageMap, packageRoot: packageRoot); |
| 758 } | 758 } |
| 759 // The package root does not exist (or is not a folder). Since | 759 // The package root does not exist (or is not a folder). Since |
| 760 // [setRoots] ignores any package roots that don't exist (or aren't | 760 // [setRoots] ignores any package roots that don't exist (or aren't |
| 761 // folders), the only way we should be able to get here is due to a race | 761 // folders), the only way we should be able to get here is due to a race |
| 762 // condition. In any case, the package root folder is gone, so we can't | 762 // condition. In any case, the package root folder is gone, so we can't |
| 763 // resolve packages. | 763 // resolve packages. |
| 764 return new NoPackageFolderDisposition(packageRoot: packageRoot); | 764 return new NoPackageFolderDisposition(packageRoot: packageRoot); |
| 765 } else { | 765 } else { |
| 766 PackageMapInfo packageMapInfo; |
| 766 callbacks.beginComputePackageMap(); | 767 callbacks.beginComputePackageMap(); |
| 767 if (packageResolverProvider != null) { | 768 try { |
| 768 UriResolver resolver = packageResolverProvider(folder); | 769 if (ENABLE_PACKAGESPEC_SUPPORT) { |
| 769 if (resolver != null) { | 770 // Try .packages first. |
| 770 return new CustomPackageResolverDisposition(resolver); | 771 if (pathos.basename(packagespecFile.path) == PACKAGE_SPEC_NAME) { |
| 772 Packages packages = _readPackagespec(packagespecFile); |
| 773 return new PackagesFileDisposition(packages); |
| 774 } |
| 771 } | 775 } |
| 776 if (packageResolverProvider != null) { |
| 777 UriResolver resolver = packageResolverProvider(folder); |
| 778 if (resolver != null) { |
| 779 return new CustomPackageResolverDisposition(resolver); |
| 780 } |
| 781 } |
| 782 ServerPerformanceStatistics.pub.makeCurrentWhile(() { |
| 783 packageMapInfo = _packageMapProvider.computePackageMap(folder); |
| 784 }); |
| 785 } finally { |
| 786 callbacks.endComputePackageMap(); |
| 772 } | 787 } |
| 773 PackageMapInfo packageMapInfo; | |
| 774 ServerPerformanceStatistics.pub.makeCurrentWhile(() { | |
| 775 packageMapInfo = _packageMapProvider.computePackageMap(folder); | |
| 776 }); | |
| 777 callbacks.endComputePackageMap(); | |
| 778 for (String dependencyPath in packageMapInfo.dependencies) { | 788 for (String dependencyPath in packageMapInfo.dependencies) { |
| 779 addDependency(dependencyPath); | 789 addDependency(dependencyPath); |
| 780 } | 790 } |
| 781 if (packageMapInfo.packageMap == null) { | 791 if (packageMapInfo.packageMap == null) { |
| 782 return new NoPackageFolderDisposition(); | 792 return new NoPackageFolderDisposition(); |
| 783 } | 793 } |
| 784 return new PackageMapDisposition(packageMapInfo.packageMap); | 794 return new PackageMapDisposition(packageMapInfo.packageMap); |
| 785 } | 795 } |
| 786 } | 796 } |
| 787 | 797 |
| 788 /** | 798 /** |
| 789 * Create a new empty context associated with [folder], having parent | 799 * Create a new empty context associated with [folder], having parent |
| 790 * [parent] and using [packagespecFile] to resolve package URI's. | 800 * [parent] and using [packagespecFile] to resolve package URI's. |
| 791 */ | 801 */ |
| 792 ContextInfo _createContext( | 802 ContextInfo _createContext( |
| 793 ContextInfo parent, Folder folder, File packagespecFile) { | 803 ContextInfo parent, Folder folder, File packagespecFile) { |
| 794 ContextInfo info = new ContextInfo(this, parent, folder, packagespecFile, | 804 ContextInfo info = new ContextInfo(this, parent, folder, packagespecFile, |
| 795 normalizedPackageRoots[folder.path]); | 805 normalizedPackageRoots[folder.path]); |
| 796 Map<String, YamlNode> options = analysisOptionsProvider.getOptions(folder); | 806 Map<String, YamlNode> options = analysisOptionsProvider.getOptions(folder); |
| 797 processOptionsForContext(info, options); | 807 processOptionsForContext(info, options); |
| 798 FolderDisposition disposition; | 808 FolderDisposition disposition; |
| 799 List<String> dependencies = <String>[]; | 809 List<String> dependencies = <String>[]; |
| 800 | 810 |
| 801 if (ENABLE_PACKAGESPEC_SUPPORT) { | |
| 802 // Try .packages first. | |
| 803 if (pathos.basename(packagespecFile.path) == PACKAGE_SPEC_NAME) { | |
| 804 Packages packages = _readPackagespec(packagespecFile); | |
| 805 disposition = new PackagesFileDisposition(packages); | |
| 806 } | |
| 807 } | |
| 808 | |
| 809 // Next resort to a package uri resolver. | 811 // Next resort to a package uri resolver. |
| 810 if (disposition == null) { | 812 if (disposition == null) { |
| 811 disposition = _computeFolderDisposition(folder, dependencies.add); | 813 disposition = |
| 814 _computeFolderDisposition(folder, dependencies.add, packagespecFile); |
| 812 } | 815 } |
| 813 | 816 |
| 814 info.setDependencies(dependencies); | 817 info.setDependencies(dependencies); |
| 815 info.context = callbacks.addContext(folder, disposition); | 818 info.context = callbacks.addContext(folder, disposition); |
| 816 info.context.name = folder.path; | 819 info.context.name = folder.path; |
| 817 return info; | 820 return info; |
| 818 } | 821 } |
| 819 | 822 |
| 820 /** | 823 /** |
| 821 * Potentially create a new context associated with the given [folder]. | 824 * Potentially create a new context associated with the given [folder]. |
| 822 * | 825 * |
| 823 * If there are subfolders with 'pubspec.yaml' files, separate contexts are | 826 * If there are subfolders with 'pubspec.yaml' files, separate contexts are |
| 824 * created for them and excluded from the context associated with the | 827 * created for them and excluded from the context associated with the |
| 825 * [folder]. | 828 * [folder]. |
| 826 * | 829 * |
| 827 * If [withPackageSpecOnly] is `true`, a context will be created only if there | 830 * If [withPackageSpecOnly] is `true`, a context will be created only if there |
| 828 * is a 'pubspec.yaml' or '.packages' file in the [folder]. | 831 * is a 'pubspec.yaml' or '.packages' file in the [folder]. |
| 829 * | 832 * |
| 830 * [parent] should be the parent of any contexts that are created. | 833 * [parent] should be the parent of any contexts that are created. |
| 831 */ | 834 */ |
| 832 void _createContexts( | 835 void _createContexts( |
| 833 ContextInfo parent, Folder folder, bool withPackageSpecOnly) { | 836 ContextInfo parent, Folder folder, bool withPackageSpecOnly) { |
| 834 // Decide whether a context needs to be created for [folder] here, and if | 837 // Decide whether a context needs to be created for [folder] here, and if |
| 835 // so, create it. | 838 // so, create it. |
| 836 File packageSpec; | 839 File packageSpec = _findPackageSpecFile(folder); |
| 837 | |
| 838 if (ENABLE_PACKAGESPEC_SUPPORT) { | |
| 839 // Start by looking for .packages. | |
| 840 packageSpec = folder.getChild(PACKAGE_SPEC_NAME); | |
| 841 } | |
| 842 | |
| 843 // Fall back to looking for a pubspec. | |
| 844 if (packageSpec == null || !packageSpec.exists) { | |
| 845 packageSpec = folder.getChild(PUBSPEC_NAME); | |
| 846 } | |
| 847 | |
| 848 bool createContext = packageSpec.exists || !withPackageSpecOnly; | 840 bool createContext = packageSpec.exists || !withPackageSpecOnly; |
| 849 if (withPackageSpecOnly && | 841 if (withPackageSpecOnly && |
| 850 packageSpec.exists && | 842 packageSpec.exists && |
| 851 (parent != null) && | 843 (parent != null) && |
| 852 parent.ignored(packageSpec.path)) { | 844 parent.ignored(packageSpec.path)) { |
| 853 // Don't create a context if the package spec is required and ignored. | 845 // Don't create a context if the package spec is required and ignored. |
| 854 createContext = false; | 846 createContext = false; |
| 855 } | 847 } |
| 856 if (createContext) { | 848 if (createContext) { |
| 857 parent = _createContext(parent, folder, packageSpec); | 849 parent = _createContext(parent, folder, packageSpec); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 922 changeSet.removedSource(source); | 914 changeSet.removedSource(source); |
| 923 }); | 915 }); |
| 924 callbacks.applyChangesToContext(oldInfo.folder, changeSet); | 916 callbacks.applyChangesToContext(oldInfo.folder, changeSet); |
| 925 } | 917 } |
| 926 // TODO(paulberry): every context that was previously a child of oldInfo is | 918 // TODO(paulberry): every context that was previously a child of oldInfo is |
| 927 // is still a child of oldInfo. This is wrong--some of them ought to be | 919 // is still a child of oldInfo. This is wrong--some of them ought to be |
| 928 // adopted by newInfo now. | 920 // adopted by newInfo now. |
| 929 } | 921 } |
| 930 | 922 |
| 931 /** | 923 /** |
| 924 * Find the file that should be used to determine whether a context needs to |
| 925 * be created here--this is either the ".packages" file or the "pubspec.yaml" |
| 926 * file. |
| 927 */ |
| 928 File _findPackageSpecFile(Folder folder) { |
| 929 // Decide whether a context needs to be created for [folder] here, and if |
| 930 // so, create it. |
| 931 File packageSpec; |
| 932 |
| 933 if (ENABLE_PACKAGESPEC_SUPPORT) { |
| 934 // Start by looking for .packages. |
| 935 packageSpec = folder.getChild(PACKAGE_SPEC_NAME); |
| 936 } |
| 937 |
| 938 // Fall back to looking for a pubspec. |
| 939 if (packageSpec == null || !packageSpec.exists) { |
| 940 packageSpec = folder.getChild(PUBSPEC_NAME); |
| 941 } |
| 942 return packageSpec; |
| 943 } |
| 944 |
| 945 /** |
| 932 * Return the [ContextInfo] for the "innermost" context whose associated | 946 * Return the [ContextInfo] for the "innermost" context whose associated |
| 933 * folder is or contains the given path. ("innermost" refers to the nesting | 947 * folder is or contains the given path. ("innermost" refers to the nesting |
| 934 * of contexts, so if there is a context for path /foo and a context for | 948 * of contexts, so if there is a context for path /foo and a context for |
| 935 * path /foo/bar, then the innermost context containing /foo/bar/baz.dart is | 949 * path /foo/bar, then the innermost context containing /foo/bar/baz.dart is |
| 936 * the context for /foo/bar.) | 950 * the context for /foo/bar.) |
| 937 * | 951 * |
| 938 * If no context contains the given path, `null` is returned. | 952 * If no context contains the given path, `null` is returned. |
| 939 */ | 953 */ |
| 940 ContextInfo _getInnermostContextInfoFor(String path) { | 954 ContextInfo _getInnermostContextInfoFor(String path) { |
| 941 ContextInfo info = _rootInfo.findChildInfoFor(path); | 955 ContextInfo info = _rootInfo.findChildInfoFor(path); |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1175 /** | 1189 /** |
| 1176 * Recompute the [FolderDisposition] for the context described by [info], | 1190 * Recompute the [FolderDisposition] for the context described by [info], |
| 1177 * and update the client appropriately. | 1191 * and update the client appropriately. |
| 1178 */ | 1192 */ |
| 1179 void _recomputeFolderDisposition(ContextInfo info) { | 1193 void _recomputeFolderDisposition(ContextInfo info) { |
| 1180 // TODO(paulberry): when computePackageMap is changed into an | 1194 // TODO(paulberry): when computePackageMap is changed into an |
| 1181 // asynchronous API call, we'll want to suspend analysis for this context | 1195 // asynchronous API call, we'll want to suspend analysis for this context |
| 1182 // while we're rerunning "pub list", since any analysis we complete while | 1196 // while we're rerunning "pub list", since any analysis we complete while |
| 1183 // "pub list" is in progress is just going to get thrown away anyhow. | 1197 // "pub list" is in progress is just going to get thrown away anyhow. |
| 1184 List<String> dependencies = <String>[]; | 1198 List<String> dependencies = <String>[]; |
| 1185 FolderDisposition disposition = | 1199 FolderDisposition disposition = _computeFolderDisposition( |
| 1186 _computeFolderDisposition(info.folder, dependencies.add); | 1200 info.folder, dependencies.add, _findPackageSpecFile(info.folder)); |
| 1187 info.setDependencies(dependencies); | 1201 info.setDependencies(dependencies); |
| 1188 callbacks.updateContextPackageUriResolver(info.folder, disposition); | 1202 callbacks.updateContextPackageUriResolver(info.folder, disposition); |
| 1189 } | 1203 } |
| 1190 | 1204 |
| 1191 /** | 1205 /** |
| 1192 * Create and return a source representing the given [file] within the given | 1206 * Create and return a source representing the given [file] within the given |
| 1193 * [context]. | 1207 * [context]. |
| 1194 */ | 1208 */ |
| 1195 static Source createSourceInContext(AnalysisContext context, File file) { | 1209 static Source createSourceInContext(AnalysisContext context, File file) { |
| 1196 // TODO(brianwilkerson) Optimize this, by allowing support for source | 1210 // TODO(brianwilkerson) Optimize this, by allowing support for source |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1352 PackagesFileDisposition(this.packages) {} | 1366 PackagesFileDisposition(this.packages) {} |
| 1353 | 1367 |
| 1354 @override | 1368 @override |
| 1355 String get packageRoot => null; | 1369 String get packageRoot => null; |
| 1356 | 1370 |
| 1357 @override | 1371 @override |
| 1358 Iterable<UriResolver> createPackageUriResolvers( | 1372 Iterable<UriResolver> createPackageUriResolvers( |
| 1359 ResourceProvider resourceProvider) => | 1373 ResourceProvider resourceProvider) => |
| 1360 const <UriResolver>[]; | 1374 const <UriResolver>[]; |
| 1361 } | 1375 } |
| OLD | NEW |