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

Unified Diff: pkg/analysis_server/lib/src/plugin/plugin_watcher.dart

Issue 2750483006: Add PluginWatcher to watch for new plugins that need to be run (Closed)
Patch Set: Created 3 years, 9 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
Index: pkg/analysis_server/lib/src/plugin/plugin_watcher.dart
diff --git a/pkg/analysis_server/lib/src/plugin/plugin_watcher.dart b/pkg/analysis_server/lib/src/plugin/plugin_watcher.dart
new file mode 100644
index 0000000000000000000000000000000000000000..1490253d2002993fd4ac8225b39c5d328c1d40b5
--- /dev/null
+++ b/pkg/analysis_server/lib/src/plugin/plugin_watcher.dart
@@ -0,0 +1,150 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/plugin/plugin_locator.dart';
+import 'package:analysis_server/src/plugin/plugin_manager.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/source/package_map_resolver.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/util/absolute_path.dart';
+import 'package:analyzer_plugin/protocol/protocol_generated.dart';
+
+/**
+ * An object that watches the results produced by analysis drivers to identify
+ * references to previously unseen packages and, if those packages have plugins
+ * associated with them, causes the plugin to be associated with the driver's
+ * context root (which in turn might cause the plugin to be started).
+ */
+class PluginWatcher {
+ /**
+ * The resource provider used to access the file system.
+ */
+ final ResourceProvider resourceProvider;
+
+ /**
+ * The object managing the execution of plugins.
+ */
+ final PluginManager manager;
+
+ /**
+ * The object used to locate plugins within packages.
+ */
+ final PluginLocator _locator;
+
+ /**
+ * A table mapping analysis drivers to information related to the driver.
+ */
+ Map<AnalysisDriver, _DriverInfo> _driverInfo =
+ <AnalysisDriver, _DriverInfo>{};
+
+ /**
+ * Initialize a newly created plugin watcher.
+ */
+ PluginWatcher(this.resourceProvider, this.manager)
+ : _locator = new PluginLocator(resourceProvider);
+
+ /**
+ * The context manager has just added the given analysis [driver]. This method
+ * must be called before the driver has been allowed to perform any analysis.
+ */
+ void addedDriver(AnalysisDriver driver, ContextRoot contextRoot) {
+ _driverInfo[driver] = new _DriverInfo(
+ contextRoot, <String>[contextRoot.root, _getSdkPath(driver)]);
+ driver.results.listen((AnalysisResult result) {
+ List<String> addedPluginPaths = _checkPluginsFor(driver);
scheglov 2017/03/15 17:41:33 It seems very wasteful to me to perform this cycle
Brian Wilkerson 2017/03/15 18:25:45 I agree that this is wasteful. I'm not convinced
+ for (String pluginPath in addedPluginPaths) {
+ manager.addPluginToContextRoot(contextRoot, pluginPath);
+ }
+ });
+ }
+
+ /**
+ * The context manager has just removed the given analysis [driver].
+ */
+ void removedDriver(AnalysisDriver driver) {
+ _DriverInfo info = _driverInfo[driver];
+ if (info == null) {
+ throw new StateError('Cannot remove a driver that was not added');
+ }
+ manager.removedContextRoot(info.contextRoot);
+ _driverInfo.remove(driver);
+ }
+
+ /**
+ * Check all of the files that have been analyzed so far by the given [driver]
+ * to see whether any of them are in a package that had not previously been
+ * seen that defines a plugin. Return a list of the roots of all such plugins
+ * that are found.
+ */
+ List<String> _checkPluginsFor(AnalysisDriver driver) {
+ AbsolutePathContext context = resourceProvider.absolutePathContext;
+ List<String> packageRoots = _driverInfo[driver].packageRoots;
+
+ bool isInRoot(String path) {
+ for (String root in packageRoots) {
+ if (context.isWithin(root, path)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ String getPackageRoot(String path, Uri uri) {
+ List<String> segments = uri.pathSegments.toList();
+ segments[0] = 'lib';
+ String suffix = resourceProvider.pathContext.joinAll(segments);
+ return path.substring(0, path.length - suffix.length - 1);
+ }
+
+ List<String> addedPluginPaths = <String>[];
+ for (FileState state in driver.fsState.knownFiles) {
scheglov 2017/03/15 17:41:34 If the set of files is the same as it was the last
Brian Wilkerson 2017/03/15 18:25:45 True, and I can cache the previous list in order t
+ String path = state.path;
+ if (!isInRoot(path)) {
+ // Found a file not in a previously known package.
+ Uri uri = state.uri;
+ if (PackageMapUriResolver.isPackageUri(uri)) {
+ String packageRoot = getPackageRoot(path, uri);
+ packageRoots.add(packageRoot);
+ addedPluginPaths.add(_locator.findPlugin(packageRoot));
scheglov 2017/03/15 17:41:34 Can findPlugin() return null? Also, could we cach
Brian Wilkerson 2017/03/15 18:25:45 Yes. Good catch! I'll fix it before committing.
+ }
+ }
+ }
+ return addedPluginPaths;
+ }
+
+ /**
+ * Return the path to the root of the SDK being used by the given analysis
+ * [driver].
+ */
+ String _getSdkPath(AnalysisDriver driver) {
+ AbsolutePathContext context = resourceProvider.absolutePathContext;
+ String sdkRoot = driver.sourceFactory.forUri('dart:core').fullName;
+ while (sdkRoot.isNotEmpty && context.basename(sdkRoot) != 'lib') {
+ sdkRoot = context.dirname(sdkRoot);
+ }
+ return sdkRoot;
+ }
+}
+
+/**
+ * Information related to an analysis driver.
+ */
+class _DriverInfo {
+ /**
+ * The context root representing the context being analyzed by the driver.
+ */
+ ContextRoot contextRoot;
scheglov 2017/03/15 17:41:34 Do these fields change over the life of the instan
Brian Wilkerson 2017/03/15 18:25:45 The context root doesn't. The list of package root
+
+ /**
+ * A list of the absolute paths of directories inside of which we have already
+ * searched for a plugin.
+ */
+ List<String> packageRoots;
+
+ /**
+ * Initialize a newly created information holder.
+ */
+ _DriverInfo(this.contextRoot, this.packageRoots);
+}
« no previous file with comments | « pkg/analysis_server/lib/src/plugin/plugin_locator.dart ('k') | pkg/analysis_server/test/src/plugin/plugin_watcher_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698