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:analysis_server/src/analysis_logger.dart'; | 10 import 'package:analysis_server/src/analysis_logger.dart'; |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 37 final DirectoryBasedDartSdk SHARED_SDK = DirectoryBasedDartSdk.defaultSdk; | 37 final DirectoryBasedDartSdk SHARED_SDK = DirectoryBasedDartSdk.defaultSdk; |
| 38 | 38 |
| 39 class AnalysisServerContextDirectoryManager extends ContextDirectoryManager { | 39 class AnalysisServerContextDirectoryManager extends ContextDirectoryManager { |
| 40 final AnalysisServer analysisServer; | 40 final AnalysisServer analysisServer; |
| 41 | 41 |
| 42 /** | 42 /** |
| 43 * The default options used to create new analysis contexts. | 43 * The default options used to create new analysis contexts. |
| 44 */ | 44 */ |
| 45 AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl(); | 45 AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl(); |
| 46 | 46 |
| 47 AnalysisServerContextDirectoryManager(this.analysisServer, ResourceProvider re sourceProvider) | 47 AnalysisServerContextDirectoryManager( |
| 48 : super(resourceProvider); | 48 this.analysisServer, ResourceProvider resourceProvider, |
| 49 PackageMapProvider packageMapProvider) | |
| 50 : super(resourceProvider, packageMapProvider); | |
| 49 | 51 |
| 50 @override | 52 @override |
| 51 void addContext(Folder folder) { | 53 void addContext(Folder folder, Map<String, List<Folder>> packageMap) { |
| 52 Map<String, List<Folder>> packageMap = | 54 AnalysisContext context = AnalysisEngine.instance.createAnalysisContext(); |
| 53 analysisServer.packageMapProvider.computePackageMap(folder); | 55 analysisServer.folderMap[folder] = context; |
| 54 ContextDirectory contextDirectory = new ContextDirectory( | 56 context.sourceFactory = _createSourceFactory(packageMap); |
| 55 analysisServer.defaultSdk, resourceProvider, folder, packageMap); | |
| 56 analysisServer.folderMap[folder] = contextDirectory; | |
| 57 AnalysisContext context = contextDirectory.context; | |
| 58 context.analysisOptions = new AnalysisOptionsImpl.con1(defaultOptions); | 57 context.analysisOptions = new AnalysisOptionsImpl.con1(defaultOptions); |
| 59 analysisServer.schedulePerformAnalysisOperation(context); | 58 analysisServer.schedulePerformAnalysisOperation(context); |
| 60 } | 59 } |
| 61 | 60 |
| 62 @override | 61 @override |
| 63 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) { | 62 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) { |
| 64 AnalysisContext context = analysisServer.folderMap[contextFolder].context; | 63 AnalysisContext context = analysisServer.folderMap[contextFolder]; |
| 65 context.applyChanges(changeSet); | 64 context.applyChanges(changeSet); |
| 66 analysisServer.schedulePerformAnalysisOperation(context); | 65 analysisServer.schedulePerformAnalysisOperation(context); |
| 67 } | 66 } |
| 68 | 67 |
| 69 @override | 68 @override |
| 70 void removeContext(Folder folder) { | 69 void removeContext(Folder folder) { |
| 71 analysisServer.folderMap.remove(folder); | 70 analysisServer.folderMap.remove(folder); |
| 72 } | 71 } |
| 72 | |
| 73 @override | |
| 74 void updateContextPackageMap(Folder contextFolder, | |
| 75 Map<String, List<Folder>> packageMap) { | |
| 76 AnalysisContext context = analysisServer.folderMap[contextFolder]; | |
| 77 context.sourceFactory = _createSourceFactory(packageMap); | |
| 78 analysisServer.schedulePerformAnalysisOperation(context); | |
| 79 } | |
| 80 | |
| 81 /** | |
| 82 * Set up a [SourceFactory] that resolves packages using the given | |
| 83 * [packageMap]. | |
| 84 */ | |
| 85 SourceFactory _createSourceFactory(Map<String, List<Folder>> packageMap) { | |
|
Brian Wilkerson
2014/06/30 16:53:16
Do we need to handle the case where the package ma
Paul Berry
2014/06/30 17:43:00
We don't need special code to handle an empty pack
| |
| 86 List<UriResolver> resolvers = <UriResolver>[ | |
| 87 new DartUriResolver(analysisServer.defaultSdk), | |
| 88 new ResourceUriResolver(resourceProvider), | |
|
Brian Wilkerson
2014/06/30 16:53:16
I assume ResourceUriResolver handles file: URI's,
Paul Berry
2014/06/30 17:43:00
You're correct that ResourceUriResolver only handl
| |
| 89 new PackageMapUriResolver(resourceProvider, packageMap) | |
| 90 ]; | |
| 91 return new SourceFactory(resolvers); | |
| 92 } | |
| 73 } | 93 } |
| 74 | 94 |
| 75 /** | 95 /** |
| 76 * Instances of the class [AnalysisServer] implement a server that listens on a | 96 * Instances of the class [AnalysisServer] implement a server that listens on a |
| 77 * [CommunicationChannel] for analysis requests and process them. | 97 * [CommunicationChannel] for analysis requests and process them. |
| 78 */ | 98 */ |
| 79 class AnalysisServer { | 99 class AnalysisServer { |
| 80 /** | 100 /** |
| 81 * The channel from which requests are received and to which responses should | 101 * The channel from which requests are received and to which responses should |
| 82 * be sent. | 102 * be sent. |
| 83 */ | 103 */ |
| 84 final ServerCommunicationChannel channel; | 104 final ServerCommunicationChannel channel; |
| 85 | 105 |
| 86 /** | 106 /** |
| 87 * The [Index] for this server. | 107 * The [Index] for this server. |
| 88 */ | 108 */ |
| 89 final Index index; | 109 final Index index; |
| 90 | 110 |
| 91 /** | 111 /** |
| 92 * [ContextDirectoryManager] which handles the mapping from analysis roots | 112 * [ContextDirectoryManager] which handles the mapping from analysis roots |
| 93 * to context directories. | 113 * to context directories. |
| 94 */ | 114 */ |
| 95 AnalysisServerContextDirectoryManager contextDirectoryManager; | 115 AnalysisServerContextDirectoryManager contextDirectoryManager; |
| 96 | 116 |
| 97 /** | 117 /** |
| 98 * Provider which is used to determine the mapping from package name to | |
| 99 * package folder. | |
| 100 */ | |
| 101 final PackageMapProvider packageMapProvider; | |
| 102 | |
| 103 /** | |
| 104 * A flag indicating whether the server is running. When false, contexts | 118 * A flag indicating whether the server is running. When false, contexts |
| 105 * will no longer be added to [contextWorkQueue], and [performOperation] will | 119 * will no longer be added to [contextWorkQueue], and [performOperation] will |
| 106 * discard any tasks it finds on [contextWorkQueue]. | 120 * discard any tasks it finds on [contextWorkQueue]. |
| 107 */ | 121 */ |
| 108 bool running; | 122 bool running; |
| 109 | 123 |
| 110 /** | 124 /** |
| 111 * A flag indicating the value of the 'analyzing' parameter sent in the last | 125 * A flag indicating the value of the 'analyzing' parameter sent in the last |
| 112 * status message to the client. | 126 * status message to the client. |
| 113 */ | 127 */ |
| 114 bool statusAnalyzing = false; | 128 bool statusAnalyzing = false; |
| 115 | 129 |
| 116 /** | 130 /** |
| 117 * A list of the request handlers used to handle the requests sent to this | 131 * A list of the request handlers used to handle the requests sent to this |
| 118 * server. | 132 * server. |
| 119 */ | 133 */ |
| 120 List<RequestHandler> handlers; | 134 List<RequestHandler> handlers; |
| 121 | 135 |
| 122 /** | 136 /** |
| 123 * The current default [DartSdk]. | 137 * The current default [DartSdk]. |
| 124 */ | 138 */ |
| 125 DartSdk defaultSdk = SHARED_SDK; | 139 DartSdk defaultSdk = SHARED_SDK; |
| 126 | 140 |
| 127 /** | 141 /** |
| 128 * A table mapping [Folder]s to the [ContextDirectory]s associated with them. | 142 * A table mapping [Folder]s to the [AnalysisContext]s associated with them. |
| 129 */ | 143 */ |
| 130 final Map<Folder, ContextDirectory> folderMap = | 144 final Map<Folder, AnalysisContext> folderMap = |
| 131 new HashMap<Folder, ContextDirectory>(); | 145 new HashMap<Folder, AnalysisContext>(); |
| 132 | 146 |
| 133 /** | 147 /** |
| 134 * A queue of the operations to perform in this server. | 148 * A queue of the operations to perform in this server. |
| 135 * | 149 * |
| 136 * Invariant: when this queue is non-empty, there is exactly one pending call | 150 * Invariant: when this queue is non-empty, there is exactly one pending call |
| 137 * to [performOperation] on the event queue. When this list is empty, there a re | 151 * to [performOperation] on the event queue. When this list is empty, there a re |
| 138 * no calls to [performOperation] on the event queue. | 152 * no calls to [performOperation] on the event queue. |
| 139 */ | 153 */ |
| 140 ServerOperationQueue operationQueue; | 154 ServerOperationQueue operationQueue; |
| 141 | 155 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 160 /** | 174 /** |
| 161 * Initialize a newly created server to receive requests from and send | 175 * Initialize a newly created server to receive requests from and send |
| 162 * responses to the given [channel]. | 176 * responses to the given [channel]. |
| 163 * | 177 * |
| 164 * If [rethrowExceptions] is true, then any exceptions thrown by analysis are | 178 * If [rethrowExceptions] is true, then any exceptions thrown by analysis are |
| 165 * propagated up the call stack. The default is true to allow analysis | 179 * propagated up the call stack. The default is true to allow analysis |
| 166 * exceptions to show up in unit tests, but it should be set to false when | 180 * exceptions to show up in unit tests, but it should be set to false when |
| 167 * running a full analysis server. | 181 * running a full analysis server. |
| 168 */ | 182 */ |
| 169 AnalysisServer(this.channel, ResourceProvider resourceProvider, | 183 AnalysisServer(this.channel, ResourceProvider resourceProvider, |
| 170 this.packageMapProvider, this.index, {this.rethrowExceptions: true}) { | 184 PackageMapProvider packageMapProvider, this.index, |
| 185 {this.rethrowExceptions: true}) { | |
| 171 operationQueue = new ServerOperationQueue(this); | 186 operationQueue = new ServerOperationQueue(this); |
| 172 contextDirectoryManager = new AnalysisServerContextDirectoryManager(this, re sourceProvider); | 187 contextDirectoryManager = new AnalysisServerContextDirectoryManager( |
| 188 this, resourceProvider, packageMapProvider); | |
| 173 AnalysisEngine.instance.logger = new AnalysisLogger(); | 189 AnalysisEngine.instance.logger = new AnalysisLogger(); |
| 174 running = true; | 190 running = true; |
| 175 Notification notification = new Notification(SERVER_CONNECTED); | 191 Notification notification = new Notification(SERVER_CONNECTED); |
| 176 channel.sendNotification(notification); | 192 channel.sendNotification(notification); |
| 177 channel.listen(handleRequest, onDone: done, onError: error); | 193 channel.listen(handleRequest, onDone: done, onError: error); |
| 178 } | 194 } |
| 179 | 195 |
| 180 /** | 196 /** |
| 181 * Schedules execution of the given [ServerOperation]. | 197 * Schedules execution of the given [ServerOperation]. |
| 182 */ | 198 */ |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 221 } | 237 } |
| 222 sourceList.add(_getSource(file)); | 238 sourceList.add(_getSource(file)); |
| 223 } | 239 } |
| 224 }); | 240 }); |
| 225 if (unanalyzed.isNotEmpty) { | 241 if (unanalyzed.isNotEmpty) { |
| 226 StringBuffer buffer = new StringBuffer(); | 242 StringBuffer buffer = new StringBuffer(); |
| 227 buffer.writeAll(unanalyzed, ', '); | 243 buffer.writeAll(unanalyzed, ', '); |
| 228 throw new RequestFailure(new Response.unanalyzedPriorityFiles(request, | 244 throw new RequestFailure(new Response.unanalyzedPriorityFiles(request, |
| 229 buffer.toString())); | 245 buffer.toString())); |
| 230 } | 246 } |
| 231 folderMap.forEach((Folder folder, ContextDirectory directory) { | 247 folderMap.forEach((Folder folder, AnalysisContext context) { |
| 232 AnalysisContext context = directory.context; | |
| 233 List<Source> sourceList = sourceMap[context]; | 248 List<Source> sourceList = sourceMap[context]; |
| 234 if (sourceList == null) { | 249 if (sourceList == null) { |
| 235 sourceList = Source.EMPTY_ARRAY; | 250 sourceList = Source.EMPTY_ARRAY; |
| 236 } | 251 } |
| 237 context.analysisPriorityOrder = sourceList; | 252 context.analysisPriorityOrder = sourceList; |
| 238 }); | 253 }); |
| 239 } | 254 } |
| 240 | 255 |
| 241 /** | 256 /** |
| 242 * Use the given updaters to update the values of the options in every | 257 * Use the given updaters to update the values of the options in every |
| 243 * existing analysis context. | 258 * existing analysis context. |
| 244 */ | 259 */ |
| 245 void updateOptions(List<OptionUpdater> optionUpdaters) { | 260 void updateOptions(List<OptionUpdater> optionUpdaters) { |
| 246 // | 261 // |
| 247 // Update existing contexts. | 262 // Update existing contexts. |
| 248 // | 263 // |
| 249 folderMap.forEach((Folder folder, ContextDirectory directory) { | 264 folderMap.forEach((Folder folder, AnalysisContext context) { |
| 250 AnalysisContext context = directory.context; | |
| 251 AnalysisOptionsImpl options = new AnalysisOptionsImpl.con1(context.analysi sOptions); | 265 AnalysisOptionsImpl options = new AnalysisOptionsImpl.con1(context.analysi sOptions); |
| 252 optionUpdaters.forEach((OptionUpdater optionUpdater) { | 266 optionUpdaters.forEach((OptionUpdater optionUpdater) { |
| 253 optionUpdater(options); | 267 optionUpdater(options); |
| 254 }); | 268 }); |
| 255 context.analysisOptions = options; | 269 context.analysisOptions = options; |
| 256 }); | 270 }); |
| 257 // | 271 // |
| 258 // Update the defaults used to create new contexts. | 272 // Update the defaults used to create new contexts. |
| 259 // | 273 // |
| 260 AnalysisOptionsImpl options = contextDirectoryManager.defaultOptions; | 274 AnalysisOptionsImpl options = contextDirectoryManager.defaultOptions; |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 477 this.analysisServices = subscriptions; | 491 this.analysisServices = subscriptions; |
| 478 } | 492 } |
| 479 | 493 |
| 480 /** | 494 /** |
| 481 * Return the [AnalysisContext] that is used to analyze the given [path]. | 495 * Return the [AnalysisContext] that is used to analyze the given [path]. |
| 482 * Return `null` if there is no such context. | 496 * Return `null` if there is no such context. |
| 483 */ | 497 */ |
| 484 AnalysisContext _getAnalysisContext(String path) { | 498 AnalysisContext _getAnalysisContext(String path) { |
| 485 for (Folder folder in folderMap.keys) { | 499 for (Folder folder in folderMap.keys) { |
| 486 if (path.startsWith(folder.path)) { | 500 if (path.startsWith(folder.path)) { |
| 487 return folderMap[folder].context; | 501 return folderMap[folder]; |
| 488 } | 502 } |
| 489 } | 503 } |
| 490 return null; | 504 return null; |
| 491 } | 505 } |
| 492 | 506 |
| 493 /** | 507 /** |
| 494 * Return the [Source] of the Dart file with the given [path]. | 508 * Return the [Source] of the Dart file with the given [path]. |
| 495 */ | 509 */ |
| 496 Source _getSource(String path) { | 510 Source _getSource(String path) { |
| 497 File file = contextDirectoryManager.resourceProvider.getResource(path); | 511 File file = contextDirectoryManager.resourceProvider.getResource(path); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 570 static const AnalysisService NAVIGATION = const AnalysisService('NAVIGATION', 2); | 584 static const AnalysisService NAVIGATION = const AnalysisService('NAVIGATION', 2); |
| 571 static const AnalysisService OUTLINE = const AnalysisService('OUTLINE', 3); | 585 static const AnalysisService OUTLINE = const AnalysisService('OUTLINE', 3); |
| 572 | 586 |
| 573 static const List<AnalysisService> VALUES = | 587 static const List<AnalysisService> VALUES = |
| 574 const [ERRORS, HIGHLIGHTS, NAVIGATION, OUTLINE]; | 588 const [ERRORS, HIGHLIGHTS, NAVIGATION, OUTLINE]; |
| 575 | 589 |
| 576 const AnalysisService(String name, int ordinal) : super(name, ordinal); | 590 const AnalysisService(String name, int ordinal) : super(name, ordinal); |
| 577 } | 591 } |
| 578 | 592 |
| 579 | 593 |
| 580 /** | |
| 581 * Instances of [ContextDirectory] represents a [Folder] associated with an | |
| 582 * analysis context. The folder may or may not contain a Pub `pubspec.yaml`. | |
| 583 * | |
| 584 * TODO(scheglov) implement complete projects/contexts semantics. | |
| 585 * | |
| 586 * This class is intentionally simplified to serve as a base to start working | |
| 587 * on services while work on complete semantics is being done in parallel. | |
| 588 */ | |
| 589 class ContextDirectory { | |
| 590 /** | |
| 591 * The root [ResourceProvider] of this [ContextDirectory]. | |
| 592 */ | |
| 593 final ResourceProvider _resourceProvider; | |
| 594 | |
| 595 /** | |
| 596 * The root [Folder] of this [ContextDirectory]. | |
| 597 */ | |
| 598 final Folder _folder; | |
| 599 | |
| 600 /** | |
| 601 * The [AnalysisContext] of this [_folder]. | |
| 602 */ | |
| 603 AnalysisContext _context; | |
| 604 | |
| 605 ContextDirectory(DartSdk sdk, this._resourceProvider, this._folder, | |
| 606 Map<String, List<Folder>> packageMap) { | |
| 607 // create AnalysisContext | |
| 608 _context = AnalysisEngine.instance.createAnalysisContext(); | |
| 609 // TODO(scheglov) replace FileUriResolver with an Resource based resolver | |
| 610 List<UriResolver> resolvers = <UriResolver>[new DartUriResolver(sdk), | |
| 611 new ResourceUriResolver(_resourceProvider), | |
| 612 ]; | |
| 613 if (packageMap != null) { | |
| 614 resolvers.add(new PackageMapUriResolver(_resourceProvider, packageMap)); | |
| 615 } | |
| 616 _context.sourceFactory = new SourceFactory(resolvers); | |
| 617 } | |
| 618 | |
| 619 /** | |
| 620 * Return the [AnalysisContext] of this folder. | |
| 621 */ | |
| 622 AnalysisContext get context => _context; | |
| 623 } | |
| 624 | |
| 625 typedef void OptionUpdater(AnalysisOptionsImpl options); | 594 typedef void OptionUpdater(AnalysisOptionsImpl options); |
| 626 | 595 |
| 627 /** | 596 /** |
| 628 * An enumeration of the services provided by the server domain. | 597 * An enumeration of the services provided by the server domain. |
| 629 */ | 598 */ |
| 630 class ServerService extends Enum2<ServerService> { | 599 class ServerService extends Enum2<ServerService> { |
| 631 static const ServerService STATUS = const ServerService('STATUS', 0); | 600 static const ServerService STATUS = const ServerService('STATUS', 0); |
| 632 | 601 |
| 633 static const List<ServerService> VALUES = const [STATUS]; | 602 static const List<ServerService> VALUES = const [STATUS]; |
| 634 | 603 |
| 635 const ServerService(String name, int ordinal) : super(name, ordinal); | 604 const ServerService(String name, int ordinal) : super(name, ordinal); |
| 636 } | 605 } |
| OLD | NEW |