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 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 * [addedContexts] lists contexts that were added to the server. | |
|
Brian Wilkerson
2014/11/17 15:58:34
These comments don't follow the form you used else
danrubel
2014/11/17 17:10:14
Done.
| |
| 123 */ | |
| 124 List<AnalysisContext> addedContexts; | |
| 125 | |
| 126 /** | |
| 127 * [changedContexts] lists contexts that were changed. | |
| 128 */ | |
| 129 List<AnalysisContext> changedContexts; | |
| 130 | |
| 131 /** | |
| 132 * [removedContexts] lists contexts that were removed from the server. | |
| 133 */ | |
| 134 List<AnalysisContext> removedContexts; | |
| 135 | |
| 136 ContextsChangedEvent({List<AnalysisContext> added: null, | |
| 137 List<AnalysisContext> changed: null, List<AnalysisContext> removed: null}) { | |
|
Brian Wilkerson
2014/11/17 15:58:34
How about something like:
ContextsChangedEvent({t
danrubel
2014/11/17 17:10:14
Good point. Done.
| |
| 138 addedContexts = added != null ? added : []; | |
| 139 changedContexts = changed != null ? changed : []; | |
| 140 removedContexts = removed != null ? removed : []; | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 | |
| 145 /** | |
| 95 * Enum representing reasons why analysis might be done for a given file. | 146 * Enum representing reasons why analysis might be done for a given file. |
| 96 */ | 147 */ |
| 97 class AnalysisDoneReason { | 148 class AnalysisDoneReason { |
| 98 /** | 149 /** |
| 99 * Analysis of the file completed successfully. | 150 * Analysis of the file completed successfully. |
| 100 */ | 151 */ |
| 101 static const AnalysisDoneReason COMPLETE = | 152 static const AnalysisDoneReason COMPLETE = |
| 102 const AnalysisDoneReason._('COMPLETE'); | 153 const AnalysisDoneReason._('COMPLETE'); |
| 103 | 154 |
| 104 /** | 155 /** |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 222 */ | 273 */ |
| 223 StreamController<ChangeNotice> _onFileAnalyzedController; | 274 StreamController<ChangeNotice> _onFileAnalyzedController; |
| 224 | 275 |
| 225 /** | 276 /** |
| 226 * True if any exceptions thrown by analysis should be propagated up the call | 277 * True if any exceptions thrown by analysis should be propagated up the call |
| 227 * stack. | 278 * stack. |
| 228 */ | 279 */ |
| 229 bool rethrowExceptions; | 280 bool rethrowExceptions; |
| 230 | 281 |
| 231 /** | 282 /** |
| 283 * The stream that is notified when contexts are added or removed. | |
| 284 */ | |
| 285 Stream<ContextsChangedEvent> onContextsChanged; | |
| 286 | |
| 287 /** | |
| 232 * Initialize a newly created server to receive requests from and send | 288 * Initialize a newly created server to receive requests from and send |
| 233 * responses to the given [channel]. | 289 * responses to the given [channel]. |
| 234 * | 290 * |
| 235 * If [rethrowExceptions] is true, then any exceptions thrown by analysis are | 291 * If [rethrowExceptions] is true, then any exceptions thrown by analysis are |
| 236 * propagated up the call stack. The default is true to allow analysis | 292 * 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 | 293 * exceptions to show up in unit tests, but it should be set to false when |
| 238 * running a full analysis server. | 294 * running a full analysis server. |
| 239 */ | 295 */ |
| 240 AnalysisServer(this.channel, this.resourceProvider, | 296 AnalysisServer(this.channel, this.resourceProvider, |
| 241 PackageMapProvider packageMapProvider, this.index, this.defaultSdk, | 297 PackageMapProvider packageMapProvider, this.index, this.defaultSdk, |
| 242 {this.rethrowExceptions: true}) { | 298 {this.rethrowExceptions: true}) { |
| 243 searchEngine = createSearchEngine(index); | 299 searchEngine = createSearchEngine(index); |
| 244 operationQueue = new ServerOperationQueue(this); | 300 operationQueue = new ServerOperationQueue(this); |
| 245 contextDirectoryManager = | 301 contextDirectoryManager = |
| 246 new ServerContextManager(this, resourceProvider, packageMapProvider); | 302 new ServerContextManager(this, resourceProvider, packageMapProvider); |
| 303 onContextsChanged = | |
| 304 contextDirectoryManager.onContextsChanged.asBroadcastStream(); | |
| 247 AnalysisEngine.instance.logger = new AnalysisLogger(); | 305 AnalysisEngine.instance.logger = new AnalysisLogger(); |
| 248 _onAnalysisStartedController = new StreamController.broadcast(); | 306 _onAnalysisStartedController = new StreamController.broadcast(); |
| 249 _onAnalysisCompleteController = new StreamController.broadcast(); | 307 _onAnalysisCompleteController = new StreamController.broadcast(); |
| 250 _onFileAnalyzedController = new StreamController.broadcast(); | 308 _onFileAnalyzedController = new StreamController.broadcast(); |
| 251 running = true; | 309 running = true; |
| 252 Notification notification = new ServerConnectedParams().toNotification(); | 310 Notification notification = new ServerConnectedParams().toNotification(); |
| 253 channel.sendNotification(notification); | 311 channel.sendNotification(notification); |
| 254 channel.listen(handleRequest, onDone: done, onError: error); | 312 channel.listen(handleRequest, onDone: done, onError: error); |
| 255 } | 313 } |
| 256 | 314 |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 428 return; | 486 return; |
| 429 } | 487 } |
| 430 if (response != null) { | 488 if (response != null) { |
| 431 channel.sendResponse(response); | 489 channel.sendResponse(response); |
| 432 return; | 490 return; |
| 433 } | 491 } |
| 434 } on RequestFailure catch (exception) { | 492 } on RequestFailure catch (exception) { |
| 435 channel.sendResponse(exception.response); | 493 channel.sendResponse(exception.response); |
| 436 return; | 494 return; |
| 437 } catch (exception, stackTrace) { | 495 } catch (exception, stackTrace) { |
| 438 RequestError error = new RequestError( | 496 RequestError error = |
| 439 RequestErrorCode.SERVER_ERROR, | 497 new RequestError(RequestErrorCode.SERVER_ERROR, exception.toString ()); |
| 440 exception.toString()); | |
| 441 if (stackTrace != null) { | 498 if (stackTrace != null) { |
| 442 error.stackTrace = stackTrace.toString(); | 499 error.stackTrace = stackTrace.toString(); |
| 443 } | 500 } |
| 444 Response response = new Response(request.id, error: error); | 501 Response response = new Response(request.id, error: error); |
| 445 channel.sendResponse(response); | 502 channel.sendResponse(response); |
| 446 return; | 503 return; |
| 447 } | 504 } |
| 448 } | 505 } |
| 449 channel.sendResponse(new Response.unknownRequest(request)); | 506 channel.sendResponse(new Response.unknownRequest(request)); |
| 450 }, onError: _sendServerErrorNotification); | 507 }, onError: _sendServerErrorNotification); |
| (...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 913 index.stop(); | 970 index.stop(); |
| 914 } | 971 } |
| 915 // Defer closing the channel so that the shutdown response can be sent. | 972 // Defer closing the channel so that the shutdown response can be sent. |
| 916 new Future(channel.close); | 973 new Future(channel.close); |
| 917 } | 974 } |
| 918 | 975 |
| 919 /** | 976 /** |
| 920 * Schedules [performOperation] exection. | 977 * Schedules [performOperation] exection. |
| 921 */ | 978 */ |
| 922 void _schedulePerformOperation() { | 979 void _schedulePerformOperation() { |
| 923 assert (!performOperationPending); | 980 assert(!performOperationPending); |
| 924 new Future(performOperation); | 981 new Future(performOperation); |
| 925 performOperationPending = true; | 982 performOperationPending = true; |
| 926 } | 983 } |
| 927 | 984 |
| 928 /** | 985 /** |
| 929 * Sends a fatal `server.error` notification. | 986 * Sends a fatal `server.error` notification. |
| 930 */ | 987 */ |
| 931 void _sendServerErrorNotification(exception, stackTrace) { | 988 void _sendServerErrorNotification(exception, stackTrace) { |
| 932 // prepare exception.toString() | 989 // prepare exception.toString() |
| 933 String exceptionString; | 990 String exceptionString; |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 946 // send the notification | 1003 // send the notification |
| 947 channel.sendNotification( | 1004 channel.sendNotification( |
| 948 new ServerErrorParams( | 1005 new ServerErrorParams( |
| 949 true, | 1006 true, |
| 950 exceptionString, | 1007 exceptionString, |
| 951 stackTraceString).toNotification()); | 1008 stackTraceString).toNotification()); |
| 952 } | 1009 } |
| 953 } | 1010 } |
| 954 | 1011 |
| 955 typedef void OptionUpdater(AnalysisOptionsImpl options); | 1012 typedef void OptionUpdater(AnalysisOptionsImpl options); |
| OLD | NEW |