| 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; |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 91 * Remove the given [contextRoot] from the set of context roots being analyzed | 91 * Remove the given [contextRoot] from the set of context roots being analyzed |
| 92 * by this plugin. | 92 * by this plugin. |
| 93 */ | 93 */ |
| 94 void removeContextRoot(analyzer.ContextRoot contextRoot) { | 94 void removeContextRoot(analyzer.ContextRoot contextRoot) { |
| 95 if (contextRoots.remove(contextRoot)) { | 95 if (contextRoots.remove(contextRoot)) { |
| 96 _updatePluginRoots(); | 96 _updatePluginRoots(); |
| 97 } | 97 } |
| 98 } | 98 } |
| 99 | 99 |
| 100 /** | 100 /** |
| 101 * If the plugin is currently running, send a request based on the given |
| 102 * [params] to the plugin. If the plugin is not running, the request will |
| 103 * silently be dropped. |
| 104 */ |
| 105 void sendRequest(RequestParams params) { |
| 106 currentSession?.sendRequest(params); |
| 107 } |
| 108 |
| 109 /** |
| 101 * Start a new isolate that is running the plugin. Return the state object | 110 * Start a new isolate that is running the plugin. Return the state object |
| 102 * used to interact with the plugin. | 111 * used to interact with the plugin. |
| 103 */ | 112 */ |
| 104 Future<PluginSession> start(String byteStorePath) async { | 113 Future<PluginSession> start(String byteStorePath) async { |
| 105 if (currentSession != null) { | 114 if (currentSession != null) { |
| 106 throw new StateError('Cannot start a plugin that is already running.'); | 115 throw new StateError('Cannot start a plugin that is already running.'); |
| 107 } | 116 } |
| 108 currentSession = new PluginSession(this); | 117 currentSession = new PluginSession(this); |
| 109 await currentSession.start(byteStorePath); | 118 await currentSession.start(byteStorePath); |
| 110 return currentSession; | 119 return currentSession; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 161 * The instrumentation service that is being used by the analysis server. | 170 * The instrumentation service that is being used by the analysis server. |
| 162 */ | 171 */ |
| 163 final InstrumentationService instrumentationService; | 172 final InstrumentationService instrumentationService; |
| 164 | 173 |
| 165 /** | 174 /** |
| 166 * A table mapping the paths of plugins to information about those plugins. | 175 * A table mapping the paths of plugins to information about those plugins. |
| 167 */ | 176 */ |
| 168 Map<String, PluginInfo> _pluginMap = <String, PluginInfo>{}; | 177 Map<String, PluginInfo> _pluginMap = <String, PluginInfo>{}; |
| 169 | 178 |
| 170 /** | 179 /** |
| 180 * The parameters for the last 'analysis.setPriorityFiles' request that was |
| 181 * received from the client. Because plugins are lazily discovered, this needs |
| 182 * to be retained so that it can be sent after a plugin has been started. |
| 183 */ |
| 184 AnalysisSetPriorityFilesParams _analysisSetPriorityFilesParams; |
| 185 |
| 186 /** |
| 187 * The parameters for the last 'analysis.setSubscriptions' request that was |
| 188 * received from the client. Because plugins are lazily discovered, this needs |
| 189 * to be retained so that it can be sent after a plugin has been started. |
| 190 */ |
| 191 AnalysisSetSubscriptionsParams _analysisSetSubscriptionsParams; |
| 192 |
| 193 /** |
| 194 * The current state of content overlays. Because plugins are lazily |
| 195 * discovered, the state needs to be retained so that it can be sent after a |
| 196 * plugin has been started. |
| 197 */ |
| 198 Map<String, dynamic> _overlayState = <String, dynamic>{}; |
| 199 |
| 200 /** |
| 171 * Initialize a newly created plugin manager. The notifications from the | 201 * Initialize a newly created plugin manager. The notifications from the |
| 172 * running plugins will be handled by the given [notificationManager]. | 202 * running plugins will be handled by the given [notificationManager]. |
| 173 */ | 203 */ |
| 174 PluginManager(this.resourceProvider, this.byteStorePath, | 204 PluginManager(this.resourceProvider, this.byteStorePath, |
| 175 this.notificationManager, this.instrumentationService); | 205 this.notificationManager, this.instrumentationService); |
| 176 | 206 |
| 177 /** | 207 /** |
| 178 * Add the plugin with the given [path] to the list of plugins that should be | 208 * Add the plugin with the given [path] to the list of plugins that should be |
| 179 * used when analyzing code for the given [contextRoot]. If the plugin had not | 209 * used when analyzing code for the given [contextRoot]. If the plugin had not |
| 180 * yet been started, then it will be started by this method. | 210 * yet been started, then it will be started by this method. |
| 181 */ | 211 */ |
| 182 Future<Null> addPluginToContextRoot( | 212 Future<Null> addPluginToContextRoot( |
| 183 analyzer.ContextRoot contextRoot, String path) async { | 213 analyzer.ContextRoot contextRoot, String path) async { |
| 184 PluginInfo plugin = _pluginMap[path]; | 214 PluginInfo plugin = _pluginMap[path]; |
| 215 bool isNew = false; |
| 185 if (plugin == null) { | 216 if (plugin == null) { |
| 217 isNew = true; |
| 186 List<String> pluginPaths = _pathsFor(path); | 218 List<String> pluginPaths = _pathsFor(path); |
| 187 plugin = new PluginInfo(path, pluginPaths[0], pluginPaths[1], | 219 plugin = new PluginInfo(path, pluginPaths[0], pluginPaths[1], |
| 188 notificationManager, instrumentationService); | 220 notificationManager, instrumentationService); |
| 189 _pluginMap[path] = plugin; | 221 _pluginMap[path] = plugin; |
| 190 if (pluginPaths[0] != null) { | 222 if (pluginPaths[0] != null) { |
| 191 PluginSession session = await plugin.start(byteStorePath); | 223 PluginSession session = await plugin.start(byteStorePath); |
| 192 session.onDone.then((_) { | 224 session.onDone.then((_) { |
| 193 _pluginMap.remove(path); | 225 _pluginMap.remove(path); |
| 194 }); | 226 }); |
| 195 } | 227 } |
| 196 } | 228 } |
| 197 plugin.addContextRoot(contextRoot); | 229 plugin.addContextRoot(contextRoot); |
| 230 if (isNew) { |
| 231 if (_analysisSetSubscriptionsParams != null) { |
| 232 plugin.sendRequest(_analysisSetSubscriptionsParams); |
| 233 } |
| 234 if (_overlayState.isNotEmpty) { |
| 235 plugin.sendRequest(new AnalysisUpdateContentParams(_overlayState)); |
| 236 } |
| 237 if (_analysisSetPriorityFilesParams != null) { |
| 238 plugin.sendRequest(_analysisSetPriorityFilesParams); |
| 239 } |
| 240 } |
| 198 } | 241 } |
| 199 | 242 |
| 200 /** | 243 /** |
| 201 * Broadcast a request built from the given [params] to all of the plugins | 244 * Broadcast a request built from the given [params] to all of the plugins |
| 202 * that are currently associated with the given [contextRoot]. Return a list | 245 * that are currently associated with the given [contextRoot]. Return a list |
| 203 * containing futures that will complete when each of the plugins have sent a | 246 * containing futures that will complete when each of the plugins have sent a |
| 204 * response. | 247 * response. |
| 205 */ | 248 */ |
| 206 Map<PluginInfo, Future<Response>> broadcast( | 249 Map<PluginInfo, Future<Response>> broadcast( |
| 207 analyzer.ContextRoot contextRoot, RequestParams params) { | 250 analyzer.ContextRoot contextRoot, RequestParams params) { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 237 for (PluginInfo plugin in plugins) { | 280 for (PluginInfo plugin in plugins) { |
| 238 plugin.removeContextRoot(contextRoot); | 281 plugin.removeContextRoot(contextRoot); |
| 239 if (plugin.contextRoots.isEmpty) { | 282 if (plugin.contextRoots.isEmpty) { |
| 240 _pluginMap.remove(plugin.path); | 283 _pluginMap.remove(plugin.path); |
| 241 plugin.stop(); | 284 plugin.stop(); |
| 242 } | 285 } |
| 243 } | 286 } |
| 244 } | 287 } |
| 245 | 288 |
| 246 /** | 289 /** |
| 290 * Send a request based on the given [params] to existing plugins to set the |
| 291 * priority files to those specified by the [params]. As a side-effect, record |
| 292 * the parameters so that they can be sent to any newly started plugins. |
| 293 */ |
| 294 void setAnalysisSetPriorityFilesParams( |
| 295 AnalysisSetPriorityFilesParams params) { |
| 296 for (PluginInfo plugin in _pluginMap.values) { |
| 297 plugin.sendRequest(params); |
| 298 } |
| 299 _analysisSetPriorityFilesParams = params; |
| 300 } |
| 301 |
| 302 /** |
| 303 * Send a request based on the given [params] to existing plugins to set the |
| 304 * subscriptions to those specified by the [params]. As a side-effect, record |
| 305 * the parameters so that they can be sent to any newly started plugins. |
| 306 */ |
| 307 void setAnalysisSetSubscriptionsParams( |
| 308 AnalysisSetSubscriptionsParams params) { |
| 309 for (PluginInfo plugin in _pluginMap.values) { |
| 310 plugin.sendRequest(params); |
| 311 } |
| 312 _analysisSetSubscriptionsParams = params; |
| 313 } |
| 314 |
| 315 /** |
| 316 * Send a request based on the given [params] to existing plugins to set the |
| 317 * content overlays to those specified by the [params]. As a side-effect, |
| 318 * update the overlay state so that it can be sent to any newly started |
| 319 * plugins. |
| 320 */ |
| 321 void setAnalysisUpdateContentParams(AnalysisUpdateContentParams params) { |
| 322 for (PluginInfo plugin in _pluginMap.values) { |
| 323 plugin.sendRequest(params); |
| 324 } |
| 325 Map<String, dynamic> files = params.files; |
| 326 for (String file in files.keys) { |
| 327 Object overlay = files[file]; |
| 328 if (overlay is RemoveContentOverlay) { |
| 329 _overlayState.remove(file); |
| 330 } else if (overlay is AddContentOverlay) { |
| 331 _overlayState[file] = overlay; |
| 332 } else if (overlay is ChangeContentOverlay) { |
| 333 AddContentOverlay previousOverlay = _overlayState[file]; |
| 334 String newContent = |
| 335 SourceEdit.applySequence(previousOverlay.content, overlay.edits); |
| 336 _overlayState[file] = new AddContentOverlay(newContent); |
| 337 } else { |
| 338 throw new ArgumentError( |
| 339 'Invalid class of overlay: ${overlay.runtimeType}'); |
| 340 } |
| 341 } |
| 342 } |
| 343 |
| 344 /** |
| 247 * Stop all of the plugins that are currently running. | 345 * Stop all of the plugins that are currently running. |
| 248 */ | 346 */ |
| 249 Future<List<Null>> stopAll() { | 347 Future<List<Null>> stopAll() { |
| 250 return Future.wait(_pluginMap.values.map((PluginInfo info) => info.stop())); | 348 return Future.wait(_pluginMap.values.map((PluginInfo info) => info.stop())); |
| 251 } | 349 } |
| 252 | 350 |
| 253 /** | 351 /** |
| 254 * Return the execution path and .packages path associated with the plugin at | 352 * Return the execution path and .packages path associated with the plugin at |
| 255 * the given [path], or `null` if there is a problem that prevents us from | 353 * the given [path], or `null` if there is a problem that prevents us from |
| 256 * executing the plugin. | 354 * executing the plugin. |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 502 Future<Null> stop() { | 600 Future<Null> stop() { |
| 503 if (channel == null) { | 601 if (channel == null) { |
| 504 throw new StateError('Cannot stop a plugin that is not running.'); | 602 throw new StateError('Cannot stop a plugin that is not running.'); |
| 505 } | 603 } |
| 506 // TODO(brianwilkerson) Ensure that the isolate is killed if it does not | 604 // TODO(brianwilkerson) Ensure that the isolate is killed if it does not |
| 507 // terminate normally. | 605 // terminate normally. |
| 508 sendRequest(new PluginShutdownParams()); | 606 sendRequest(new PluginShutdownParams()); |
| 509 return pluginStoppedCompleter.future; | 607 return pluginStoppedCompleter.future; |
| 510 } | 608 } |
| 511 } | 609 } |
| OLD | NEW |