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

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

Issue 2988673002: Add support for creating a .packages file when the plugin is in a Bazel workspace (Closed)
Patch Set: address comments Created 3 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/src/plugin/plugin_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/plugin/plugin_manager.dart
diff --git a/pkg/analysis_server/lib/src/plugin/plugin_manager.dart b/pkg/analysis_server/lib/src/plugin/plugin_manager.dart
index 6b4fdc7cd722550722f612627dc8604bb7a42ec1..148cc37ee311317b2139a7a77d8ee973389a1eb5 100644
--- a/pkg/analysis_server/lib/src/plugin/plugin_manager.dart
+++ b/pkg/analysis_server/lib/src/plugin/plugin_manager.dart
@@ -13,6 +13,8 @@ import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/src/generated/bazel.dart';
import 'package:analyzer/src/generated/gn.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/workspace.dart';
import 'package:analyzer/src/util/glob.dart';
import 'package:analyzer_plugin/channel/channel.dart';
import 'package:analyzer_plugin/protocol/protocol.dart';
@@ -26,6 +28,7 @@ import 'package:crypto/crypto.dart';
import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
import 'package:watcher/watcher.dart' as watcher;
+import 'package:yaml/yaml.dart';
/**
* Information about a plugin that is built-in.
@@ -336,8 +339,8 @@ class PluginManager {
PluginInfo plugin = _pluginMap[path];
bool isNew = plugin == null;
if (isNew) {
- List<String> pluginPaths = _pathsFor(path);
- if (pluginPaths == null || pluginPaths[1] == null) {
+ List<String> pluginPaths = pathsFor(path);
+ if (pluginPaths == null) {
return;
}
plugin = new DiscoveredPluginInfo(path, pluginPaths[0], pluginPaths[1],
@@ -415,6 +418,46 @@ class PluginManager {
}
/**
+ * Return the execution path and .packages path associated with the plugin at
+ * the given [path], or `null` if there is a problem that prevents us from
+ * executing the plugin.
+ */
+ @visibleForTesting
+ List<String> pathsFor(String pluginPath) {
+ Folder pluginFolder = resourceProvider.getFolder(pluginPath);
+ File pubspecFile = pluginFolder.getChildAssumingFile('pubspec.yaml');
+ if (!pubspecFile.exists) {
+ // If there's no pubspec file, then we don't need to copy the package
+ // because we won't be running pub.
mfairhurst 2017/07/24 18:00:07 This will prevent the bazel support from working w
+ return _computePaths(pluginFolder);
+ }
+ Workspace workspace =
+ BazelWorkspace.find(resourceProvider, pluginFolder.path) ??
+ GnWorkspace.find(resourceProvider, pluginFolder.path);
+ if (workspace != null) {
+ // Similarly, we won't be running pub if we're in a workspace because
+ // there is exactly one version of each package.
+ return _computePaths(pluginFolder, workspace: workspace);
+ }
+ //
+ // Copy the plugin directory to a unique subdirectory of the plugin
+ // manager's state location. The subdirectory's name is selected such that
+ // it will be invariant across sessions, reducing the number of times the
+ // plugin will need to be copied and pub will need to be run.
+ //
+ Folder stateFolder = resourceProvider.getStateLocation('.plugin_manager');
+ String stateName = _uniqueDirectoryName(pluginPath);
+ Folder parentFolder = stateFolder.getChildAssumingFolder(stateName);
+ if (parentFolder.exists) {
+ Folder executionFolder =
+ parentFolder.getChildAssumingFolder(pluginFolder.shortName);
+ return _computePaths(executionFolder);
+ }
+ Folder executionFolder = pluginFolder.copyTo(parentFolder);
+ return _computePaths(executionFolder, runPub: true);
+ }
+
+ /**
* Return a list of all of the plugins that are currently associated with the
* given [contextRoot].
*/
@@ -518,6 +561,52 @@ class PluginManager {
];
}
+ /**
+ * Compute the paths to be returned by the enclosing method given that the
+ * plugin should exist in the given [pluginFolder].
+ */
+ List<String> _computePaths(Folder pluginFolder,
+ {bool runPub: false, Workspace workspace}) {
+ File pluginFile = pluginFolder
+ .getChildAssumingFolder('bin')
+ .getChildAssumingFile('plugin.dart');
+ if (!pluginFile.exists) {
+ return null;
+ }
+ File packagesFile = pluginFolder.getChildAssumingFile('.packages');
+ if (!packagesFile.exists) {
+ if (runPub) {
+ String vmPath = Platform.executable;
+ String pubPath = path.join(path.dirname(vmPath), 'pub');
+ ProcessResult result = Process.runSync(pubPath, <String>['get'],
+ stderrEncoding: UTF8,
+ stdoutEncoding: UTF8,
+ workingDirectory: pluginFolder.path);
+ if (result.exitCode != 0) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.writeln('Failed to run pub get');
+ buffer.writeln(' pluginFolder = ${pluginFolder.path}');
+ buffer.writeln(' exitCode = ${result.exitCode}');
+ buffer.writeln(' stdout = ${result.stdout}');
+ buffer.writeln(' stderr = ${result.stderr}');
+ instrumentationService.logError(buffer.toString());
+ }
+ if (!packagesFile.exists) {
+ packagesFile = null;
+ }
+ } else if (workspace != null) {
+ packagesFile =
+ _createPackagesFile(pluginFolder, workspace.packageUriResolver);
+ } else {
+ packagesFile = null;
+ }
+ }
+ if (packagesFile == null) {
+ return null;
+ }
+ return <String>[pluginFile.path, packagesFile.path];
+ }
+
WatchEventType _convertChangeType(watcher.ChangeType type) {
switch (type) {
case watcher.ChangeType.ADD:
@@ -536,6 +625,61 @@ class PluginManager {
}
/**
+ * Return a temporary `.packages` file that is appropriate for the plugin in
+ * the given [pluginFolder]. The [packageUriResolver] is used to determine the
+ * location of the packages that need to be included in the packages file.
+ */
+ File _createPackagesFile(
+ Folder pluginFolder, UriResolver packageUriResolver) {
+ String pluginPath = pluginFolder.path;
+ Folder stateFolder = resourceProvider.getStateLocation('.plugin_manager');
+ String stateName = _uniqueDirectoryName(pluginPath) + '.packages';
+ File packagesFile = stateFolder.getChildAssumingFile(stateName);
+ if (!packagesFile.exists) {
+ File pluginPubspec = pluginFolder.getChildAssumingFile('pubspec.yaml');
+ if (!pluginPubspec.exists) {
+ return null;
+ }
+
+ try {
+ Map<String, String> visitedPackages = <String, String>{};
+ path.Context context = resourceProvider.pathContext;
+ visitedPackages[context.basename(pluginPath)] =
+ context.join(pluginFolder.path, 'lib');
+ List<File> pubspecFiles = <File>[];
+ pubspecFiles.add(pluginPubspec);
+ while (pubspecFiles.isNotEmpty) {
+ File pubspecFile = pubspecFiles.removeLast();
+ for (String packageName in _readDependecies(pubspecFile)) {
+ if (!visitedPackages.containsKey(packageName)) {
+ Uri uri = Uri.parse('package:$packageName/$packageName.dart');
+ Source packageSource = packageUriResolver.resolveAbsolute(uri);
+ String libDirPath = context.dirname(packageSource.fullName);
+ visitedPackages[packageName] = libDirPath;
+ String pubspecPath =
+ context.join(context.dirname(libDirPath), 'pubspec.yaml');
+ pubspecFiles.add(resourceProvider.getFile(pubspecPath));
+ }
+ }
+ }
+
+ StringBuffer buffer = new StringBuffer();
+ visitedPackages.forEach((String name, String path) {
+ buffer.write(name);
+ buffer.write(':');
+ buffer.writeln(new Uri.file(path));
+ });
+ packagesFile.writeAsStringSync(buffer.toString());
+ } catch (exception) {
+ // If we are not able to produce a .packages file, return null so that
+ // callers will not try to load the plugin.
+ return null;
mfairhurst 2017/07/24 18:00:06 should log the exception too though
+ }
+ }
+ return packagesFile;
+ }
+
+ /**
* Return `true` if the plugin with the given [path] has been whitelisted.
*/
bool _isWhitelisted(String path) {
@@ -548,85 +692,20 @@ class PluginManager {
}
/**
- * Return the execution path and .packages path associated with the plugin at
- * the given [path], or `null` if there is a problem that prevents us from
- * executing the plugin.
+ * Return the names of packages that are listed as dependencies in the given
+ * [pubspecFile].
*/
- List<String> _pathsFor(String pluginPath) {
- /**
- * Return `true` if the plugin in the give [folder] needs to be copied to a
- * temporary location so that 'pub' can be run to resolve dependencies. We
- * need to run `pub` if the plugin contains a `pubspec.yaml` file and is not
- * in a workspace.
- */
- bool needToCopy(Folder folder) {
- File pubspecFile = folder.getChildAssumingFile('pubspec.yaml');
- if (!pubspecFile.exists) {
- return false;
+ Iterable<String> _readDependecies(File pubspecFile) {
+ YamlDocument document = loadYamlDocument(pubspecFile.readAsStringSync(),
+ sourceUrl: pubspecFile.toUri());
+ YamlNode contents = document.contents;
+ if (contents is YamlMap) {
+ YamlNode dependencies = contents['dependencies'];
mfairhurst 2017/07/24 18:00:06 Is there any way we can get this info by running p
+ if (dependencies is YamlMap) {
+ return dependencies.keys;
}
- return BazelWorkspace.find(resourceProvider, folder.path) == null &&
- GnWorkspace.find(resourceProvider, folder.path) == null;
}
-
- /**
- * Compute the paths to be returned by the enclosing method given that the
- * plugin should exist in the given [pluginFolder].
- */
- List<String> computePaths(Folder pluginFolder, {bool runPub: false}) {
- File pluginFile = pluginFolder
- .getChildAssumingFolder('bin')
- .getChildAssumingFile('plugin.dart');
- if (!pluginFile.exists) {
- return null;
- }
- File packagesFile = pluginFolder.getChildAssumingFile('.packages');
- if (!packagesFile.exists) {
- if (runPub) {
- String vmPath = Platform.executable;
- String pubPath = path.join(path.dirname(vmPath), 'pub');
- ProcessResult result = Process.runSync(pubPath, <String>['get'],
- stderrEncoding: UTF8,
- stdoutEncoding: UTF8,
- workingDirectory: pluginFolder.path);
- if (result.exitCode != 0) {
- StringBuffer buffer = new StringBuffer();
- buffer.writeln('Failed to run pub get');
- buffer.writeln(' pluginFolder = ${pluginFolder.path}');
- buffer.writeln(' exitCode = ${result.exitCode}');
- buffer.writeln(' stdout = ${result.stdout}');
- buffer.writeln(' stderr = ${result.stderr}');
- instrumentationService.logError(buffer.toString());
- }
- if (!packagesFile.exists) {
- packagesFile = null;
- }
- } else {
- packagesFile = null;
- }
- }
- return <String>[pluginFile.path, packagesFile?.path];
- }
-
- Folder pluginFolder = resourceProvider.getFolder(pluginPath);
- if (!needToCopy(pluginFolder)) {
- return computePaths(pluginFolder);
- }
- //
- // Copy the plugin directory to a unique subdirectory of the plugin
- // manager's state location. The subdirectory's name is selected such that
- // it will be invariant across sessions, reducing the number of times the
- // plugin will need to be copied and pub will need to be run.
- //
- Folder stateFolder = resourceProvider.getStateLocation('.plugin_manager');
- String stateName = _uniqueDirectoryName(pluginPath);
- Folder parentFolder = stateFolder.getChildAssumingFolder(stateName);
- if (parentFolder.exists) {
- Folder executionFolder =
- parentFolder.getChildAssumingFolder(pluginFolder.shortName);
- return computePaths(executionFolder);
- }
- Folder executionFolder = pluginFolder.copyTo(parentFolder);
- return computePaths(executionFolder, runPub: true);
+ return const <String>[];
}
/**
« no previous file with comments | « no previous file | pkg/analysis_server/test/src/plugin/plugin_manager_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698