Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(607)

Unified Diff: pkg/analysis_server/lib/src/context_manager.dart

Issue 1257933002: Convert ContextManager to recursively watch analysis roots. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/analysis_server/test/context_manager_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 145c942d1b3d9639e07153ae405e2544cb43b9b0..78dcc69e79a8959c5684252d727ede6802d8d23d 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -69,21 +69,13 @@ class ContextInfo {
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. Organized as a map from path to
- * subscription.
+ * Paths to files which determine the folder disposition and package map.
*
- * For paths that are inside [folder], the subscription is null, since the
- * entire contents of the folder are automatically being watched.
+ * TODO(paulberry): if any of these files are outside of [folder], they won't
+ * be watched for changes. I believe the use case for watching these files
+ * is no longer relevant.
*/
- final Map<String, StreamSubscription<WatchEvent>> _dependencySubscriptions =
- <String, StreamSubscription<WatchEvent>>{};
+ Set<String> _dependencies = new Set<String>();
/**
* The analysis context that was created for the [folder].
@@ -161,7 +153,7 @@ class ContextInfo {
* Determine if the given [path] is one of the dependencies most recently
* passed to [setDependencies].
*/
- bool hasDependency(String path) => _dependencySubscriptions.containsKey(path);
+ bool hasDependency(String path) => _dependencies.contains(path);
/// Returns `true` if [path] should be ignored.
bool ignored(String path) => pathFilter.ignored(path);
@@ -174,42 +166,10 @@ class ContextInfo {
path == packageDescriptionPath;
/**
- * Update the set of dependencies for this context. Watchers are
- * automatically set up for the dependencies (if necessary) to ensure that
- * [ContextManagerImpl._handleWatchEvent] is called when they are modified.
+ * Update the set of dependencies for this context.
*/
void setDependencies(Iterable<String> newDependencies) {
- for (String oldDependency in _dependencySubscriptions.keys.toList()) {
- if (!newDependencies.contains(oldDependency)) {
- StreamSubscription<WatchEvent> subscription =
- _dependencySubscriptions[oldDependency];
- if (subscription != null) {
- subscription.cancel();
- }
- _dependencySubscriptions.remove(oldDependency);
- }
- }
- for (String newDependency in newDependencies) {
- if (!_dependencySubscriptions.containsKey(newDependency)) {
- StreamSubscription<WatchEvent> subscription;
- if (!folder.contains(newDependency)) {
- Resource resource =
- contextManager.resourceProvider.getResource(newDependency);
- if (resource is File) {
- subscription = resource.changes.listen((WatchEvent event) {
- contextManager._handleWatchEvent(folder, this, event);
- }, onError: (error, StackTrace stackTrace) {
- // Gracefully degrade if file is or becomes unwatchable
- contextManager._instrumentationService.logException(
- error, stackTrace);
- subscription.cancel();
- _dependencySubscriptions[newDependency] = null;
- });
- }
- }
- _dependencySubscriptions[newDependency] = subscription;
- }
- }
+ _dependencies = newDependencies.toSet();
}
}
@@ -433,6 +393,13 @@ class ContextManagerImpl implements ContextManager {
*/
final ContextInfo _rootInfo = new ContextInfo._root();
+ /**
+ * Stream subscription we are using to watch each analysis root directory for
+ * changes.
+ */
+ final Map<Folder, StreamSubscription<WatchEvent>> _changeSubscriptions =
+ <Folder, StreamSubscription<WatchEvent>>{};
+
ContextManagerImpl(this.resourceProvider, this.packageResolverProvider,
this._packageMapProvider, this._instrumentationService) {
pathContext = resourceProvider.pathContext;
@@ -591,6 +558,8 @@ class ContextManagerImpl implements ContextManager {
return info.folder.isOrContains(includedFolder.path);
});
if (!wasIncluded) {
+ _changeSubscriptions[includedFolder] =
+ includedFolder.changes.listen(_handleWatchEvent);
_createContexts(_rootInfo, includedFolder, false);
}
}
@@ -706,13 +675,6 @@ class ContextManagerImpl implements ContextManager {
}
}
- /**
- * Cancel all dependency subscriptions for the given context.
- */
- void _cancelDependencySubscriptions(ContextInfo info) {
- info.setDependencies(const <String>[]);
- }
-
void _checkForPackagespecUpdate(
String path, ContextInfo info, Folder folder) {
// Check to see if this is the .packages file for this context and if so,
@@ -754,7 +716,7 @@ class ContextManagerImpl implements ContextManager {
}
/**
- * Compute the appropriate [FolderDisposition] for [info]. Use
+ * Compute the appropriate [FolderDisposition] for [folder]. Use
* [addDependency] to indicate which files needed to be consulted in order to
* figure out the [FolderDisposition]; these dependencies will be watched in
* order to determine when it is necessary to call this function again.
@@ -763,11 +725,12 @@ class ContextManagerImpl implements ContextManager {
* dependencies (currently we only use it to track "pub list" dependencies).
*/
FolderDisposition _computeFolderDisposition(
- Folder folder, ContextInfo info, void addDependency(String path)) {
- if (info.packageRoot != null) {
+ Folder folder, void addDependency(String path)) {
+ String packageRoot = normalizedPackageRoots[folder.path];
+ if (packageRoot != null) {
// TODO(paulberry): We shouldn't be using JavaFile here because it
// makes the code untestable (see dartbug.com/23909).
- JavaFile packagesDir = new JavaFile(info.packageRoot);
+ JavaFile packagesDir = new JavaFile(packageRoot);
Map<String, List<Folder>> packageMap = new Map<String, List<Folder>>();
if (packagesDir.isDirectory()) {
for (JavaFile file in packagesDir.listFiles()) {
@@ -786,15 +749,14 @@ class ContextManagerImpl implements ContextManager {
packageMap[file.getName()] = <Folder>[res];
}
}
- return new PackageMapDisposition(packageMap,
- packageRoot: info.packageRoot);
+ return new PackageMapDisposition(packageMap, packageRoot: packageRoot);
}
// The package root does not exist (or is not a folder). Since
// [setRoots] ignores any package roots that don't exist (or aren't
// folders), the only way we should be able to get here is due to a race
// condition. In any case, the package root folder is gone, so we can't
// resolve packages.
- return new NoPackageFolderDisposition(packageRoot: info.packageRoot);
+ return new NoPackageFolderDisposition(packageRoot: packageRoot);
} else {
callbacks.beginComputePackageMap();
if (packageResolverProvider != null) {
@@ -828,33 +790,25 @@ class ContextManagerImpl implements ContextManager {
normalizedPackageRoots[folder.path]);
Map<String, YamlNode> options = analysisOptionsProvider.getOptions(folder);
processOptionsForContext(info, options);
- info.changeSubscription = folder.changes.listen((WatchEvent event) {
- _handleWatchEvent(folder, info, event);
- });
- try {
- FolderDisposition disposition;
- List<String> dependencies = <String>[];
-
- if (ENABLE_PACKAGESPEC_SUPPORT) {
- // Try .packages first.
- if (pathos.basename(packagespecFile.path) == PACKAGE_SPEC_NAME) {
- Packages packages = _readPackagespec(packagespecFile);
- disposition = new PackagesFileDisposition(packages);
- }
- }
+ FolderDisposition disposition;
+ List<String> dependencies = <String>[];
- // Next resort to a package uri resolver.
- if (disposition == null) {
- disposition = _computeFolderDisposition(folder, info, dependencies.add);
+ if (ENABLE_PACKAGESPEC_SUPPORT) {
+ // Try .packages first.
+ if (pathos.basename(packagespecFile.path) == PACKAGE_SPEC_NAME) {
+ Packages packages = _readPackagespec(packagespecFile);
+ disposition = new PackagesFileDisposition(packages);
}
+ }
- info.setDependencies(dependencies);
- info.context = callbacks.addContext(folder, disposition);
- info.context.name = folder.path;
- } catch (_) {
- info.changeSubscription.cancel();
- rethrow;
+ // Next resort to a package uri resolver.
+ if (disposition == null) {
+ disposition = _computeFolderDisposition(folder, dependencies.add);
}
+
+ info.setDependencies(dependencies);
+ info.context = callbacks.addContext(folder, disposition);
+ info.context.name = folder.path;
return info;
}
@@ -917,8 +871,9 @@ class ContextManagerImpl implements ContextManager {
* Clean up and destroy the context associated with the given folder.
*/
void _destroyContext(ContextInfo info) {
- info.changeSubscription.cancel();
- _cancelDependencySubscriptions(info);
+ if (_changeSubscriptions.containsKey(info.folder)) {
+ _changeSubscriptions[info.folder].cancel();
+ }
callbacks.removeContext(info.folder, _computeFlushedFiles(info));
bool wasRemoved = info.parent.children.remove(info);
assert(wasRemoved);
@@ -983,13 +938,21 @@ class ContextManagerImpl implements ContextManager {
}
}
- void _handleWatchEvent(Folder folder, ContextInfo info, WatchEvent event) {
+ void _handleWatchEvent(WatchEvent event) {
+ // Figure out which context this event applies to.
// 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
// that's the only context that's watching the file).
+ ContextInfo info = _getInnermostContextInfoFor(event.path);
+ if (info == null) {
+ // This event doesn't apply to any context. This could happen due to a
+ // race condition (e.g. a context was removed while one of its events was
+ // in the event loop). The event is inapplicable now, so just ignore it.
+ return;
+ }
_instrumentationService.logWatchEvent(
- folder.path, event.path, event.type.toString());
+ info.folder.path, event.path, event.type.toString());
String path = event.path;
// First handle changes that affect folderDisposition (since these need to
// be processed regardless of whether they are part of an excluded/ignored
@@ -1011,7 +974,7 @@ class ContextManagerImpl implements ContextManager {
// handle the change
switch (event.type) {
case ChangeType.ADD:
- if (_isInPackagesDir(path, folder)) {
+ if (_isInPackagesDir(path, info.folder)) {
return;
}
@@ -1063,7 +1026,7 @@ class ContextManagerImpl implements ContextManager {
ChangeSet changeSet = new ChangeSet();
Source source = createSourceInContext(info.context, file);
changeSet.addedSource(source);
- callbacks.applyChangesToContext(folder, changeSet);
+ callbacks.applyChangesToContext(info.folder, changeSet);
info.sources[path] = source;
}
}
@@ -1110,7 +1073,7 @@ class ContextManagerImpl implements ContextManager {
sources.forEach((Source source) {
changeSet.removedSource(source);
});
- callbacks.applyChangesToContext(folder, changeSet);
+ callbacks.applyChangesToContext(info.folder, changeSet);
info.sources.remove(path);
}
break;
@@ -1121,13 +1084,13 @@ class ContextManagerImpl implements ContextManager {
sources.forEach((Source source) {
changeSet.changedSource(source);
});
- callbacks.applyChangesToContext(folder, changeSet);
+ callbacks.applyChangesToContext(info.folder, changeSet);
}
break;
}
//TODO(pquitslund): find the right place for this
- _checkForPackagespecUpdate(path, info, folder);
+ _checkForPackagespecUpdate(path, info, info.folder);
}
/**
@@ -1204,7 +1167,7 @@ class ContextManagerImpl implements ContextManager {
// "pub list" is in progress is just going to get thrown away anyhow.
List<String> dependencies = <String>[];
FolderDisposition disposition =
- _computeFolderDisposition(info.folder, info, dependencies.add);
+ _computeFolderDisposition(info.folder, dependencies.add);
info.setDependencies(dependencies);
callbacks.updateContextPackageUriResolver(info.folder, disposition);
}
« no previous file with comments | « no previous file | pkg/analysis_server/test/context_manager_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698