| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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.src.single_context_manager; | 5 library analysis_server.src.single_context_manager; |
| 6 | 6 |
| 7 import 'dart:core' hide Resource; | 7 import 'dart:core' hide Resource; |
| 8 import 'dart:math' as math; | 8 import 'dart:math' as math; |
| 9 | 9 |
| 10 import 'package:analysis_server/src/context_manager.dart'; | 10 import 'package:analysis_server/src/context_manager.dart'; |
| 11 import 'package:analyzer/file_system/file_system.dart'; | 11 import 'package:analyzer/file_system/file_system.dart'; |
| 12 import 'package:analyzer/plugin/resolver_provider.dart'; | |
| 13 import 'package:analyzer/source/path_filter.dart'; | 12 import 'package:analyzer/source/path_filter.dart'; |
| 14 import 'package:analyzer/src/generated/engine.dart'; | 13 import 'package:analyzer/src/generated/engine.dart'; |
| 15 import 'package:analyzer/src/generated/sdk.dart'; | 14 import 'package:analyzer/src/generated/sdk.dart'; |
| 16 import 'package:analyzer/src/generated/source.dart'; | 15 import 'package:analyzer/src/generated/source.dart'; |
| 17 import 'package:analyzer/src/util/glob.dart'; | 16 import 'package:analyzer/src/util/glob.dart'; |
| 18 import 'package:path/path.dart' as path; | 17 import 'package:path/path.dart' as path; |
| 19 | 18 |
| 20 /** | 19 /** |
| 20 * A function that will return a [UriResolver] that can be used to resolve |
| 21 * `package:` URIs in [SingleContextManager]. |
| 22 */ |
| 23 typedef UriResolver PackageResolverProvider(); |
| 24 |
| 25 /** |
| 21 * Implementation of [ContextManager] that supports only one [AnalysisContext]. | 26 * Implementation of [ContextManager] that supports only one [AnalysisContext]. |
| 22 * So, sources from all analysis roots are added to this single context. All | 27 * So, sources from all analysis roots are added to this single context. All |
| 23 * features that could otherwise cause creating additional contexts, such as | 28 * features that could otherwise cause creating additional contexts, such as |
| 24 * presence of `pubspec.yaml` or `.packages` files, or `.analysis_options` files | 29 * presence of `pubspec.yaml` or `.packages` files, or `.analysis_options` files |
| 25 * are ignored. | 30 * are ignored. |
| 26 */ | 31 */ |
| 27 class SingleContextManager implements ContextManager { | 32 class SingleContextManager implements ContextManager { |
| 28 /** | 33 /** |
| 29 * The [ResourceProvider] using which paths are converted into [Resource]s. | 34 * The [ResourceProvider] using which paths are converted into [Resource]s. |
| 30 */ | 35 */ |
| 31 final ResourceProvider resourceProvider; | 36 final ResourceProvider resourceProvider; |
| 32 | 37 |
| 33 /** | 38 /** |
| 34 * The manager used to access the SDK that should be associated with a | 39 * The manager used to access the SDK that should be associated with a |
| 35 * particular context. | 40 * particular context. |
| 36 */ | 41 */ |
| 37 final DartSdkManager sdkManager; | 42 final DartSdkManager sdkManager; |
| 38 | 43 |
| 39 /** | 44 /** |
| 40 * A function that will return a [UriResolver] that can be used to resolve | 45 * A function that will return a [UriResolver] that can be used to resolve |
| 41 * `package:` URI's within a given folder, or `null` if we should fall back | 46 * `package:` URIs. |
| 42 * to the standard URI resolver. | |
| 43 */ | 47 */ |
| 44 final ResolverProvider packageResolverProvider; | 48 final PackageResolverProvider packageResolverProvider; |
| 45 | 49 |
| 46 /** | 50 /** |
| 47 * A list of the globs used to determine which files should be analyzed. | 51 * A list of the globs used to determine which files should be analyzed. |
| 48 */ | 52 */ |
| 49 final List<Glob> analyzedFilesGlobs; | 53 final List<Glob> analyzedFilesGlobs; |
| 50 | 54 |
| 51 /** | 55 /** |
| 52 * The list of included paths (folders and files) most recently passed to | 56 * The list of included paths (folders and files) most recently passed to |
| 53 * [setRoots]. | 57 * [setRoots]. |
| 54 */ | 58 */ |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 142 } | 146 } |
| 143 } | 147 } |
| 144 | 148 |
| 145 @override | 149 @override |
| 146 void setRoots(List<String> includedPaths, List<String> excludedPaths, | 150 void setRoots(List<String> includedPaths, List<String> excludedPaths, |
| 147 Map<String, String> packageRoots) { | 151 Map<String, String> packageRoots) { |
| 148 includedPaths = _nonOverlappingPaths(includedPaths); | 152 includedPaths = _nonOverlappingPaths(includedPaths); |
| 149 excludedPaths = _nonOverlappingPaths(excludedPaths); | 153 excludedPaths = _nonOverlappingPaths(excludedPaths); |
| 150 this.packageRoots = packageRoots; | 154 this.packageRoots = packageRoots; |
| 151 _updateNormalizedPackageRoots(); | 155 _updateNormalizedPackageRoots(); |
| 156 // Update context path. |
| 157 { |
| 158 String contextPath = _commonPrefix(includedPaths); |
| 159 Folder contextFolder = resourceProvider.getFolder(contextPath); |
| 160 if (contextFolder != this.contextFolder) { |
| 161 if (context != null) { |
| 162 callbacks.moveContext(this.contextFolder, contextFolder); |
| 163 } |
| 164 this.contextFolder = contextFolder; |
| 165 // TODO(scheglov) watch for changes in `contextFolder` |
| 166 } |
| 167 } |
| 152 if (context == null) { | 168 if (context == null) { |
| 153 String contextPath = _commonPrefix(includedPaths); | 169 UriResolver packageResolver = packageResolverProvider(); |
| 154 contextFolder = resourceProvider.getFolder(contextPath); | 170 context = callbacks.addContext(contextFolder, new AnalysisOptionsImpl(), |
| 155 // TODO(scheglov) watch for changes in `contextFolder` | 171 new CustomPackageResolverDisposition(packageResolver)); |
| 156 pathFilter = new PathFilter( | |
| 157 contextFolder.path, null, resourceProvider.pathContext); | |
| 158 AnalysisOptions options = new AnalysisOptionsImpl(); | |
| 159 FolderDisposition disposition = new CustomPackageResolverDisposition( | |
| 160 packageResolverProvider(contextFolder)); | |
| 161 context = callbacks.addContext(contextFolder, options, disposition); | |
| 162 ChangeSet changeSet = | 172 ChangeSet changeSet = |
| 163 _buildChangeSet(added: _includedFiles(includedPaths, excludedPaths)); | 173 _buildChangeSet(added: _includedFiles(includedPaths, excludedPaths)); |
| 164 callbacks.applyChangesToContext(contextFolder, changeSet); | 174 callbacks.applyChangesToContext(contextFolder, changeSet); |
| 165 } else { | 175 } else { |
| 166 // TODO(scheglov) in general 'contextFolder' may be different now | |
| 167 // TODO(brianwilkerson) Optimize this. | 176 // TODO(brianwilkerson) Optimize this. |
| 168 List<File> oldFiles = | 177 List<File> oldFiles = |
| 169 _includedFiles(this.includedPaths, this.excludedPaths); | 178 _includedFiles(this.includedPaths, this.excludedPaths); |
| 170 List<File> newFiles = _includedFiles(includedPaths, excludedPaths); | 179 List<File> newFiles = _includedFiles(includedPaths, excludedPaths); |
| 171 ChangeSet changeSet = _buildChangeSet( | 180 ChangeSet changeSet = _buildChangeSet( |
| 172 added: _diff(newFiles, oldFiles), removed: _diff(oldFiles, newFiles)); | 181 added: _diff(newFiles, oldFiles), removed: _diff(oldFiles, newFiles)); |
| 173 callbacks.applyChangesToContext(contextFolder, changeSet); | 182 callbacks.applyChangesToContext(contextFolder, changeSet); |
| 174 } | 183 } |
| 175 this.includedPaths = includedPaths; | 184 this.includedPaths = includedPaths; |
| 176 this.excludedPaths = excludedPaths; | 185 this.excludedPaths = excludedPaths; |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 279 } | 288 } |
| 280 return max; | 289 return max; |
| 281 } | 290 } |
| 282 | 291 |
| 283 static String _commonPrefix(List<String> paths) { | 292 static String _commonPrefix(List<String> paths) { |
| 284 if (paths.isEmpty) { | 293 if (paths.isEmpty) { |
| 285 return ''; | 294 return ''; |
| 286 } | 295 } |
| 287 List<String> left = path.split(paths[0]); | 296 List<String> left = path.split(paths[0]); |
| 288 int count = left.length; | 297 int count = left.length; |
| 289 for (int i = 0; i < paths.length; i++) { | 298 for (int i = 1; i < paths.length; i++) { |
| 290 List<String> right = path.split(paths[0]); | 299 List<String> right = path.split(paths[i]); |
| 291 count = _commonComponents(left, count, right); | 300 count = _commonComponents(left, count, right); |
| 292 } | 301 } |
| 293 return path.joinAll(left); | 302 return path.joinAll(left.sublist(0, count)); |
| 294 } | 303 } |
| 295 | 304 |
| 296 /** | 305 /** |
| 297 * Return a list of all the files in the [left] that are not in the [right]. | 306 * Return a list of all the files in the [left] that are not in the [right]. |
| 298 */ | 307 */ |
| 299 static List<File> _diff(List<File> left, List<File> right) { | 308 static List<File> _diff(List<File> left, List<File> right) { |
| 300 List<File> diff = new List.from(left); | 309 List<File> diff = new List.from(left); |
| 301 for (File file in right) { | 310 for (File file in right) { |
| 302 diff.remove(file); | 311 diff.remove(file); |
| 303 } | 312 } |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 for (int j = 0; j < i; j++) { | 366 for (int j = 0; j < i; j++) { |
| 358 if (_isEqualOrWithin(path, sortedPaths[j])) { | 367 if (_isEqualOrWithin(path, sortedPaths[j])) { |
| 359 sortedPaths.removeAt(i); | 368 sortedPaths.removeAt(i); |
| 360 break; | 369 break; |
| 361 } | 370 } |
| 362 } | 371 } |
| 363 } | 372 } |
| 364 return sortedPaths; | 373 return sortedPaths; |
| 365 } | 374 } |
| 366 } | 375 } |
| OLD | NEW |