Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library analysis.server; | 5 library analysis.server; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 | 9 |
| 10 import 'package:analyzer/file_system/file_system.dart'; | 10 import 'package:analyzer/file_system/file_system.dart'; |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 201 new HashMap<AnalysisService, Set<String>>(); | 201 new HashMap<AnalysisService, Set<String>>(); |
| 202 | 202 |
| 203 /** | 203 /** |
| 204 * A table mapping [AnalysisContext]s to the completers that should be | 204 * A table mapping [AnalysisContext]s to the completers that should be |
| 205 * completed when analysis of this context is finished. | 205 * completed when analysis of this context is finished. |
| 206 */ | 206 */ |
| 207 Map<AnalysisContext, Completer<AnalysisDoneReason>> contextAnalysisDoneComplet ers = | 207 Map<AnalysisContext, Completer<AnalysisDoneReason>> contextAnalysisDoneComplet ers = |
| 208 new HashMap<AnalysisContext, Completer<AnalysisDoneReason>>(); | 208 new HashMap<AnalysisContext, Completer<AnalysisDoneReason>>(); |
| 209 | 209 |
| 210 /** | 210 /** |
| 211 * The listeners that are listening for lifecycle events from this server. | 211 * The controller that is notified when analysis is complete. |
| 212 */ | 212 */ |
| 213 List<AnalysisServerListener> listeners = <AnalysisServerListener>[]; | 213 StreamController _onAnalysisCompleteController; |
| 214 | 214 |
| 215 /** | 215 /** |
| 216 * True if any exceptions thrown by analysis should be propagated up the call | 216 * True if any exceptions thrown by analysis should be propagated up the call |
| 217 * stack. | 217 * stack. |
| 218 */ | 218 */ |
| 219 bool rethrowExceptions; | 219 bool rethrowExceptions; |
| 220 | 220 |
| 221 /** | 221 /** |
| 222 * Initialize a newly created server to receive requests from and send | 222 * Initialize a newly created server to receive requests from and send |
| 223 * responses to the given [channel]. | 223 * responses to the given [channel]. |
| 224 * | 224 * |
| 225 * If [rethrowExceptions] is true, then any exceptions thrown by analysis are | 225 * If [rethrowExceptions] is true, then any exceptions thrown by analysis are |
| 226 * propagated up the call stack. The default is true to allow analysis | 226 * propagated up the call stack. The default is true to allow analysis |
| 227 * exceptions to show up in unit tests, but it should be set to false when | 227 * exceptions to show up in unit tests, but it should be set to false when |
| 228 * running a full analysis server. | 228 * running a full analysis server. |
| 229 */ | 229 */ |
| 230 AnalysisServer(this.channel, this.resourceProvider, | 230 AnalysisServer(this.channel, this.resourceProvider, |
| 231 PackageMapProvider packageMapProvider, this.index, this.defaultSdk, | 231 PackageMapProvider packageMapProvider, this.index, this.defaultSdk, |
| 232 {this.rethrowExceptions: true}) { | 232 {this.rethrowExceptions: true}) { |
| 233 searchEngine = createSearchEngine(index); | 233 searchEngine = createSearchEngine(index); |
| 234 operationQueue = new ServerOperationQueue(this); | 234 operationQueue = new ServerOperationQueue(this); |
| 235 contextDirectoryManager = | 235 contextDirectoryManager = |
| 236 new ServerContextManager(this, resourceProvider, packageMapProvider); | 236 new ServerContextManager(this, resourceProvider, packageMapProvider); |
| 237 AnalysisEngine.instance.logger = new AnalysisLogger(); | 237 AnalysisEngine.instance.logger = new AnalysisLogger(); |
| 238 _onAnalysisCompleteController = new StreamController.broadcast(onListen: () { | |
| 239 if (isAnalysisComplete()) { | |
| 240 _onAnalysisCompleteController.add(null); | |
|
Paul Berry
2014/09/22 15:52:21
This will notify *all* listeners that analysis is
scheglov
2014/09/22 18:03:18
Done.
| |
| 241 } | |
| 242 }); | |
| 238 running = true; | 243 running = true; |
| 239 Notification notification = new ServerConnectedParams().toNotification(); | 244 Notification notification = new ServerConnectedParams().toNotification(); |
| 240 channel.sendNotification(notification); | 245 channel.sendNotification(notification); |
| 241 channel.listen(handleRequest, onDone: done, onError: error); | 246 channel.listen(handleRequest, onDone: done, onError: error); |
| 242 } | 247 } |
| 243 | 248 |
| 244 /** | 249 /** |
| 245 * Schedules execution of the given [ServerOperation]. | 250 * Schedules execution of the given [ServerOperation]. |
| 246 */ | 251 */ |
| 247 void scheduleOperation(ServerOperation operation) { | 252 void scheduleOperation(ServerOperation operation) { |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 327 // | 332 // |
| 328 // Update the defaults used to create new contexts. | 333 // Update the defaults used to create new contexts. |
| 329 // | 334 // |
| 330 AnalysisOptionsImpl options = contextDirectoryManager.defaultOptions; | 335 AnalysisOptionsImpl options = contextDirectoryManager.defaultOptions; |
| 331 optionUpdaters.forEach((OptionUpdater optionUpdater) { | 336 optionUpdaters.forEach((OptionUpdater optionUpdater) { |
| 332 optionUpdater(options); | 337 optionUpdater(options); |
| 333 }); | 338 }); |
| 334 } | 339 } |
| 335 | 340 |
| 336 /** | 341 /** |
| 337 * Add the given [listener] to the list of listeners that are listening for | 342 * The stream that is notified when analysis is complete. |
| 338 * lifecycle events from this server. | |
| 339 */ | 343 */ |
| 340 void addAnalysisServerListener(AnalysisServerListener listener) { | 344 Stream get onAnalysisComplete => _onAnalysisCompleteController.stream; |
| 341 if (!listeners.contains(listener)) { | |
| 342 listeners.add(listener); | |
| 343 } | |
| 344 } | |
| 345 | 345 |
| 346 /** | 346 /** |
| 347 * Adds the given [ServerOperation] to the queue, but does not schedule | 347 * Adds the given [ServerOperation] to the queue, but does not schedule |
| 348 * operations execution. | 348 * operations execution. |
| 349 */ | 349 */ |
| 350 void addOperation(ServerOperation operation) { | 350 void addOperation(ServerOperation operation) { |
| 351 operationQueue.add(operation); | 351 operationQueue.add(operation); |
| 352 } | 352 } |
| 353 | 353 |
| 354 /** | 354 /** |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 475 'Unexpected exception during analysis', | 475 'Unexpected exception during analysis', |
| 476 new CaughtException(exception, stackTrace)); | 476 new CaughtException(exception, stackTrace)); |
| 477 } | 477 } |
| 478 _sendServerErrorNotification(exception, stackTrace); | 478 _sendServerErrorNotification(exception, stackTrace); |
| 479 shutdown(); | 479 shutdown(); |
| 480 } finally { | 480 } finally { |
| 481 if (!operationQueue.isEmpty) { | 481 if (!operationQueue.isEmpty) { |
| 482 _schedulePerformOperation(); | 482 _schedulePerformOperation(); |
| 483 } else { | 483 } else { |
| 484 sendStatusNotification(null); | 484 sendStatusNotification(null); |
| 485 _notifyAnalysisComplete(); | 485 _onAnalysisCompleteController.add(null); |
| 486 } | 486 } |
| 487 } | 487 } |
| 488 } | 488 } |
| 489 | 489 |
| 490 /** | 490 /** |
| 491 * Trigger reanalysis of all files from disk. | 491 * Trigger reanalysis of all files from disk. |
| 492 */ | 492 */ |
| 493 void reanalyze() { | 493 void reanalyze() { |
| 494 // Clear any operations that are pending. | 494 // Clear any operations that are pending. |
| 495 operationQueue.clear(); | 495 operationQueue.clear(); |
| 496 // Instruct the contextDirectoryManager to rebuild all contexts from | 496 // Instruct the contextDirectoryManager to rebuild all contexts from |
| 497 // scratch. | 497 // scratch. |
| 498 contextDirectoryManager.refresh(); | 498 contextDirectoryManager.refresh(); |
| 499 } | 499 } |
| 500 | 500 |
| 501 /** | 501 /** |
| 502 * Remove the given [listener] from the list of listeners that are listening | |
| 503 * for lifecycle events from this server. | |
| 504 */ | |
| 505 void removeAnalysisServerListener(AnalysisServerListener listener) { | |
| 506 listeners.remove(listener); | |
| 507 } | |
| 508 | |
| 509 /** | |
| 510 * Send status notification to the client. The `operation` is the operation | 502 * Send status notification to the client. The `operation` is the operation |
| 511 * being performed or `null` if analysis is complete. | 503 * being performed or `null` if analysis is complete. |
| 512 */ | 504 */ |
| 513 void sendStatusNotification(ServerOperation operation) { | 505 void sendStatusNotification(ServerOperation operation) { |
| 514 // Only send status when subscribed. | 506 // Only send status when subscribed. |
| 515 if (!serverServices.contains(ServerService.STATUS)) { | 507 if (!serverServices.contains(ServerService.STATUS)) { |
| 516 return; | 508 return; |
| 517 } | 509 } |
| 518 // Only send status when it changes | 510 // Only send status when it changes |
| 519 bool isAnalyzing = operation != null; | 511 bool isAnalyzing = operation != null; |
| (...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 896 } | 888 } |
| 897 | 889 |
| 898 /** | 890 /** |
| 899 * Return `true` if all operations have been performed in this [AnalysisServer ]. | 891 * Return `true` if all operations have been performed in this [AnalysisServer ]. |
| 900 */ | 892 */ |
| 901 bool test_areOperationsFinished() { | 893 bool test_areOperationsFinished() { |
| 902 return operationQueue.isEmpty; | 894 return operationQueue.isEmpty; |
| 903 } | 895 } |
| 904 | 896 |
| 905 /** | 897 /** |
| 906 * Notify all listeners that analysis is complete. | |
| 907 */ | |
| 908 void _notifyAnalysisComplete() { | |
| 909 listeners.forEach((AnalysisServerListener listener) { | |
| 910 listener.analysisComplete(); | |
| 911 }); | |
| 912 } | |
| 913 | |
| 914 /** | |
| 915 * Schedules [performOperation] exection. | 898 * Schedules [performOperation] exection. |
| 916 */ | 899 */ |
| 917 void _schedulePerformOperation() { | 900 void _schedulePerformOperation() { |
| 918 new Future(performOperation); | 901 new Future(performOperation); |
| 919 } | 902 } |
| 920 | 903 |
| 921 /** | 904 /** |
| 922 * Sends a fatal `server.error` notification. | 905 * Sends a fatal `server.error` notification. |
| 923 */ | 906 */ |
| 924 void _sendServerErrorNotification(exception, stackTrace) { | 907 void _sendServerErrorNotification(exception, stackTrace) { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 938 } | 921 } |
| 939 // send the notification | 922 // send the notification |
| 940 channel.sendNotification( | 923 channel.sendNotification( |
| 941 new ServerErrorParams( | 924 new ServerErrorParams( |
| 942 true, | 925 true, |
| 943 exceptionString, | 926 exceptionString, |
| 944 stackTraceString).toNotification()); | 927 stackTraceString).toNotification()); |
| 945 } | 928 } |
| 946 } | 929 } |
| 947 | 930 |
| 948 /** | |
| 949 * An object that is listening for lifecycle events from an analysis server. | |
| 950 */ | |
| 951 abstract class AnalysisServerListener { | |
| 952 /** | |
| 953 * Analysis is complete. | |
| 954 */ | |
| 955 void analysisComplete(); | |
| 956 } | |
| 957 | |
| 958 typedef void OptionUpdater(AnalysisOptionsImpl options); | 931 typedef void OptionUpdater(AnalysisOptionsImpl options); |
| OLD | NEW |