Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 import 'dart:async'; | 5 import 'dart:async'; |
| 6 import 'dart:collection'; | 6 import 'dart:collection'; |
| 7 import 'dart:io' show Platform; | 7 import 'dart:io' show Platform; |
| 8 | 8 |
| 9 import 'package:analysis_server/src/plugin/notification_manager.dart'; | 9 import 'package:analysis_server/src/plugin/notification_manager.dart'; |
| 10 import 'package:analyzer/context/context_root.dart' as analyzer; | 10 import 'package:analyzer/context/context_root.dart' as analyzer; |
| 11 import 'package:analyzer/file_system/file_system.dart'; | 11 import 'package:analyzer/file_system/file_system.dart'; |
| 12 import 'package:analyzer/instrumentation/instrumentation.dart'; | 12 import 'package:analyzer/instrumentation/instrumentation.dart'; |
| 13 import 'package:analyzer/src/generated/bazel.dart'; | 13 import 'package:analyzer/src/generated/bazel.dart'; |
| 14 import 'package:analyzer/src/generated/gn.dart'; | 14 import 'package:analyzer/src/generated/gn.dart'; |
| 15 import 'package:analyzer/src/util/glob.dart'; | |
| 15 import 'package:analyzer_plugin/channel/channel.dart'; | 16 import 'package:analyzer_plugin/channel/channel.dart'; |
| 16 import 'package:analyzer_plugin/protocol/protocol.dart'; | 17 import 'package:analyzer_plugin/protocol/protocol.dart'; |
| 18 import 'package:analyzer_plugin/protocol/protocol_constants.dart'; | |
| 17 import 'package:analyzer_plugin/protocol/protocol_generated.dart'; | 19 import 'package:analyzer_plugin/protocol/protocol_generated.dart'; |
| 18 import 'package:analyzer_plugin/src/channel/isolate_channel.dart'; | 20 import 'package:analyzer_plugin/src/channel/isolate_channel.dart'; |
| 19 import 'package:analyzer_plugin/src/protocol/protocol_internal.dart'; | 21 import 'package:analyzer_plugin/src/protocol/protocol_internal.dart'; |
| 20 import 'package:convert/convert.dart'; | 22 import 'package:convert/convert.dart'; |
| 21 import 'package:crypto/crypto.dart'; | 23 import 'package:crypto/crypto.dart'; |
| 22 import 'package:meta/meta.dart'; | 24 import 'package:meta/meta.dart'; |
| 23 import 'package:path/path.dart' as path; | 25 import 'package:path/path.dart' as path; |
| 26 import 'package:watcher/watcher.dart' as watcher; | |
| 24 | 27 |
| 25 /** | 28 /** |
| 26 * Information about a single plugin. | 29 * Information about a single plugin. |
| 27 */ | 30 */ |
| 28 class PluginInfo { | 31 class PluginInfo { |
| 29 /** | 32 /** |
| 30 * The path to the root directory of the definition of the plugin on disk (the | 33 * The path to the root directory of the definition of the plugin on disk (the |
| 31 * directory containing the 'pubspec.yaml' file and the 'bin' directory). | 34 * directory containing the 'pubspec.yaml' file and the 'bin' directory). |
| 32 */ | 35 */ |
| 33 final String path; | 36 final String path; |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 241 } | 244 } |
| 242 } | 245 } |
| 243 } | 246 } |
| 244 | 247 |
| 245 /** | 248 /** |
| 246 * Broadcast a request built from the given [params] to all of the plugins | 249 * Broadcast a request built from the given [params] to all of the plugins |
| 247 * that are currently associated with the given [contextRoot]. Return a list | 250 * that are currently associated with the given [contextRoot]. Return a list |
| 248 * containing futures that will complete when each of the plugins have sent a | 251 * containing futures that will complete when each of the plugins have sent a |
| 249 * response. | 252 * response. |
| 250 */ | 253 */ |
| 251 Map<PluginInfo, Future<Response>> broadcast( | 254 Map<PluginInfo, Future<Response>> broadcastRequest( |
| 252 analyzer.ContextRoot contextRoot, RequestParams params) { | 255 analyzer.ContextRoot contextRoot, RequestParams params) { |
| 253 List<PluginInfo> plugins = pluginsForContextRoot(contextRoot); | 256 List<PluginInfo> plugins = pluginsForContextRoot(contextRoot); |
| 254 Map<PluginInfo, Future<Response>> responseMap = | 257 Map<PluginInfo, Future<Response>> responseMap = |
| 255 <PluginInfo, Future<Response>>{}; | 258 <PluginInfo, Future<Response>>{}; |
| 256 for (PluginInfo plugin in plugins) { | 259 for (PluginInfo plugin in plugins) { |
| 257 responseMap[plugin] = plugin.currentSession?.sendRequest(params); | 260 responseMap[plugin] = plugin.currentSession?.sendRequest(params); |
| 258 } | 261 } |
| 259 return responseMap; | 262 return responseMap; |
| 260 } | 263 } |
| 261 | 264 |
| 262 /** | 265 /** |
| 266 * Broadcast the given [watchEvent] to all of the plugins that are analyzing | |
| 267 * in contexts containing the file associated with the event. Return a list | |
| 268 * containing futures that will complete when each of the plugins have sent a | |
| 269 * response. | |
| 270 */ | |
| 271 Future<List<Future<Response>>> broadcastWatchEvent( | |
| 272 watcher.WatchEvent watchEvent) async { | |
|
scheglov
2017/04/26 15:55:18
Do we await it anywhere?
Or do we want to return t
Brian Wilkerson
2017/04/26 16:35:55
It's useful in test code to allow us to know wheth
| |
| 273 String filePath = watchEvent.path; | |
| 274 | |
| 275 /** | |
| 276 * Return `true` if the given glob [pattern] matches the file being watched. | |
| 277 */ | |
| 278 bool matches(String pattern) => | |
| 279 new Glob(path.separator, pattern).matches(filePath); | |
| 280 | |
| 281 WatchEvent event = null; | |
| 282 List<Future<Response>> responses = <Future<Response>>[]; | |
| 283 for (PluginInfo plugin in _pluginMap.values) { | |
| 284 PluginSession session = plugin.currentSession; | |
| 285 if (session != null && | |
| 286 path.isWithin(plugin.path, filePath) && | |
| 287 session.interestingFiles.any(matches)) { | |
| 288 event ??= _convertWatchEvent(watchEvent); | |
| 289 AnalysisHandleWatchEventsParams params = | |
| 290 new AnalysisHandleWatchEventsParams([event]); | |
| 291 responses.add(session.sendRequest(params)); | |
| 292 } | |
| 293 } | |
| 294 return responses; | |
| 295 } | |
| 296 | |
| 297 /** | |
| 263 * Return a list of all of the plugins that are currently associated with the | 298 * Return a list of all of the plugins that are currently associated with the |
| 264 * given [contextRoot]. | 299 * given [contextRoot]. |
| 265 */ | 300 */ |
| 266 @visibleForTesting | 301 @visibleForTesting |
| 267 List<PluginInfo> pluginsForContextRoot(analyzer.ContextRoot contextRoot) { | 302 List<PluginInfo> pluginsForContextRoot(analyzer.ContextRoot contextRoot) { |
| 268 List<PluginInfo> plugins = <PluginInfo>[]; | 303 List<PluginInfo> plugins = <PluginInfo>[]; |
| 269 for (PluginInfo plugin in _pluginMap.values) { | 304 for (PluginInfo plugin in _pluginMap.values) { |
| 270 if (plugin.contextRoots.contains(contextRoot)) { | 305 if (plugin.contextRoots.contains(contextRoot)) { |
| 271 plugins.add(plugin); | 306 plugins.add(plugin); |
| 272 } | 307 } |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 343 } | 378 } |
| 344 } | 379 } |
| 345 | 380 |
| 346 /** | 381 /** |
| 347 * Stop all of the plugins that are currently running. | 382 * Stop all of the plugins that are currently running. |
| 348 */ | 383 */ |
| 349 Future<List<Null>> stopAll() { | 384 Future<List<Null>> stopAll() { |
| 350 return Future.wait(_pluginMap.values.map((PluginInfo info) => info.stop())); | 385 return Future.wait(_pluginMap.values.map((PluginInfo info) => info.stop())); |
| 351 } | 386 } |
| 352 | 387 |
| 388 WatchEventType _convertChangeType(watcher.ChangeType type) { | |
| 389 switch (type) { | |
| 390 case watcher.ChangeType.ADD: | |
| 391 return WatchEventType.ADD; | |
| 392 case watcher.ChangeType.MODIFY: | |
| 393 return WatchEventType.MODIFY; | |
| 394 case watcher.ChangeType.REMOVE: | |
| 395 return WatchEventType.REMOVE; | |
| 396 default: | |
| 397 throw new StateError('Unknown change type: $type'); | |
| 398 } | |
| 399 } | |
| 400 | |
| 401 WatchEvent _convertWatchEvent(watcher.WatchEvent watchEvent) { | |
| 402 return new WatchEvent(_convertChangeType(watchEvent.type), watchEvent.path); | |
| 403 } | |
| 404 | |
| 353 /** | 405 /** |
| 354 * Return the execution path and .packages path associated with the plugin at | 406 * Return the execution path and .packages path associated with the plugin at |
| 355 * the given [path], or `null` if there is a problem that prevents us from | 407 * the given [path], or `null` if there is a problem that prevents us from |
| 356 * executing the plugin. | 408 * executing the plugin. |
| 357 */ | 409 */ |
| 358 List<String> _pathsFor(String pluginPath) { | 410 List<String> _pathsFor(String pluginPath) { |
| 359 /** | 411 /** |
| 360 * Return `true` if the plugin in the give [folder] needs to be copied to a | 412 * Return `true` if the plugin in the give [folder] needs to be copied to a |
| 361 * temporary location so that 'pub' can be run to resolve dependencies. We | 413 * temporary location so that 'pub' can be run to resolve dependencies. We |
| 362 * need to run `pub` if the plugin contains a `pubspec.yaml` file and is not | 414 * need to run `pub` if the plugin contains a `pubspec.yaml` file and is not |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 500 | 552 |
| 501 /** | 553 /** |
| 502 * Return a future that will complete when the plugin has stopped. | 554 * Return a future that will complete when the plugin has stopped. |
| 503 */ | 555 */ |
| 504 Future<Null> get onDone => pluginStoppedCompleter.future; | 556 Future<Null> get onDone => pluginStoppedCompleter.future; |
| 505 | 557 |
| 506 /** | 558 /** |
| 507 * Handle the given [notification]. | 559 * Handle the given [notification]. |
| 508 */ | 560 */ |
| 509 void handleNotification(Notification notification) { | 561 void handleNotification(Notification notification) { |
| 562 if (notification.event == PLUGIN_NOTIFICATION_ERROR) { | |
| 563 PluginErrorParams params = | |
| 564 new PluginErrorParams.fromNotification(notification); | |
| 565 if (params.isFatal) { | |
| 566 info.stop(); | |
| 567 stop(); | |
| 568 } | |
| 569 } | |
| 510 info.notificationManager.handlePluginNotification(info.path, notification); | 570 info.notificationManager.handlePluginNotification(info.path, notification); |
| 511 } | 571 } |
| 512 | 572 |
| 513 /** | 573 /** |
| 514 * Handle the fact that the plugin has stopped. | 574 * Handle the fact that the plugin has stopped. |
| 515 */ | 575 */ |
| 516 void handleOnDone() { | 576 void handleOnDone() { |
| 517 channel.close(); | 577 channel.close(); |
| 518 channel = null; | 578 channel = null; |
| 519 pluginStoppedCompleter.complete(null); | 579 pluginStoppedCompleter.complete(null); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 603 Future<Null> stop() { | 663 Future<Null> stop() { |
| 604 if (channel == null) { | 664 if (channel == null) { |
| 605 throw new StateError('Cannot stop a plugin that is not running.'); | 665 throw new StateError('Cannot stop a plugin that is not running.'); |
| 606 } | 666 } |
| 607 // TODO(brianwilkerson) Ensure that the isolate is killed if it does not | 667 // TODO(brianwilkerson) Ensure that the isolate is killed if it does not |
| 608 // terminate normally. | 668 // terminate normally. |
| 609 sendRequest(new PluginShutdownParams()); | 669 sendRequest(new PluginShutdownParams()); |
| 610 return pluginStoppedCompleter.future; | 670 return pluginStoppedCompleter.future; |
| 611 } | 671 } |
| 612 } | 672 } |
| OLD | NEW |