| 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 context.directory.manager; | 5 library context.directory.manager; |
| 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 const String PUBSPEC_NAME = 'pubspec.yaml'; | 30 const String PUBSPEC_NAME = 'pubspec.yaml'; |
| 31 | 31 |
| 32 | 32 |
| 33 /** | 33 /** |
| 34 * Class that maintains a mapping from included/excluded paths to a set of | 34 * Class that maintains a mapping from included/excluded paths to a set of |
| 35 * folders that should correspond to analysis contexts. | 35 * folders that should correspond to analysis contexts. |
| 36 */ | 36 */ |
| 37 abstract class ContextManager { | 37 abstract class ContextManager { |
| 38 /** | 38 /** |
| 39 * The name of the `lib` directory. |
| 40 */ |
| 41 static const String LIB_DIR_NAME = 'lib'; |
| 42 |
| 43 /** |
| 39 * [_ContextInfo] object for each included directory in the most | 44 * [_ContextInfo] object for each included directory in the most |
| 40 * recent successful call to [setRoots]. | 45 * recent successful call to [setRoots]. |
| 41 */ | 46 */ |
| 42 Map<Folder, _ContextInfo> _contexts = new HashMap<Folder, _ContextInfo>(); | 47 Map<Folder, _ContextInfo> _contexts = new HashMap<Folder, _ContextInfo>(); |
| 43 | 48 |
| 44 /** | 49 /** |
| 45 * The [ResourceProvider] using which paths are converted into [Resource]s. | 50 * The [ResourceProvider] using which paths are converted into [Resource]s. |
| 46 */ | 51 */ |
| 47 final ResourceProvider resourceProvider; | 52 final ResourceProvider resourceProvider; |
| 48 | 53 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 78 * Provider which is used to determine the mapping from package name to | 83 * Provider which is used to determine the mapping from package name to |
| 79 * package folder. | 84 * package folder. |
| 80 */ | 85 */ |
| 81 final PackageMapProvider _packageMapProvider; | 86 final PackageMapProvider _packageMapProvider; |
| 82 | 87 |
| 83 ContextManager(this.resourceProvider, this._packageMapProvider) { | 88 ContextManager(this.resourceProvider, this._packageMapProvider) { |
| 84 pathContext = resourceProvider.pathContext; | 89 pathContext = resourceProvider.pathContext; |
| 85 } | 90 } |
| 86 | 91 |
| 87 /** | 92 /** |
| 88 * Called when a new context needs to be created. | 93 * Create and return a new analysis context. |
| 89 */ | 94 */ |
| 90 void addContext(Folder folder, UriResolver packageUriResolver); | 95 AnalysisContext addContext(Folder folder, UriResolver packageUriResolver); |
| 91 | 96 |
| 92 /** | 97 /** |
| 93 * Called when the set of files associated with a context have changed (or | 98 * Called when the set of files associated with a context have changed (or |
| 94 * some of those files have been modified). [changeSet] is the set of | 99 * some of those files have been modified). [changeSet] is the set of |
| 95 * changes that need to be applied to the context. | 100 * changes that need to be applied to the context. |
| 96 */ | 101 */ |
| 97 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet); | 102 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet); |
| 98 | 103 |
| 99 /** | 104 /** |
| 100 * We are about to start computing the package map. | 105 * We are about to start computing the package map. |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 continue; | 280 continue; |
| 276 } | 281 } |
| 277 _addPreviouslyExcludedSources(info, changeSet, child, oldExcludedPaths); | 282 _addPreviouslyExcludedSources(info, changeSet, child, oldExcludedPaths); |
| 278 } | 283 } |
| 279 } | 284 } |
| 280 } | 285 } |
| 281 | 286 |
| 282 /** | 287 /** |
| 283 * Resursively adds all Dart and HTML files to the [changeSet]. | 288 * Resursively adds all Dart and HTML files to the [changeSet]. |
| 284 */ | 289 */ |
| 285 void _addSourceFiles(ChangeSet changeSet, Folder folder, _ContextInfo info) { | 290 void _addSourceFiles(ChangeSet changeSet, Folder folder, _ContextInfo info, |
| 291 bool pubspecExists, bool createPackageUri) { |
| 286 if (info.excludesResource(folder) || folder.shortName.startsWith('.')) { | 292 if (info.excludesResource(folder) || folder.shortName.startsWith('.')) { |
| 287 return; | 293 return; |
| 288 } | 294 } |
| 289 List<Resource> children = folder.getChildren(); | 295 List<Resource> children = folder.getChildren(); |
| 290 for (Resource child in children) { | 296 for (Resource child in children) { |
| 291 String path = child.path; | 297 String path = child.path; |
| 292 // ignore excluded files or folders | 298 // ignore excluded files or folders |
| 293 if (_isExcluded(path)) { | 299 if (_isExcluded(path)) { |
| 294 continue; | 300 continue; |
| 295 } | 301 } |
| 296 // add files, recurse into folders | 302 // add files, recurse into folders |
| 297 if (child is File) { | 303 if (child is File) { |
| 298 if (_shouldFileBeAnalyzed(child)) { | 304 if (_shouldFileBeAnalyzed(child)) { |
| 299 Source source = child.createSource(); | 305 Source source = child.createSource(); |
| 306 if (createPackageUri) { |
| 307 String packagePath = info.folder.path; |
| 308 String packageName = |
| 309 resourceProvider.pathContext.basename(packagePath); |
| 310 String libPath = |
| 311 resourceProvider.pathContext.join(packagePath, LIB_DIR_NAME); |
| 312 String relPath = source.fullName.substring(libPath.length); |
| 313 Uri uri = |
| 314 Uri.parse('${PackageMapUriResolver.PACKAGE_SCHEME}:$packageName$
relPath'); |
| 315 source = child.createSource(uri); |
| 316 } |
| 300 changeSet.addedSource(source); | 317 changeSet.addedSource(source); |
| 301 info.sources[path] = source; | 318 info.sources[path] = source; |
| 302 } | 319 } |
| 303 } else if (child is Folder) { | 320 } else if (child is Folder) { |
| 304 if (child.shortName == PACKAGES_NAME) { | 321 String shortName = child.shortName; |
| 322 if (shortName == PACKAGES_NAME) { |
| 305 continue; | 323 continue; |
| 306 } | 324 } |
| 307 _addSourceFiles(changeSet, child, info); | 325 if (pubspecExists && |
| 326 !createPackageUri && |
| 327 shortName == LIB_DIR_NAME && |
| 328 child.parent == info.folder) { |
| 329 _addSourceFiles(changeSet, child, info, pubspecExists, true); |
| 330 } else { |
| 331 _addSourceFiles( |
| 332 changeSet, |
| 333 child, |
| 334 info, |
| 335 pubspecExists, |
| 336 createPackageUri); |
| 337 } |
| 308 } | 338 } |
| 309 } | 339 } |
| 310 } | 340 } |
| 311 | 341 |
| 312 /** | 342 /** |
| 313 * Compute the appropriate package URI resolver for [folder], and store | 343 * Compute the appropriate package URI resolver for [folder], and store |
| 314 * dependency information in [info]. Return `null` if no package map can | 344 * dependency information in [info]. Return `null` if no package map can |
| 315 * be computed. | 345 * be computed. |
| 316 */ | 346 */ |
| 317 UriResolver _computePackageUriResolver(Folder folder, _ContextInfo info) { | 347 UriResolver _computePackageUriResolver(Folder folder, _ContextInfo info) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 331 resourceProvider, | 361 resourceProvider, |
| 332 packageMapInfo.packageMap); | 362 packageMapInfo.packageMap); |
| 333 // TODO(paulberry): if any of the dependencies is outside of [folder], | 363 // TODO(paulberry): if any of the dependencies is outside of [folder], |
| 334 // we'll need to watch their parent folders as well. | 364 // we'll need to watch their parent folders as well. |
| 335 } | 365 } |
| 336 } | 366 } |
| 337 | 367 |
| 338 /** | 368 /** |
| 339 * Create a new empty context associated with [folder]. | 369 * Create a new empty context associated with [folder]. |
| 340 */ | 370 */ |
| 341 _ContextInfo _createContext(Folder folder, List<_ContextInfo> children) { | 371 _ContextInfo _createContext(Folder folder, File pubspecFile, |
| 342 _ContextInfo info = | 372 List<_ContextInfo> children) { |
| 343 new _ContextInfo(folder, children, normalizedPackageRoots[folder.path]); | 373 _ContextInfo info = new _ContextInfo( |
| 374 folder, |
| 375 pubspecFile, |
| 376 children, |
| 377 normalizedPackageRoots[folder.path]); |
| 344 _contexts[folder] = info; | 378 _contexts[folder] = info; |
| 345 info.changeSubscription = folder.changes.listen((WatchEvent event) { | 379 info.changeSubscription = folder.changes.listen((WatchEvent event) { |
| 346 _handleWatchEvent(folder, info, event); | 380 _handleWatchEvent(folder, info, event); |
| 347 }); | 381 }); |
| 348 UriResolver packageUriResolver = _computePackageUriResolver(folder, info); | 382 UriResolver packageUriResolver = _computePackageUriResolver(folder, info); |
| 349 addContext(folder, packageUriResolver); | 383 info.context = addContext(folder, packageUriResolver); |
| 350 return info; | 384 return info; |
| 351 } | 385 } |
| 352 | 386 |
| 353 /** | 387 /** |
| 354 * Creates a new context associated with [folder]. | 388 * Creates a new context associated with [folder]. |
| 355 * | 389 * |
| 356 * If there are subfolders with 'pubspec.yaml' files, separate contexts | 390 * If there are subfolders with 'pubspec.yaml' files, separate contexts |
| 357 * are created for them, and excluded from the context associated with | 391 * are created for them, and excluded from the context associated with |
| 358 * [folder]. | 392 * [folder]. |
| 359 * | 393 * |
| 360 * If [folder] itself contains a 'pubspec.yaml' file, subfolders are ignored. | 394 * If [folder] itself contains a 'pubspec.yaml' file, subfolders are ignored. |
| 361 * | 395 * |
| 362 * If [withPubspecOnly] is `true`, a context will be created only if there | 396 * If [withPubspecOnly] is `true`, a context will be created only if there |
| 363 * is a 'pubspec.yaml' file in [folder]. | 397 * is a 'pubspec.yaml' file in [folder]. |
| 364 * | 398 * |
| 365 * Returns create pubspec-based contexts. | 399 * Returns create pubspec-based contexts. |
| 366 */ | 400 */ |
| 367 List<_ContextInfo> _createContexts(Folder folder, bool withPubspecOnly) { | 401 List<_ContextInfo> _createContexts(Folder folder, bool withPubspecOnly) { |
| 368 // check if there is a pubspec in the folder | 402 // check whether there is a pubspec in the folder |
| 369 { | 403 File pubspecFile = folder.getChild(PUBSPEC_NAME); |
| 370 File pubspecFile = folder.getChild(PUBSPEC_NAME); | 404 bool pubspecExists = pubspecFile.exists; |
| 371 if (pubspecFile.exists) { | 405 if (pubspecExists) { |
| 372 _ContextInfo info = _createContextWithSources(folder, <_ContextInfo>[]); | 406 _ContextInfo info = _createContextWithSources( |
| 373 return [info]; | 407 folder, |
| 374 } | 408 pubspecFile, |
| 409 pubspecExists, |
| 410 <_ContextInfo>[]); |
| 411 return [info]; |
| 375 } | 412 } |
| 376 // try to find subfolders with pubspec files | 413 // try to find subfolders with pubspec files |
| 377 List<_ContextInfo> children = <_ContextInfo>[]; | 414 List<_ContextInfo> children = <_ContextInfo>[]; |
| 378 for (Resource child in folder.getChildren()) { | 415 for (Resource child in folder.getChildren()) { |
| 379 if (child is Folder) { | 416 if (child is Folder) { |
| 380 List<_ContextInfo> childContexts = _createContexts(child, true); | 417 List<_ContextInfo> childContexts = _createContexts(child, true); |
| 381 children.addAll(childContexts); | 418 children.addAll(childContexts); |
| 382 } | 419 } |
| 383 } | 420 } |
| 384 // no pubspec, done | 421 // no pubspec, done |
| 385 if (withPubspecOnly) { | 422 if (withPubspecOnly) { |
| 386 return children; | 423 return children; |
| 387 } | 424 } |
| 388 // OK, create a context without a pubspec | 425 // OK, create a context without a pubspec |
| 389 _createContextWithSources(folder, children); | 426 _createContextWithSources(folder, pubspecFile, pubspecExists, children); |
| 390 return children; | 427 return children; |
| 391 } | 428 } |
| 392 | 429 |
| 393 /** | 430 /** |
| 394 * Create a new context associated with [folder] and fills its with sources. | 431 * Create a new context associated with the given [folder]. The [pubspecFile] |
| 432 * is the `pubspec.yaml` file contained in the folder, and [pubspecExists] is |
| 433 * `true` if the file exists. Add any sources that are not included in one of |
| 434 * the [children] to the context. |
| 395 */ | 435 */ |
| 396 _ContextInfo _createContextWithSources(Folder folder, | 436 _ContextInfo _createContextWithSources(Folder folder, File pubspecFile, |
| 397 List<_ContextInfo> children) { | 437 bool pubspecExists, List<_ContextInfo> children) { |
| 398 _ContextInfo info = _createContext(folder, children); | 438 _ContextInfo info = _createContext(folder, pubspecFile, children); |
| 399 ChangeSet changeSet = new ChangeSet(); | 439 ChangeSet changeSet = new ChangeSet(); |
| 400 _addSourceFiles(changeSet, folder, info); | 440 _addSourceFiles(changeSet, folder, info, pubspecExists, false); |
| 401 applyChangesToContext(folder, changeSet); | 441 applyChangesToContext(folder, changeSet); |
| 402 return info; | 442 return info; |
| 403 } | 443 } |
| 404 | 444 |
| 405 /** | 445 /** |
| 406 * Clean up and destroy the context associated with the given folder. | 446 * Clean up and destroy the context associated with the given folder. |
| 407 */ | 447 */ |
| 408 void _destroyContext(Folder folder) { | 448 void _destroyContext(Folder folder) { |
| 409 _contexts[folder].changeSubscription.cancel(); | 449 _contexts[folder].changeSubscription.cancel(); |
| 410 _contexts.remove(folder); | 450 _contexts.remove(folder); |
| 411 removeContext(folder); | 451 removeContext(folder); |
| 412 } | 452 } |
| 413 | 453 |
| 414 /** | 454 /** |
| 415 * Extract a new [pubspecFile]-based context from [oldInfo]. | 455 * Extract a new [pubspecFile]-based context from [oldInfo]. |
| 416 */ | 456 */ |
| 417 void _extractContext(_ContextInfo oldInfo, File pubspecFile) { | 457 void _extractContext(_ContextInfo oldInfo, File pubspecFile) { |
| 418 Folder newFolder = pubspecFile.parent; | 458 Folder newFolder = pubspecFile.parent; |
| 419 _ContextInfo newInfo = _createContext(newFolder, []); | 459 _ContextInfo newInfo = _createContext(newFolder, pubspecFile, []); |
| 420 newInfo.parent = oldInfo; | 460 newInfo.parent = oldInfo; |
| 421 // prepare sources to extract | 461 // prepare sources to extract |
| 422 Map<String, Source> extractedSources = new HashMap<String, Source>(); | 462 Map<String, Source> extractedSources = new HashMap<String, Source>(); |
| 423 oldInfo.sources.forEach((path, source) { | 463 oldInfo.sources.forEach((path, source) { |
| 424 if (newFolder.contains(path)) { | 464 if (newFolder.contains(path)) { |
| 425 extractedSources[path] = source; | 465 extractedSources[path] = source; |
| 426 } | 466 } |
| 427 }); | 467 }); |
| 428 // update new context | 468 // update new context |
| 429 { | 469 { |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 622 */ | 662 */ |
| 623 String pubspecPath; | 663 String pubspecPath; |
| 624 | 664 |
| 625 /** | 665 /** |
| 626 * Stream subscription we are using to watch the context's directory for | 666 * Stream subscription we are using to watch the context's directory for |
| 627 * changes. | 667 * changes. |
| 628 */ | 668 */ |
| 629 StreamSubscription<WatchEvent> changeSubscription; | 669 StreamSubscription<WatchEvent> changeSubscription; |
| 630 | 670 |
| 631 /** | 671 /** |
| 672 * The analysis context that was created for the [folder]. |
| 673 */ |
| 674 AnalysisContext context; |
| 675 |
| 676 /** |
| 632 * Map from full path to the [Source] object, for each source that has been | 677 * Map from full path to the [Source] object, for each source that has been |
| 633 * added to the context. | 678 * added to the context. |
| 634 */ | 679 */ |
| 635 Map<String, Source> sources = new HashMap<String, Source>(); | 680 Map<String, Source> sources = new HashMap<String, Source>(); |
| 636 | 681 |
| 637 /** | 682 /** |
| 638 * Dependencies of the context's package map. | 683 * Dependencies of the context's package map. |
| 639 * If any of these files changes, the package map needs to be recomputed. | 684 * If any of these files changes, the package map needs to be recomputed. |
| 640 */ | 685 */ |
| 641 Set<String> packageMapDependencies; | 686 Set<String> packageMapDependencies; |
| 642 | 687 |
| 643 _ContextInfo(this.folder, this.children, this.packageRoot) { | 688 _ContextInfo(this.folder, File pubspecFile, this.children, this.packageRoot) { |
| 644 pubspecPath = folder.getChild(PUBSPEC_NAME).path; | 689 pubspecPath = pubspecFile.path; |
| 645 for (_ContextInfo child in children) { | 690 for (_ContextInfo child in children) { |
| 646 child.parent = this; | 691 child.parent = this; |
| 647 } | 692 } |
| 648 } | 693 } |
| 649 | 694 |
| 650 /** | 695 /** |
| 651 * Returns `true` if this context is root folder based. | 696 * Returns `true` if this context is root folder based. |
| 652 */ | 697 */ |
| 653 bool get isRoot => parent == null; | 698 bool get isRoot => parent == null; |
| 654 | 699 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 668 return excludes(resource.path); | 713 return excludes(resource.path); |
| 669 } | 714 } |
| 670 | 715 |
| 671 /** | 716 /** |
| 672 * Returns `true` if [path] is the pubspec file of this context. | 717 * Returns `true` if [path] is the pubspec file of this context. |
| 673 */ | 718 */ |
| 674 bool isPubspec(String path) { | 719 bool isPubspec(String path) { |
| 675 return path == pubspecPath; | 720 return path == pubspecPath; |
| 676 } | 721 } |
| 677 } | 722 } |
| OLD | NEW |