| 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 18 matching lines...) Expand all Loading... |
| 29 | 29 |
| 30 | 30 |
| 31 class ServerContextManager extends ContextManager { | 31 class ServerContextManager extends ContextManager { |
| 32 final AnalysisServer analysisServer; | 32 final AnalysisServer analysisServer; |
| 33 | 33 |
| 34 /** | 34 /** |
| 35 * The default options used to create new analysis contexts. | 35 * The default options used to create new analysis contexts. |
| 36 */ | 36 */ |
| 37 AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl(); | 37 AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl(); |
| 38 | 38 |
| 39 /** |
| 40 * The controller for sending [ContextsChangedEvent]s. |
| 41 */ |
| 42 StreamController<ContextsChangedEvent> _onContextsChangedController; |
| 43 |
| 39 ServerContextManager(this.analysisServer, ResourceProvider resourceProvider, | 44 ServerContextManager(this.analysisServer, ResourceProvider resourceProvider, |
| 40 PackageMapProvider packageMapProvider) | 45 PackageMapProvider packageMapProvider) |
| 41 : super(resourceProvider, packageMapProvider); | 46 : super(resourceProvider, packageMapProvider) { |
| 47 _onContextsChangedController = new StreamController<ContextsChangedEvent>(); |
| 48 } |
| 49 |
| 50 /** |
| 51 * The stream that is notified when contexts are added or removed. |
| 52 */ |
| 53 Stream<ContextsChangedEvent> get onContextsChanged => |
| 54 _onContextsChangedController.stream; |
| 42 | 55 |
| 43 @override | 56 @override |
| 44 void addContext(Folder folder, UriResolver packageUriResolver) { | 57 void addContext(Folder folder, UriResolver packageUriResolver) { |
| 45 AnalysisContext context = AnalysisEngine.instance.createAnalysisContext(); | 58 AnalysisContext context = AnalysisEngine.instance.createAnalysisContext(); |
| 46 analysisServer.folderMap[folder] = context; | 59 analysisServer.folderMap[folder] = context; |
| 47 context.sourceFactory = _createSourceFactory(packageUriResolver); | 60 context.sourceFactory = _createSourceFactory(packageUriResolver); |
| 48 context.analysisOptions = new AnalysisOptionsImpl.con1(defaultOptions); | 61 context.analysisOptions = new AnalysisOptionsImpl.con1(defaultOptions); |
| 62 _onContextsChangedController.add( |
| 63 new ContextsChangedEvent(added: [context])); |
| 49 analysisServer.schedulePerformAnalysisOperation(context); | 64 analysisServer.schedulePerformAnalysisOperation(context); |
| 50 } | 65 } |
| 51 | 66 |
| 52 @override | 67 @override |
| 53 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) { | 68 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) { |
| 54 AnalysisContext context = analysisServer.folderMap[contextFolder]; | 69 AnalysisContext context = analysisServer.folderMap[contextFolder]; |
| 55 if (context != null) { | 70 if (context != null) { |
| 56 context.applyChanges(changeSet); | 71 context.applyChanges(changeSet); |
| 57 analysisServer.schedulePerformAnalysisOperation(context); | 72 analysisServer.schedulePerformAnalysisOperation(context); |
| 58 } | 73 } |
| 59 } | 74 } |
| 60 | 75 |
| 61 @override | 76 @override |
| 62 void removeContext(Folder folder) { | 77 void removeContext(Folder folder) { |
| 63 AnalysisContext context = analysisServer.folderMap.remove(folder); | 78 AnalysisContext context = analysisServer.folderMap.remove(folder); |
| 64 if (analysisServer.index != null) { | 79 if (analysisServer.index != null) { |
| 65 analysisServer.index.removeContext(context); | 80 analysisServer.index.removeContext(context); |
| 66 } | 81 } |
| 82 _onContextsChangedController.add( |
| 83 new ContextsChangedEvent(removed: [context])); |
| 67 analysisServer.sendContextAnalysisDoneNotifications( | 84 analysisServer.sendContextAnalysisDoneNotifications( |
| 68 context, | 85 context, |
| 69 AnalysisDoneReason.CONTEXT_REMOVED); | 86 AnalysisDoneReason.CONTEXT_REMOVED); |
| 70 } | 87 } |
| 71 | 88 |
| 72 @override | 89 @override |
| 73 void updateContextPackageUriResolver(Folder contextFolder, | 90 void updateContextPackageUriResolver(Folder contextFolder, |
| 74 UriResolver packageUriResolver) { | 91 UriResolver packageUriResolver) { |
| 75 AnalysisContext context = analysisServer.folderMap[contextFolder]; | 92 AnalysisContext context = analysisServer.folderMap[contextFolder]; |
| 76 context.sourceFactory = _createSourceFactory(packageUriResolver); | 93 context.sourceFactory = _createSourceFactory(packageUriResolver); |
| 94 _onContextsChangedController.add( |
| 95 new ContextsChangedEvent(changed: [context])); |
| 77 analysisServer.schedulePerformAnalysisOperation(context); | 96 analysisServer.schedulePerformAnalysisOperation(context); |
| 78 } | 97 } |
| 79 | 98 |
| 80 /** | 99 /** |
| 81 * Set up a [SourceFactory] that resolves packages using the given | 100 * Set up a [SourceFactory] that resolves packages using the given |
| 82 * [packageUriResolver]. | 101 * [packageUriResolver]. |
| 83 */ | 102 */ |
| 84 SourceFactory _createSourceFactory(UriResolver packageUriResolver) { | 103 SourceFactory _createSourceFactory(UriResolver packageUriResolver) { |
| 85 List<UriResolver> resolvers = <UriResolver>[ | 104 List<UriResolver> resolvers = <UriResolver>[ |
| 86 new DartUriResolver(analysisServer.defaultSdk), | 105 new DartUriResolver(analysisServer.defaultSdk), |
| 87 new ResourceUriResolver(resourceProvider), | 106 new ResourceUriResolver(resourceProvider), |
| 88 packageUriResolver]; | 107 packageUriResolver]; |
| 89 return new SourceFactory(resolvers); | 108 return new SourceFactory(resolvers); |
| 90 } | 109 } |
| 91 } | 110 } |
| 92 | 111 |
| 93 | 112 |
| 94 /** | 113 /** |
| 114 * A [ContextsChangedEvent] indicate what contexts were added or removed. |
| 115 * |
| 116 * No context should be added to the event more than once. It does not make |
| 117 * sense, for example, for a context to be both added and removed. |
| 118 */ |
| 119 class ContextsChangedEvent { |
| 120 |
| 121 /** |
| 122 * The contexts that were added to the server. |
| 123 */ |
| 124 final List<AnalysisContext> added; |
| 125 |
| 126 /** |
| 127 * The contexts that were changed. |
| 128 */ |
| 129 final List<AnalysisContext> changed; |
| 130 |
| 131 /** |
| 132 * The contexts that were removed from the server. |
| 133 */ |
| 134 final List<AnalysisContext> removed; |
| 135 |
| 136 ContextsChangedEvent({ |
| 137 this.added: AnalysisContext.EMPTY_LIST, |
| 138 this.changed: AnalysisContext.EMPTY_LIST, |
| 139 this.removed: AnalysisContext.EMPTY_LIST}); |
| 140 } |
| 141 |
| 142 |
| 143 /** |
| 95 * Enum representing reasons why analysis might be done for a given file. | 144 * Enum representing reasons why analysis might be done for a given file. |
| 96 */ | 145 */ |
| 97 class AnalysisDoneReason { | 146 class AnalysisDoneReason { |
| 98 /** | 147 /** |
| 99 * Analysis of the file completed successfully. | 148 * Analysis of the file completed successfully. |
| 100 */ | 149 */ |
| 101 static const AnalysisDoneReason COMPLETE = | 150 static const AnalysisDoneReason COMPLETE = |
| 102 const AnalysisDoneReason._('COMPLETE'); | 151 const AnalysisDoneReason._('COMPLETE'); |
| 103 | 152 |
| 104 /** | 153 /** |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 222 */ | 271 */ |
| 223 StreamController<ChangeNotice> _onFileAnalyzedController; | 272 StreamController<ChangeNotice> _onFileAnalyzedController; |
| 224 | 273 |
| 225 /** | 274 /** |
| 226 * True if any exceptions thrown by analysis should be propagated up the call | 275 * True if any exceptions thrown by analysis should be propagated up the call |
| 227 * stack. | 276 * stack. |
| 228 */ | 277 */ |
| 229 bool rethrowExceptions; | 278 bool rethrowExceptions; |
| 230 | 279 |
| 231 /** | 280 /** |
| 281 * The stream that is notified when contexts are added or removed. |
| 282 */ |
| 283 Stream<ContextsChangedEvent> onContextsChanged; |
| 284 |
| 285 /** |
| 232 * Initialize a newly created server to receive requests from and send | 286 * Initialize a newly created server to receive requests from and send |
| 233 * responses to the given [channel]. | 287 * responses to the given [channel]. |
| 234 * | 288 * |
| 235 * If [rethrowExceptions] is true, then any exceptions thrown by analysis are | 289 * If [rethrowExceptions] is true, then any exceptions thrown by analysis are |
| 236 * propagated up the call stack. The default is true to allow analysis | 290 * propagated up the call stack. The default is true to allow analysis |
| 237 * exceptions to show up in unit tests, but it should be set to false when | 291 * exceptions to show up in unit tests, but it should be set to false when |
| 238 * running a full analysis server. | 292 * running a full analysis server. |
| 239 */ | 293 */ |
| 240 AnalysisServer(this.channel, this.resourceProvider, | 294 AnalysisServer(this.channel, this.resourceProvider, |
| 241 PackageMapProvider packageMapProvider, this.index, this.defaultSdk, | 295 PackageMapProvider packageMapProvider, this.index, this.defaultSdk, |
| 242 {this.rethrowExceptions: true}) { | 296 {this.rethrowExceptions: true}) { |
| 243 searchEngine = createSearchEngine(index); | 297 searchEngine = createSearchEngine(index); |
| 244 operationQueue = new ServerOperationQueue(this); | 298 operationQueue = new ServerOperationQueue(this); |
| 245 contextDirectoryManager = | 299 contextDirectoryManager = |
| 246 new ServerContextManager(this, resourceProvider, packageMapProvider); | 300 new ServerContextManager(this, resourceProvider, packageMapProvider); |
| 301 onContextsChanged = |
| 302 contextDirectoryManager.onContextsChanged.asBroadcastStream(); |
| 247 AnalysisEngine.instance.logger = new AnalysisLogger(); | 303 AnalysisEngine.instance.logger = new AnalysisLogger(); |
| 248 _onAnalysisStartedController = new StreamController.broadcast(); | 304 _onAnalysisStartedController = new StreamController.broadcast(); |
| 249 _onAnalysisCompleteController = new StreamController.broadcast(); | 305 _onAnalysisCompleteController = new StreamController.broadcast(); |
| 250 _onFileAnalyzedController = new StreamController.broadcast(); | 306 _onFileAnalyzedController = new StreamController.broadcast(); |
| 251 running = true; | 307 running = true; |
| 252 Notification notification = new ServerConnectedParams().toNotification(); | 308 Notification notification = new ServerConnectedParams().toNotification(); |
| 253 channel.sendNotification(notification); | 309 channel.sendNotification(notification); |
| 254 channel.listen(handleRequest, onDone: done, onError: error); | 310 channel.listen(handleRequest, onDone: done, onError: error); |
| 255 } | 311 } |
| 256 | 312 |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 return; | 484 return; |
| 429 } | 485 } |
| 430 if (response != null) { | 486 if (response != null) { |
| 431 channel.sendResponse(response); | 487 channel.sendResponse(response); |
| 432 return; | 488 return; |
| 433 } | 489 } |
| 434 } on RequestFailure catch (exception) { | 490 } on RequestFailure catch (exception) { |
| 435 channel.sendResponse(exception.response); | 491 channel.sendResponse(exception.response); |
| 436 return; | 492 return; |
| 437 } catch (exception, stackTrace) { | 493 } catch (exception, stackTrace) { |
| 438 RequestError error = new RequestError( | 494 RequestError error = |
| 439 RequestErrorCode.SERVER_ERROR, | 495 new RequestError(RequestErrorCode.SERVER_ERROR, exception.toString
()); |
| 440 exception.toString()); | |
| 441 if (stackTrace != null) { | 496 if (stackTrace != null) { |
| 442 error.stackTrace = stackTrace.toString(); | 497 error.stackTrace = stackTrace.toString(); |
| 443 } | 498 } |
| 444 Response response = new Response(request.id, error: error); | 499 Response response = new Response(request.id, error: error); |
| 445 channel.sendResponse(response); | 500 channel.sendResponse(response); |
| 446 return; | 501 return; |
| 447 } | 502 } |
| 448 } | 503 } |
| 449 channel.sendResponse(new Response.unknownRequest(request)); | 504 channel.sendResponse(new Response.unknownRequest(request)); |
| 450 }, onError: _sendServerErrorNotification); | 505 }, onError: _sendServerErrorNotification); |
| (...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 913 index.stop(); | 968 index.stop(); |
| 914 } | 969 } |
| 915 // Defer closing the channel so that the shutdown response can be sent. | 970 // Defer closing the channel so that the shutdown response can be sent. |
| 916 new Future(channel.close); | 971 new Future(channel.close); |
| 917 } | 972 } |
| 918 | 973 |
| 919 /** | 974 /** |
| 920 * Schedules [performOperation] exection. | 975 * Schedules [performOperation] exection. |
| 921 */ | 976 */ |
| 922 void _schedulePerformOperation() { | 977 void _schedulePerformOperation() { |
| 923 assert (!performOperationPending); | 978 assert(!performOperationPending); |
| 924 new Future(performOperation); | 979 new Future(performOperation); |
| 925 performOperationPending = true; | 980 performOperationPending = true; |
| 926 } | 981 } |
| 927 | 982 |
| 928 /** | 983 /** |
| 929 * Sends a fatal `server.error` notification. | 984 * Sends a fatal `server.error` notification. |
| 930 */ | 985 */ |
| 931 void _sendServerErrorNotification(exception, stackTrace) { | 986 void _sendServerErrorNotification(exception, stackTrace) { |
| 932 // prepare exception.toString() | 987 // prepare exception.toString() |
| 933 String exceptionString; | 988 String exceptionString; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 946 // send the notification | 1001 // send the notification |
| 947 channel.sendNotification( | 1002 channel.sendNotification( |
| 948 new ServerErrorParams( | 1003 new ServerErrorParams( |
| 949 true, | 1004 true, |
| 950 exceptionString, | 1005 exceptionString, |
| 951 stackTraceString).toNotification()); | 1006 stackTraceString).toNotification()); |
| 952 } | 1007 } |
| 953 } | 1008 } |
| 954 | 1009 |
| 955 typedef void OptionUpdater(AnalysisOptionsImpl options); | 1010 typedef void OptionUpdater(AnalysisOptionsImpl options); |
| OLD | NEW |