Index: pkg/analysis_server/lib/src/context_manager.dart |
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart |
index a57ad14582428c0cd45d08b9d50c312e901e0a5f..3d691a52f6c36752db9cb47b64bf7683f6e6c091 100644 |
--- a/pkg/analysis_server/lib/src/context_manager.dart |
+++ b/pkg/analysis_server/lib/src/context_manager.dart |
@@ -29,6 +29,109 @@ import 'package:watcher/watcher.dart'; |
import 'package:yaml/yaml.dart'; |
/** |
+ * Information tracked by the [ContextManager] for each context. |
+ */ |
+class ContextInfo { |
+ /** |
+ * The [Folder] for which this information object is created. |
+ */ |
+ final Folder folder; |
+ |
+ /// The [PathFilter] used to filter sources from being analyzed. |
+ final PathFilter pathFilter; |
+ |
+ /** |
+ * The enclosed pubspec-based contexts. |
+ */ |
+ final List<ContextInfo> children; |
+ |
+ /** |
+ * The package root for this context, or null if there is no package root. |
+ */ |
+ String packageRoot; |
+ |
+ /** |
+ * The [ContextInfo] that encloses this one. |
+ */ |
+ ContextInfo parent; |
+ |
+ /** |
+ * The package description file path for this context. |
+ */ |
+ String packageDescriptionPath; |
+ |
+ /** |
+ * Stream subscription we are using to watch the context's directory for |
+ * changes. |
+ */ |
+ StreamSubscription<WatchEvent> changeSubscription; |
+ |
+ /** |
+ * Stream subscriptions we are using to watch the files |
+ * used to determine the package map. |
+ */ |
+ final List<StreamSubscription<WatchEvent>> dependencySubscriptions = |
+ <StreamSubscription<WatchEvent>>[]; |
+ |
+ /** |
+ * The analysis context that was created for the [folder]. |
+ */ |
+ AnalysisContext context; |
+ |
+ /** |
+ * Map from full path to the [Source] object, for each source that has been |
+ * added to the context. |
+ */ |
+ Map<String, Source> sources = new HashMap<String, Source>(); |
+ |
+ /** |
+ * Info returned by the last call to |
+ * [OptimizingPubPackageMapProvider.computePackageMap], or `null` if the |
+ * package map hasn't been computed for this context yet. |
+ */ |
+ OptimizingPubPackageMapInfo packageMapInfo; |
+ |
+ ContextInfo( |
+ Folder folder, File packagespecFile, this.children, this.packageRoot) |
+ : folder = folder, |
+ pathFilter = new PathFilter(folder.path, null) { |
+ packageDescriptionPath = packagespecFile.path; |
+ for (ContextInfo child in children) { |
+ child.parent = this; |
+ } |
+ } |
+ |
+ /** |
+ * Returns `true` if this context is root folder based. |
+ */ |
+ bool get isRoot => parent == null; |
+ |
+ /** |
+ * Returns `true` if [path] is excluded, as it is in one of the children. |
+ */ |
+ bool excludes(String path) { |
+ return children.any((child) { |
+ return child.folder.contains(path); |
+ }); |
+ } |
+ |
+ /** |
+ * Returns `true` if [resource] is excluded, as it is in one of the children. |
+ */ |
+ bool excludesResource(Resource resource) => excludes(resource.path); |
+ |
+ /// Returns `true` if [path] should be ignored. |
+ bool ignored(String path) => pathFilter.ignored(path); |
+ |
+ /** |
+ * Returns `true` if [path] is the package description file for this context |
+ * (pubspec.yaml or .packages). |
+ */ |
+ bool isPathToPackageDescription(String path) => |
+ path == packageDescriptionPath; |
+} |
+ |
+/** |
* Class that maintains a mapping from included/excluded paths to a set of |
* folders that should correspond to analysis contexts. |
*/ |
@@ -184,10 +287,10 @@ class ContextManagerImpl implements ContextManager { |
static const String PACKAGE_SPEC_NAME = '.packages'; |
/** |
- * [_ContextInfo] object for each included directory in the most |
+ * [ContextInfo] object for each included directory in the most |
* recent successful call to [setRoots]. |
*/ |
- Map<Folder, _ContextInfo> _contexts = new HashMap<Folder, _ContextInfo>(); |
+ Map<Folder, ContextInfo> _contexts = new HashMap<Folder, ContextInfo>(); |
/** |
* The [ResourceProvider] using which paths are converted into [Resource]s. |
@@ -255,7 +358,7 @@ class ContextManagerImpl implements ContextManager { |
@override |
List<AnalysisContext> contextsInAnalysisRoot(Folder analysisRoot) { |
List<AnalysisContext> contexts = <AnalysisContext>[]; |
- _contexts.forEach((Folder contextFolder, _ContextInfo info) { |
+ _contexts.forEach((Folder contextFolder, ContextInfo info) { |
if (analysisRoot.isOrContains(contextFolder.path)) { |
contexts.add(info.context); |
} |
@@ -263,6 +366,11 @@ class ContextManagerImpl implements ContextManager { |
return contexts; |
} |
+ /** |
+ * For testing: get the [ContextInfo] object for the given [folder], if any. |
+ */ |
+ ContextInfo getContextInfoFor(Folder folder) => _contexts[folder]; |
+ |
@override |
bool isInAnalysisRoot(String path) { |
// check if excluded |
@@ -279,12 +387,11 @@ class ContextManagerImpl implements ContextManager { |
return false; |
} |
- /// Process [options] for the context [folder]. |
- void processOptionsForContext(Folder folder, Map<String, YamlNode> options) { |
- _ContextInfo info = _contexts[folder]; |
- if (info == null) { |
- return; |
- } |
+ /** |
+ * Process [options] for the context having info [info]. |
+ */ |
+ void processOptionsForContext( |
+ ContextInfo info, Map<String, YamlNode> options) { |
YamlMap analyzer = options['analyzer']; |
if (analyzer == null) { |
// No options for analyzer. |
@@ -294,7 +401,7 @@ class ContextManagerImpl implements ContextManager { |
// Set ignore patterns. |
YamlList exclude = analyzer['exclude']; |
if (exclude != null) { |
- setIgnorePatternsForContext(folder, exclude); |
+ setIgnorePatternsForContext(info, exclude); |
} |
} |
@@ -318,14 +425,12 @@ class ContextManagerImpl implements ContextManager { |
setRoots(includedPaths, excludedPaths, packageRoots); |
} |
- /// Sets the [ignorePatterns] for the context [folder]. |
- void setIgnorePatternsForContext(Folder folder, List<String> ignorePatterns) { |
- _ContextInfo info = _contexts[folder]; |
- if (info == null) { |
- return; |
- } |
- var pathFilter = info.pathFilter; |
- pathFilter.setIgnorePatterns(ignorePatterns); |
+ /** |
+ * Sets the [ignorePatterns] for the context having info [info]. |
+ */ |
+ void setIgnorePatternsForContext( |
+ ContextInfo info, List<String> ignorePatterns) { |
+ info.pathFilter.setIgnorePatterns(ignorePatterns); |
} |
@override |
@@ -371,7 +476,7 @@ class ContextManagerImpl implements ContextManager { |
} |
} |
// Update package roots for existing contexts |
- _contexts.forEach((Folder folder, _ContextInfo info) { |
+ _contexts.forEach((Folder folder, ContextInfo info) { |
String newPackageRoot = normalizedPackageRoots[folder.path]; |
if (info.packageRoot != newPackageRoot) { |
info.packageRoot = newPackageRoot; |
@@ -416,7 +521,7 @@ class ContextManagerImpl implements ContextManager { |
/** |
* Resursively adds all Dart and HTML files to the [changeSet]. |
*/ |
- void _addPreviouslyExcludedSources(_ContextInfo info, ChangeSet changeSet, |
+ void _addPreviouslyExcludedSources(ContextInfo info, ChangeSet changeSet, |
Folder folder, List<String> oldExcludedPaths) { |
if (info.excludesResource(folder)) { |
return; |
@@ -463,7 +568,7 @@ class ContextManagerImpl implements ContextManager { |
/** |
* Resursively adds all Dart and HTML files to the [changeSet]. |
*/ |
- void _addSourceFiles(ChangeSet changeSet, Folder folder, _ContextInfo info) { |
+ void _addSourceFiles(ChangeSet changeSet, Folder folder, ContextInfo info) { |
if (info.excludesResource(folder) || folder.shortName.startsWith('.')) { |
return; |
} |
@@ -501,7 +606,7 @@ class ContextManagerImpl implements ContextManager { |
/** |
* Cancel all dependency subscriptions for the given context. |
*/ |
- void _cancelDependencySubscriptions(_ContextInfo info) { |
+ void _cancelDependencySubscriptions(ContextInfo info) { |
for (StreamSubscription<WatchEvent> s in info.dependencySubscriptions) { |
s.cancel(); |
} |
@@ -509,7 +614,7 @@ class ContextManagerImpl implements ContextManager { |
} |
void _checkForPackagespecUpdate( |
- String path, _ContextInfo info, Folder folder) { |
+ String path, ContextInfo info, Folder folder) { |
// Check to see if this is the .packages file for this context and if so, |
// update the context's source factory. |
if (pathContext.basename(path) == PACKAGE_SPEC_NAME && |
@@ -536,7 +641,7 @@ class ContextManagerImpl implements ContextManager { |
for (Source source in context.sources) { |
flushedFiles.add(source.fullName); |
} |
- for (_ContextInfo contextInfo in _contexts.values) { |
+ for (ContextInfo contextInfo in _contexts.values) { |
AnalysisContext contextN = contextInfo.context; |
if (context != contextN) { |
for (Source source in contextN.sources) { |
@@ -552,7 +657,7 @@ class ContextManagerImpl implements ContextManager { |
* dependency information in [info]. Return `null` if no package map can |
* be computed. |
*/ |
- UriResolver _computePackageUriResolver(Folder folder, _ContextInfo info) { |
+ UriResolver _computePackageUriResolver(Folder folder, ContextInfo info) { |
_cancelDependencySubscriptions(info); |
if (info.packageRoot != null) { |
info.packageMapInfo = null; |
@@ -626,13 +731,13 @@ class ContextManagerImpl implements ContextManager { |
/** |
* Create a new empty context associated with [folder]. |
*/ |
- _ContextInfo _createContext( |
- Folder folder, File packagespecFile, List<_ContextInfo> children) { |
- _ContextInfo info = new _ContextInfo( |
+ ContextInfo _createContext( |
+ Folder folder, File packagespecFile, List<ContextInfo> children) { |
+ ContextInfo info = new ContextInfo( |
folder, packagespecFile, children, normalizedPackageRoots[folder.path]); |
_contexts[folder] = info; |
- var options = analysisOptionsProvider.getOptions(folder); |
- processOptionsForContext(folder, options); |
+ Map<String, YamlNode> options = analysisOptionsProvider.getOptions(folder); |
+ processOptionsForContext(info, options); |
info.changeSubscription = folder.changes.listen((WatchEvent event) { |
_handleWatchEvent(folder, info, event); |
}); |
@@ -673,9 +778,9 @@ class ContextManagerImpl implements ContextManager { |
* |
* Returns created contexts. |
*/ |
- List<_ContextInfo> _createContexts(Folder folder, bool withPackageSpecOnly) { |
+ List<ContextInfo> _createContexts(Folder folder, bool withPackageSpecOnly) { |
// Try to find subfolders with pubspecs or .packages files. |
- List<_ContextInfo> children = <_ContextInfo>[]; |
+ List<ContextInfo> children = <ContextInfo>[]; |
try { |
for (Resource child in folder.getChildren()) { |
if (child is Folder) { |
@@ -700,7 +805,7 @@ class ContextManagerImpl implements ContextManager { |
} |
if (packageSpec.exists) { |
- return <_ContextInfo>[ |
+ return <ContextInfo>[ |
_createContextWithSources(folder, packageSpec, children) |
]; |
} |
@@ -709,7 +814,7 @@ class ContextManagerImpl implements ContextManager { |
return children; |
} |
// OK, create a context without a packagespec. |
- return <_ContextInfo>[ |
+ return <ContextInfo>[ |
_createContextWithSources(folder, packageSpec, children) |
]; |
} |
@@ -719,9 +824,9 @@ class ContextManagerImpl implements ContextManager { |
* is the `pubspec.yaml` file contained in the folder. Add any sources that |
* are not included in one of the [children] to the context. |
*/ |
- _ContextInfo _createContextWithSources( |
- Folder folder, File pubspecFile, List<_ContextInfo> children) { |
- _ContextInfo info = _createContext(folder, pubspecFile, children); |
+ ContextInfo _createContextWithSources( |
+ Folder folder, File pubspecFile, List<ContextInfo> children) { |
+ ContextInfo info = _createContext(folder, pubspecFile, children); |
ChangeSet changeSet = new ChangeSet(); |
_addSourceFiles(changeSet, folder, info); |
callbacks.applyChangesToContext(folder, changeSet); |
@@ -732,7 +837,7 @@ class ContextManagerImpl implements ContextManager { |
* Clean up and destroy the context associated with the given folder. |
*/ |
void _destroyContext(Folder folder) { |
- _ContextInfo info = _contexts[folder]; |
+ ContextInfo info = _contexts[folder]; |
info.changeSubscription.cancel(); |
_cancelDependencySubscriptions(info); |
callbacks.removeContext(folder, _computeFlushedFiles(folder)); |
@@ -742,9 +847,9 @@ class ContextManagerImpl implements ContextManager { |
/** |
* Extract a new [packagespecFile]-based context from [oldInfo]. |
*/ |
- void _extractContext(_ContextInfo oldInfo, File packagespecFile) { |
+ void _extractContext(ContextInfo oldInfo, File packagespecFile) { |
Folder newFolder = packagespecFile.parent; |
- _ContextInfo newInfo = _createContext(newFolder, packagespecFile, []); |
+ ContextInfo newInfo = _createContext(newFolder, packagespecFile, []); |
newInfo.parent = oldInfo; |
// prepare sources to extract |
Map<String, Source> extractedSources = new HashMap<String, Source>(); |
@@ -773,7 +878,7 @@ class ContextManagerImpl implements ContextManager { |
} |
} |
- void _handleWatchEvent(Folder folder, _ContextInfo info, WatchEvent event) { |
+ void _handleWatchEvent(Folder folder, ContextInfo info, WatchEvent event) { |
// TODO(brianwilkerson) If a file is explicitly included in one context |
// but implicitly referenced in another context, we will only send a |
// changeSet to the context that explicitly includes the file (because |
@@ -954,11 +1059,11 @@ class ContextManagerImpl implements ContextManager { |
/** |
* Merges [info] context into its parent. |
*/ |
- void _mergeContext(_ContextInfo info) { |
+ void _mergeContext(ContextInfo info) { |
// destroy the context |
_destroyContext(info.folder); |
// add files to the parent context |
- _ContextInfo parentInfo = info.parent; |
+ ContextInfo parentInfo = info.parent; |
if (parentInfo != null) { |
parentInfo.children.remove(info); |
ChangeSet changeSet = new ChangeSet(); |
@@ -986,7 +1091,7 @@ class ContextManagerImpl implements ContextManager { |
* Recompute the package URI resolver for the context described by [info], |
* and update the client appropriately. |
*/ |
- void _recomputePackageUriResolver(_ContextInfo info) { |
+ void _recomputePackageUriResolver(ContextInfo info) { |
// TODO(paulberry): when computePackageMap is changed into an |
// asynchronous API call, we'll want to suspend analysis for this context |
// while we're rerunning "pub list", since any analysis we complete while |
@@ -1044,106 +1149,3 @@ class ContextsChangedEvent { |
this.changed: AnalysisContext.EMPTY_LIST, |
this.removed: AnalysisContext.EMPTY_LIST}); |
} |
- |
-/** |
- * Information tracked by the [ContextManager] for each context. |
- */ |
-class _ContextInfo { |
- /** |
- * The [Folder] for which this information object is created. |
- */ |
- final Folder folder; |
- |
- /// The [PathFilter] used to filter sources from being analyzed. |
- final PathFilter pathFilter; |
- |
- /** |
- * The enclosed pubspec-based contexts. |
- */ |
- final List<_ContextInfo> children; |
- |
- /** |
- * The package root for this context, or null if there is no package root. |
- */ |
- String packageRoot; |
- |
- /** |
- * The [_ContextInfo] that encloses this one. |
- */ |
- _ContextInfo parent; |
- |
- /** |
- * The package description file path for this context. |
- */ |
- String packageDescriptionPath; |
- |
- /** |
- * Stream subscription we are using to watch the context's directory for |
- * changes. |
- */ |
- StreamSubscription<WatchEvent> changeSubscription; |
- |
- /** |
- * Stream subscriptions we are using to watch the files |
- * used to determine the package map. |
- */ |
- final List<StreamSubscription<WatchEvent>> dependencySubscriptions = |
- <StreamSubscription<WatchEvent>>[]; |
- |
- /** |
- * The analysis context that was created for the [folder]. |
- */ |
- AnalysisContext context; |
- |
- /** |
- * Map from full path to the [Source] object, for each source that has been |
- * added to the context. |
- */ |
- Map<String, Source> sources = new HashMap<String, Source>(); |
- |
- /** |
- * Info returned by the last call to |
- * [OptimizingPubPackageMapProvider.computePackageMap], or `null` if the |
- * package map hasn't been computed for this context yet. |
- */ |
- OptimizingPubPackageMapInfo packageMapInfo; |
- |
- _ContextInfo( |
- Folder folder, File packagespecFile, this.children, this.packageRoot) |
- : folder = folder, |
- pathFilter = new PathFilter(folder.path, null) { |
- packageDescriptionPath = packagespecFile.path; |
- for (_ContextInfo child in children) { |
- child.parent = this; |
- } |
- } |
- |
- /** |
- * Returns `true` if this context is root folder based. |
- */ |
- bool get isRoot => parent == null; |
- |
- /** |
- * Returns `true` if [path] is excluded, as it is in one of the children. |
- */ |
- bool excludes(String path) { |
- return children.any((child) { |
- return child.folder.contains(path); |
- }); |
- } |
- |
- /** |
- * Returns `true` if [resource] is excluded, as it is in one of the children. |
- */ |
- bool excludesResource(Resource resource) => excludes(resource.path); |
- |
- /// Returns `true` if [path] should be ignored. |
- bool ignored(String path) => pathFilter.ignored(path); |
- |
- /** |
- * Returns `true` if [path] is the package description file for this context |
- * (pubspec.yaml or .packages). |
- */ |
- bool isPathToPackageDescription(String path) => |
- path == packageDescriptionPath; |
-} |