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 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 import 'dart:convert'; | |
| 9 import 'dart:core' hide Resource; | 10 import 'dart:core' hide Resource; |
| 10 | 11 |
| 11 import 'package:analysis_server/src/analysis_server.dart'; | 12 import 'package:analysis_server/src/analysis_server.dart'; |
| 12 import 'package:analysis_server/src/source/optimizing_pub_package_map_provider.d art'; | 13 import 'package:analysis_server/src/source/optimizing_pub_package_map_provider.d art'; |
| 13 import 'package:analysis_server/uri/resolver_provider.dart'; | 14 import 'package:analysis_server/uri/resolver_provider.dart'; |
| 14 import 'package:analyzer/file_system/file_system.dart'; | 15 import 'package:analyzer/file_system/file_system.dart'; |
| 15 import 'package:analyzer/instrumentation/instrumentation.dart'; | 16 import 'package:analyzer/instrumentation/instrumentation.dart'; |
| 16 import 'package:analyzer/source/package_map_resolver.dart'; | 17 import 'package:analyzer/source/package_map_resolver.dart'; |
| 17 import 'package:analyzer/source/path_filter.dart'; | 18 import 'package:analyzer/source/path_filter.dart'; |
| 18 import 'package:analyzer/src/generated/engine.dart'; | 19 import 'package:analyzer/src/generated/engine.dart'; |
| 19 import 'package:analyzer/src/generated/java_io.dart'; | 20 import 'package:analyzer/src/generated/java_io.dart'; |
| 20 import 'package:analyzer/src/generated/source.dart'; | 21 import 'package:analyzer/src/generated/source.dart'; |
| 21 import 'package:analyzer/src/generated/source_io.dart'; | 22 import 'package:analyzer/src/generated/source_io.dart'; |
| 23 import 'package:package_config/packages.dart'; | |
| 24 import 'package:package_config/packages_file.dart' as pkgfile show parse; | |
| 25 import 'package:package_config/src/packages_impl.dart' show MapPackages; | |
| 22 import 'package:path/path.dart' as pathos; | 26 import 'package:path/path.dart' as pathos; |
| 23 import 'package:watcher/watcher.dart'; | 27 import 'package:watcher/watcher.dart'; |
| 24 | 28 |
| 25 /** | 29 /** |
| 26 * Class that maintains a mapping from included/excluded paths to a set of | 30 * Class that maintains a mapping from included/excluded paths to a set of |
| 27 * folders that should correspond to analysis contexts. | 31 * folders that should correspond to analysis contexts. |
| 28 */ | 32 */ |
| 29 abstract class AbstractContextManager implements ContextManager { | 33 abstract class AbstractContextManager implements ContextManager { |
| 34 | |
| 35 /** | |
| 36 * Temporary flag to hide WIP .packages support. | |
|
Paul Berry
2015/07/17 20:49:13
It would be nice to mention the DEP number (DEP 5)
pquitslund
2015/07/20 20:50:22
Done.
| |
| 37 */ | |
| 38 static bool ENABLE_PACKAGESPEC_SUPPORT = false; | |
| 39 | |
| 30 /** | 40 /** |
| 31 * The name of the `lib` directory. | 41 * The name of the `lib` directory. |
| 32 */ | 42 */ |
| 33 static const String LIB_DIR_NAME = 'lib'; | 43 static const String LIB_DIR_NAME = 'lib'; |
| 34 | 44 |
| 35 /** | 45 /** |
| 36 * The name of `packages` folders. | 46 * The name of `packages` folders. |
| 37 */ | 47 */ |
| 38 static const String PACKAGES_NAME = 'packages'; | 48 static const String PACKAGES_NAME = 'packages'; |
| 39 | 49 |
| 40 /** | 50 /** |
| 41 * File name of pubspec files. | 51 * File name of pubspec files. |
| 42 */ | 52 */ |
| 43 static const String PUBSPEC_NAME = 'pubspec.yaml'; | 53 static const String PUBSPEC_NAME = 'pubspec.yaml'; |
| 44 | 54 |
| 45 /** | 55 /** |
| 56 * File name of package spec files. | |
| 57 */ | |
| 58 static const String PACKAGE_SPEC_NAME = '.packages'; | |
| 59 | |
| 60 /** | |
| 46 * [_ContextInfo] object for each included directory in the most | 61 * [_ContextInfo] object for each included directory in the most |
| 47 * recent successful call to [setRoots]. | 62 * recent successful call to [setRoots]. |
| 48 */ | 63 */ |
| 49 Map<Folder, _ContextInfo> _contexts = new HashMap<Folder, _ContextInfo>(); | 64 Map<Folder, _ContextInfo> _contexts = new HashMap<Folder, _ContextInfo>(); |
| 50 | 65 |
| 51 /** | 66 /** |
| 52 * The [ResourceProvider] using which paths are converted into [Resource]s. | 67 * The [ResourceProvider] using which paths are converted into [Resource]s. |
| 53 */ | 68 */ |
| 54 final ResourceProvider resourceProvider; | 69 final ResourceProvider resourceProvider; |
| 55 | 70 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 100 final InstrumentationService _instrumentationService; | 115 final InstrumentationService _instrumentationService; |
| 101 | 116 |
| 102 AbstractContextManager(this.resourceProvider, this.packageResolverProvider, | 117 AbstractContextManager(this.resourceProvider, this.packageResolverProvider, |
| 103 this._packageMapProvider, this._instrumentationService) { | 118 this._packageMapProvider, this._instrumentationService) { |
| 104 pathContext = resourceProvider.pathContext; | 119 pathContext = resourceProvider.pathContext; |
| 105 } | 120 } |
| 106 | 121 |
| 107 /** | 122 /** |
| 108 * Create and return a new analysis context. | 123 * Create and return a new analysis context. |
| 109 */ | 124 */ |
| 110 AnalysisContext addContext(Folder folder, UriResolver packageUriResolver); | 125 AnalysisContext addContext( |
| 126 Folder folder, UriResolver packageUriResolver, Packages packages); | |
| 111 | 127 |
| 112 /** | 128 /** |
| 113 * Called when the set of files associated with a context have changed (or | 129 * Called when the set of files associated with a context have changed (or |
| 114 * some of those files have been modified). [changeSet] is the set of | 130 * some of those files have been modified). [changeSet] is the set of |
| 115 * changes that need to be applied to the context. | 131 * changes that need to be applied to the context. |
| 116 */ | 132 */ |
| 117 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet); | 133 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet); |
| 118 | 134 |
| 119 /** | 135 /** |
| 120 * We are about to start computing the package map. | 136 * We are about to start computing the package map. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 157 return contexts; | 173 return contexts; |
| 158 } | 174 } |
| 159 | 175 |
| 160 /** | 176 /** |
| 161 * We have finished computing the package map. | 177 * We have finished computing the package map. |
| 162 */ | 178 */ |
| 163 void endComputePackageMap() { | 179 void endComputePackageMap() { |
| 164 // Do nothing. | 180 // Do nothing. |
| 165 } | 181 } |
| 166 | 182 |
| 167 // Sets the [ignorePatterns] for the context [folder]. | |
| 168 void setIgnorePatternsForContext(Folder folder, List<String> ignorePatterns) { | |
| 169 _ContextInfo info = _contexts[folder]; | |
| 170 if (info == null) { | |
| 171 return; | |
| 172 } | |
| 173 var pathFilter = info.pathFilter; | |
| 174 pathFilter.setIgnorePatterns(ignorePatterns); | |
| 175 } | |
| 176 | |
| 177 @override | 183 @override |
| 178 bool isInAnalysisRoot(String path) { | 184 bool isInAnalysisRoot(String path) { |
| 179 // check if excluded | 185 // check if excluded |
| 180 if (_isExcluded(path)) { | 186 if (_isExcluded(path)) { |
| 181 return false; | 187 return false; |
| 182 } | 188 } |
| 183 // check if in of the roots | 189 // check if in of the roots |
| 184 for (Folder root in _contexts.keys) { | 190 for (Folder root in _contexts.keys) { |
| 185 if (root.contains(path)) { | 191 if (root.contains(path)) { |
| 186 return true; | 192 return true; |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 208 | 214 |
| 209 // Rebuild contexts based on the data last sent to setRoots(). | 215 // Rebuild contexts based on the data last sent to setRoots(). |
| 210 setRoots(includedPaths, excludedPaths, packageRoots); | 216 setRoots(includedPaths, excludedPaths, packageRoots); |
| 211 } | 217 } |
| 212 | 218 |
| 213 /** | 219 /** |
| 214 * Remove the context associated with the given [folder]. | 220 * Remove the context associated with the given [folder]. |
| 215 */ | 221 */ |
| 216 void removeContext(Folder folder); | 222 void removeContext(Folder folder); |
| 217 | 223 |
| 224 /// Sets the [ignorePatterns] for the context [folder]. | |
| 225 void setIgnorePatternsForContext(Folder folder, List<String> ignorePatterns) { | |
| 226 _ContextInfo info = _contexts[folder]; | |
| 227 if (info == null) { | |
| 228 return; | |
| 229 } | |
| 230 var pathFilter = info.pathFilter; | |
| 231 pathFilter.setIgnorePatterns(ignorePatterns); | |
| 232 } | |
| 233 | |
| 218 @override | 234 @override |
| 219 void setRoots(List<String> includedPaths, List<String> excludedPaths, | 235 void setRoots(List<String> includedPaths, List<String> excludedPaths, |
| 220 Map<String, String> packageRoots) { | 236 Map<String, String> packageRoots) { |
| 221 this.packageRoots = packageRoots; | 237 this.packageRoots = packageRoots; |
| 222 | 238 |
| 223 // Normalize all package root sources by mapping them to folders on the | 239 // Normalize all package root sources by mapping them to folders on the |
| 224 // filesystem. Ignore any package root sources that aren't folders. | 240 // filesystem. Ignore any package root sources that aren't folders. |
| 225 normalizedPackageRoots = <String, String>{}; | 241 normalizedPackageRoots = <String, String>{}; |
| 226 packageRoots.forEach((String sourcePath, String targetPath) { | 242 packageRoots.forEach((String sourcePath, String targetPath) { |
| 227 Resource resource = resourceProvider.getResource(sourcePath); | 243 Resource resource = resourceProvider.getResource(sourcePath); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 302 | 318 |
| 303 /** | 319 /** |
| 304 * Return `true` if the given [file] should be analyzed. | 320 * Return `true` if the given [file] should be analyzed. |
| 305 */ | 321 */ |
| 306 bool shouldFileBeAnalyzed(File file); | 322 bool shouldFileBeAnalyzed(File file); |
| 307 | 323 |
| 308 /** | 324 /** |
| 309 * Called when the package map for a context has changed. | 325 * Called when the package map for a context has changed. |
| 310 */ | 326 */ |
| 311 void updateContextPackageUriResolver( | 327 void updateContextPackageUriResolver( |
| 312 Folder contextFolder, UriResolver packageUriResolver); | 328 Folder contextFolder, UriResolver packageUriResolver, Packages packages); |
| 313 | 329 |
| 314 /** | 330 /** |
| 315 * Resursively adds all Dart and HTML files to the [changeSet]. | 331 * Resursively adds all Dart and HTML files to the [changeSet]. |
| 316 */ | 332 */ |
| 317 void _addPreviouslyExcludedSources(_ContextInfo info, ChangeSet changeSet, | 333 void _addPreviouslyExcludedSources(_ContextInfo info, ChangeSet changeSet, |
| 318 Folder folder, List<String> oldExcludedPaths) { | 334 Folder folder, List<String> oldExcludedPaths) { |
| 319 if (info.excludesResource(folder)) { | 335 if (info.excludesResource(folder)) { |
| 320 return; | 336 return; |
| 321 } | 337 } |
| 322 List<Resource> children; | 338 List<Resource> children; |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 399 /** | 415 /** |
| 400 * Cancel all dependency subscriptions for the given context. | 416 * Cancel all dependency subscriptions for the given context. |
| 401 */ | 417 */ |
| 402 void _cancelDependencySubscriptions(_ContextInfo info) { | 418 void _cancelDependencySubscriptions(_ContextInfo info) { |
| 403 for (StreamSubscription<WatchEvent> s in info.dependencySubscriptions) { | 419 for (StreamSubscription<WatchEvent> s in info.dependencySubscriptions) { |
| 404 s.cancel(); | 420 s.cancel(); |
| 405 } | 421 } |
| 406 info.dependencySubscriptions.clear(); | 422 info.dependencySubscriptions.clear(); |
| 407 } | 423 } |
| 408 | 424 |
| 425 void _checkForPackagespecUpdate( | |
| 426 String path, _ContextInfo info, Folder folder) { | |
| 427 // Check to see if this is the .packages file for this context and if so, | |
| 428 // update the context's source factory. | |
| 429 if (pathContext.basename(path) == PACKAGE_SPEC_NAME && | |
| 430 info.isPathToPackageDescription(path)) { | |
| 431 File packagespec = resourceProvider.getFile(path); | |
| 432 if (packagespec.exists) { | |
| 433 Packages packages = _readPackagespec(packagespec); | |
| 434 if (packages != null) { | |
| 435 updateContextPackageUriResolver(folder, null, packages); | |
| 436 } | |
| 437 } | |
| 438 } | |
| 439 } | |
| 440 | |
| 409 /** | 441 /** |
| 410 * Compute the appropriate package URI resolver for [folder], and store | 442 * Compute the appropriate package URI resolver for [folder], and store |
| 411 * dependency information in [info]. Return `null` if no package map can | 443 * dependency information in [info]. Return `null` if no package map can |
| 412 * be computed. | 444 * be computed. |
| 413 */ | 445 */ |
| 414 UriResolver _computePackageUriResolver(Folder folder, _ContextInfo info) { | 446 UriResolver _computePackageUriResolver(Folder folder, _ContextInfo info) { |
| 415 _cancelDependencySubscriptions(info); | 447 _cancelDependencySubscriptions(info); |
| 416 if (info.packageRoot != null) { | 448 if (info.packageRoot != null) { |
| 417 info.packageMapInfo = null; | 449 info.packageMapInfo = null; |
| 418 JavaFile packagesDir = new JavaFile(info.packageRoot); | 450 JavaFile packagesDir = new JavaFile(info.packageRoot); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 479 resourceProvider, packageMapInfo.packageMap); | 511 resourceProvider, packageMapInfo.packageMap); |
| 480 // TODO(paulberry): if any of the dependencies is outside of [folder], | 512 // TODO(paulberry): if any of the dependencies is outside of [folder], |
| 481 // we'll need to watch their parent folders as well. | 513 // we'll need to watch their parent folders as well. |
| 482 } | 514 } |
| 483 } | 515 } |
| 484 | 516 |
| 485 /** | 517 /** |
| 486 * Create a new empty context associated with [folder]. | 518 * Create a new empty context associated with [folder]. |
| 487 */ | 519 */ |
| 488 _ContextInfo _createContext( | 520 _ContextInfo _createContext( |
| 489 Folder folder, File pubspecFile, List<_ContextInfo> children) { | 521 Folder folder, File packagespecFile, List<_ContextInfo> children) { |
| 490 _ContextInfo info = new _ContextInfo( | 522 _ContextInfo info = new _ContextInfo( |
| 491 folder, pubspecFile, children, normalizedPackageRoots[folder.path]); | 523 folder, packagespecFile, children, normalizedPackageRoots[folder.path]); |
| 492 _contexts[folder] = info; | 524 _contexts[folder] = info; |
| 493 info.changeSubscription = folder.changes.listen((WatchEvent event) { | 525 info.changeSubscription = folder.changes.listen((WatchEvent event) { |
| 494 _handleWatchEvent(folder, info, event); | 526 _handleWatchEvent(folder, info, event); |
| 495 }); | 527 }); |
| 496 try { | 528 try { |
| 497 UriResolver packageUriResolver = _computePackageUriResolver(folder, info); | 529 Packages packages; |
| 498 info.context = addContext(folder, packageUriResolver); | 530 UriResolver packageUriResolver; |
| 531 | |
| 532 if (ENABLE_PACKAGESPEC_SUPPORT) { | |
| 533 // Try .packages first. | |
| 534 if (pathos.basename(packagespecFile.path) == PACKAGE_SPEC_NAME) { | |
| 535 packages = _readPackagespec(packagespecFile); | |
| 536 } | |
| 537 } | |
| 538 | |
| 539 // Next resort to a package uri resolver. | |
| 540 if (packages == null) { | |
| 541 packageUriResolver = _computePackageUriResolver(folder, info); | |
| 542 } | |
| 543 | |
| 544 info.context = addContext(folder, packageUriResolver, packages); | |
| 499 info.context.name = folder.path; | 545 info.context.name = folder.path; |
| 500 } catch (_) { | 546 } catch (_) { |
| 501 info.changeSubscription.cancel(); | 547 info.changeSubscription.cancel(); |
| 502 rethrow; | 548 rethrow; |
| 503 } | 549 } |
| 504 return info; | 550 return info; |
| 505 } | 551 } |
| 506 | 552 |
| 507 /** | 553 /** |
| 508 * Potentially create a new context associated with the given [folder]. | 554 * Potentially create a new context associated with the given [folder]. |
| 509 * | 555 * |
| 510 * If there are subfolders with 'pubspec.yaml' files, separate contexts are | 556 * If there are subfolders with 'pubspec.yaml' files, separate contexts are |
| 511 * created for them and excluded from the context associated with the | 557 * created for them and excluded from the context associated with the |
| 512 * [folder]. | 558 * [folder]. |
| 513 * | 559 * |
| 514 * If [withPubspecOnly] is `true`, a context will be created only if there | 560 * If [withPackageSpecOnly] is `true`, a context will be created only if there |
| 515 * is a 'pubspec.yaml' file in the [folder]. | 561 * is a 'pubspec.yaml' or '.packages' file in the [folder]. |
| 516 * | 562 * |
| 517 * Returns create pubspec-based contexts. | 563 * Returns created contexts. |
| 518 */ | 564 */ |
| 519 List<_ContextInfo> _createContexts(Folder folder, bool withPubspecOnly) { | 565 List<_ContextInfo> _createContexts(Folder folder, bool withPackageSpecOnly) { |
| 520 // try to find subfolders with pubspec files | 566 // Try to find subfolders with pubspecs or .packages files. |
| 521 List<_ContextInfo> children = <_ContextInfo>[]; | 567 List<_ContextInfo> children = <_ContextInfo>[]; |
| 522 try { | 568 try { |
| 523 for (Resource child in folder.getChildren()) { | 569 for (Resource child in folder.getChildren()) { |
| 524 if (child is Folder) { | 570 if (child is Folder) { |
| 525 children.addAll(_createContexts(child, true)); | 571 children.addAll(_createContexts(child, true)); |
| 526 } | 572 } |
| 527 } | 573 } |
| 528 } on FileSystemException { | 574 } on FileSystemException { |
| 529 // The directory either doesn't exist or cannot be read. Either way, there | 575 // The directory either doesn't exist or cannot be read. Either way, there |
| 530 // are no subfolders that need to be added. | 576 // are no subfolders that need to be added. |
| 531 } | 577 } |
| 532 // check whether there is a pubspec in the folder | 578 |
| 533 File pubspecFile = folder.getChild(PUBSPEC_NAME); | 579 File packageSpec; |
| 534 if (pubspecFile.exists) { | 580 |
| 581 if (ENABLE_PACKAGESPEC_SUPPORT) { | |
| 582 // Start by looking for .packages. | |
| 583 packageSpec = folder.getChild(PACKAGE_SPEC_NAME); | |
| 584 } | |
| 585 | |
| 586 // Fall back to looking for a pubspec. | |
| 587 if (packageSpec == null || !packageSpec.exists) { | |
| 588 packageSpec = folder.getChild(PUBSPEC_NAME); | |
| 589 } | |
| 590 | |
| 591 if (packageSpec.exists) { | |
| 535 return <_ContextInfo>[ | 592 return <_ContextInfo>[ |
| 536 _createContextWithSources(folder, pubspecFile, children) | 593 _createContextWithSources(folder, packageSpec, children) |
| 537 ]; | 594 ]; |
| 538 } | 595 } |
| 539 // no pubspec, done | 596 // No packagespec? Done. |
| 540 if (withPubspecOnly) { | 597 if (withPackageSpecOnly) { |
| 541 return children; | 598 return children; |
| 542 } | 599 } |
| 543 // OK, create a context without a pubspec | 600 // OK, create a context without a packagespec. |
| 544 return <_ContextInfo>[ | 601 return <_ContextInfo>[ |
| 545 _createContextWithSources(folder, pubspecFile, children) | 602 _createContextWithSources(folder, packageSpec, children) |
| 546 ]; | 603 ]; |
| 547 } | 604 } |
| 548 | 605 |
| 549 /** | 606 /** |
| 550 * Create a new context associated with the given [folder]. The [pubspecFile] | 607 * Create a new context associated with the given [folder]. The [pubspecFile] |
| 551 * is the `pubspec.yaml` file contained in the folder. Add any sources that | 608 * is the `pubspec.yaml` file contained in the folder. Add any sources that |
| 552 * are not included in one of the [children] to the context. | 609 * are not included in one of the [children] to the context. |
| 553 */ | 610 */ |
| 554 _ContextInfo _createContextWithSources( | 611 _ContextInfo _createContextWithSources( |
| 555 Folder folder, File pubspecFile, List<_ContextInfo> children) { | 612 Folder folder, File pubspecFile, List<_ContextInfo> children) { |
| 556 _ContextInfo info = _createContext(folder, pubspecFile, children); | 613 _ContextInfo info = _createContext(folder, pubspecFile, children); |
| 557 ChangeSet changeSet = new ChangeSet(); | 614 ChangeSet changeSet = new ChangeSet(); |
| 558 _addSourceFiles(changeSet, folder, info); | 615 _addSourceFiles(changeSet, folder, info); |
| 559 applyChangesToContext(folder, changeSet); | 616 applyChangesToContext(folder, changeSet); |
| 560 return info; | 617 return info; |
| 561 } | 618 } |
| 562 | 619 |
| 563 /** | 620 /** |
| 564 * Clean up and destroy the context associated with the given folder. | 621 * Clean up and destroy the context associated with the given folder. |
| 565 */ | 622 */ |
| 566 void _destroyContext(Folder folder) { | 623 void _destroyContext(Folder folder) { |
| 567 _ContextInfo info = _contexts[folder]; | 624 _ContextInfo info = _contexts[folder]; |
| 568 info.changeSubscription.cancel(); | 625 info.changeSubscription.cancel(); |
| 569 _cancelDependencySubscriptions(info); | 626 _cancelDependencySubscriptions(info); |
| 570 removeContext(folder); | 627 removeContext(folder); |
| 571 _contexts.remove(folder); | 628 _contexts.remove(folder); |
| 572 } | 629 } |
| 573 | 630 |
| 574 /** | 631 /** |
| 575 * Extract a new [pubspecFile]-based context from [oldInfo]. | 632 * Extract a new [packagespecFile]-based context from [oldInfo]. |
| 576 */ | 633 */ |
| 577 void _extractContext(_ContextInfo oldInfo, File pubspecFile) { | 634 void _extractContext(_ContextInfo oldInfo, File packagespecFile) { |
| 578 Folder newFolder = pubspecFile.parent; | 635 Folder newFolder = packagespecFile.parent; |
| 579 _ContextInfo newInfo = _createContext(newFolder, pubspecFile, []); | 636 _ContextInfo newInfo = _createContext(newFolder, packagespecFile, []); |
| 580 newInfo.parent = oldInfo; | 637 newInfo.parent = oldInfo; |
| 581 // prepare sources to extract | 638 // prepare sources to extract |
| 582 Map<String, Source> extractedSources = new HashMap<String, Source>(); | 639 Map<String, Source> extractedSources = new HashMap<String, Source>(); |
| 583 oldInfo.sources.forEach((path, source) { | 640 oldInfo.sources.forEach((path, source) { |
| 584 if (newFolder.contains(path)) { | 641 if (newFolder.contains(path)) { |
| 585 extractedSources[path] = source; | 642 extractedSources[path] = source; |
| 586 } | 643 } |
| 587 }); | 644 }); |
| 588 // update new context | 645 // update new context |
| 589 { | 646 { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 623 } | 680 } |
| 624 if (info.ignored(path)) { | 681 if (info.ignored(path)) { |
| 625 return; | 682 return; |
| 626 } | 683 } |
| 627 // handle the change | 684 // handle the change |
| 628 switch (event.type) { | 685 switch (event.type) { |
| 629 case ChangeType.ADD: | 686 case ChangeType.ADD: |
| 630 if (_isInPackagesDir(path, folder)) { | 687 if (_isInPackagesDir(path, folder)) { |
| 631 return; | 688 return; |
| 632 } | 689 } |
| 690 | |
| 633 Resource resource = resourceProvider.getResource(path); | 691 Resource resource = resourceProvider.getResource(path); |
| 634 // pubspec was added in a sub-folder, extract a new context | 692 |
| 635 if (_isPubspec(path) && info.isRoot && !info.isPubspec(path)) { | 693 if (ENABLE_PACKAGESPEC_SUPPORT) { |
| 636 _extractContext(info, resource); | 694 String directoryPath = pathContext.dirname(path); |
| 637 return; | 695 |
| 696 // Check to see if we need to create a new context. | |
| 697 if (info.isRoot) { | |
| 698 | |
| 699 // Only create a new context if this is not the same directory | |
| 700 // described by our info object. | |
| 701 if (info.folder.path != directoryPath) { | |
| 702 if (_isPubspec(path)) { | |
| 703 // Check for a sibling .packages file. | |
| 704 if (!resourceProvider.getFile( | |
| 705 pathos.join(directoryPath, PACKAGE_SPEC_NAME)).exists) { | |
| 706 _extractContext(info, resource); | |
| 707 return; | |
| 708 } | |
| 709 } | |
| 710 if (_isPackagespec(path)) { | |
| 711 // Check for a sibling pubspec.yaml file. | |
| 712 if (!resourceProvider | |
| 713 .getFile(pathos.join(directoryPath, PUBSPEC_NAME)).exists) { | |
| 714 _extractContext(info, resource); | |
| 715 return; | |
| 716 } | |
| 717 } | |
| 718 } | |
| 719 } | |
| 720 } else { | |
| 721 // pubspec was added in a sub-folder, extract a new context | |
| 722 if (_isPubspec(path) && | |
| 723 info.isRoot && | |
| 724 !info.isPathToPackageDescription(path)) { | |
| 725 _extractContext(info, resource); | |
| 726 return; | |
| 727 } | |
| 638 } | 728 } |
| 729 | |
| 639 // If the file went away and was replaced by a folder before we | 730 // If the file went away and was replaced by a folder before we |
| 640 // had a chance to process the event, resource might be a Folder. In | 731 // had a chance to process the event, resource might be a Folder. In |
| 641 // that case don't add it. | 732 // that case don't add it. |
| 642 if (resource is File) { | 733 if (resource is File) { |
| 643 File file = resource; | 734 File file = resource; |
| 644 if (shouldFileBeAnalyzed(file)) { | 735 if (shouldFileBeAnalyzed(file)) { |
| 645 ChangeSet changeSet = new ChangeSet(); | 736 ChangeSet changeSet = new ChangeSet(); |
| 646 Source source = createSourceInContext(info.context, file); | 737 Source source = createSourceInContext(info.context, file); |
| 647 changeSet.addedSource(source); | 738 changeSet.addedSource(source); |
| 648 applyChangesToContext(folder, changeSet); | 739 applyChangesToContext(folder, changeSet); |
| 649 info.sources[path] = source; | 740 info.sources[path] = source; |
| 650 } | 741 } |
| 651 } | 742 } |
| 652 break; | 743 break; |
| 653 case ChangeType.REMOVE: | 744 case ChangeType.REMOVE: |
| 654 // pubspec was removed, merge the context into its parent | 745 |
| 655 if (info.isPubspec(path) && !info.isRoot) { | 746 // If package spec info is removed, check to see if we can merge context s. |
| 656 _mergeContext(info); | 747 // Note that it's important to verify that there is NEITHER a .packages nor a |
| 657 return; | 748 // lingering pubspec.yaml before merging. |
| 749 if (!info.isRoot) { | |
| 750 if (ENABLE_PACKAGESPEC_SUPPORT) { | |
| 751 String directoryPath = pathContext.dirname(path); | |
| 752 | |
| 753 // Only merge if this is the same directory described by our info ob ject. | |
| 754 if (info.folder.path == directoryPath) { | |
| 755 if (_isPubspec(path)) { | |
| 756 // Check for a sibling .packages file. | |
| 757 if (!resourceProvider.getFile( | |
| 758 pathos.join(directoryPath, PACKAGE_SPEC_NAME)).exists) { | |
| 759 _mergeContext(info); | |
| 760 return; | |
| 761 } | |
| 762 } | |
| 763 if (_isPackagespec(path)) { | |
| 764 // Check for a sibling pubspec.yaml file. | |
| 765 if (!resourceProvider | |
| 766 .getFile(pathos.join(directoryPath, PUBSPEC_NAME)).exists) { | |
| 767 _mergeContext(info); | |
| 768 return; | |
| 769 } | |
| 770 } | |
| 771 } | |
| 772 } else { | |
| 773 if (info.isPathToPackageDescription(path)) { | |
| 774 _mergeContext(info); | |
| 775 return; | |
| 776 } | |
| 777 } | |
| 658 } | 778 } |
| 779 | |
| 659 List<Source> sources = info.context.getSourcesWithFullName(path); | 780 List<Source> sources = info.context.getSourcesWithFullName(path); |
| 660 if (!sources.isEmpty) { | 781 if (!sources.isEmpty) { |
| 661 ChangeSet changeSet = new ChangeSet(); | 782 ChangeSet changeSet = new ChangeSet(); |
| 662 sources.forEach((Source source) { | 783 sources.forEach((Source source) { |
| 663 changeSet.removedSource(source); | 784 changeSet.removedSource(source); |
| 664 }); | 785 }); |
| 665 applyChangesToContext(folder, changeSet); | 786 applyChangesToContext(folder, changeSet); |
| 666 info.sources.remove(path); | 787 info.sources.remove(path); |
| 667 } | 788 } |
| 668 break; | 789 break; |
| 669 case ChangeType.MODIFY: | 790 case ChangeType.MODIFY: |
| 670 List<Source> sources = info.context.getSourcesWithFullName(path); | 791 List<Source> sources = info.context.getSourcesWithFullName(path); |
| 671 if (!sources.isEmpty) { | 792 if (!sources.isEmpty) { |
| 672 ChangeSet changeSet = new ChangeSet(); | 793 ChangeSet changeSet = new ChangeSet(); |
| 673 sources.forEach((Source source) { | 794 sources.forEach((Source source) { |
| 674 changeSet.changedSource(source); | 795 changeSet.changedSource(source); |
| 675 }); | 796 }); |
| 676 applyChangesToContext(folder, changeSet); | 797 applyChangesToContext(folder, changeSet); |
| 677 } | 798 } |
| 678 break; | 799 break; |
| 679 } | 800 } |
| 680 | 801 |
| 802 //TODO(pquitslund): find the right place for this | |
| 803 _checkForPackagespecUpdate(path, info, folder); | |
| 804 | |
| 681 if (info.packageMapInfo != null && | 805 if (info.packageMapInfo != null && |
| 682 info.packageMapInfo.isChangedDependency(path, resourceProvider)) { | 806 info.packageMapInfo.isChangedDependency(path, resourceProvider)) { |
| 683 _recomputePackageUriResolver(info); | 807 _recomputePackageUriResolver(info); |
| 684 } | 808 } |
| 685 } | 809 } |
| 686 | 810 |
| 687 /** | 811 /** |
| 688 * Returns `true` if the given [path] is excluded by [excludedPaths]. | 812 * Returns `true` if the given [path] is excluded by [excludedPaths]. |
| 689 */ | 813 */ |
| 690 bool _isExcluded(String path) { | 814 bool _isExcluded(String path) => _isExcludedBy(excludedPaths, path); |
| 691 return _isExcludedBy(excludedPaths, path); | |
| 692 } | |
| 693 | 815 |
| 694 /** | 816 /** |
| 695 * Returns `true` if the given [path] is excluded by [excludedPaths]. | 817 * Returns `true` if the given [path] is excluded by [excludedPaths]. |
| 696 */ | 818 */ |
| 697 bool _isExcludedBy(List<String> excludedPaths, String path) { | 819 bool _isExcludedBy(List<String> excludedPaths, String path) { |
| 698 return excludedPaths.any((excludedPath) { | 820 return excludedPaths.any((excludedPath) { |
| 699 if (pathContext.isWithin(excludedPath, path)) { | 821 if (pathContext.isWithin(excludedPath, path)) { |
| 700 return true; | 822 return true; |
| 701 } | 823 } |
| 702 return path == excludedPath; | 824 return path == excludedPath; |
| 703 }); | 825 }); |
| 704 } | 826 } |
| 705 | 827 |
| 706 /** | 828 /** |
| 707 * Determine if the path from [folder] to [path] contains a 'packages' | 829 * Determine if the path from [folder] to [path] contains a 'packages' |
| 708 * directory. | 830 * directory. |
| 709 */ | 831 */ |
| 710 bool _isInPackagesDir(String path, Folder folder) { | 832 bool _isInPackagesDir(String path, Folder folder) { |
| 711 String relativePath = pathContext.relative(path, from: folder.path); | 833 String relativePath = pathContext.relative(path, from: folder.path); |
| 712 List<String> pathParts = pathContext.split(relativePath); | 834 List<String> pathParts = pathContext.split(relativePath); |
| 713 return pathParts.contains(PACKAGES_NAME); | 835 return pathParts.contains(PACKAGES_NAME); |
| 714 } | 836 } |
| 715 | 837 |
| 716 /** | 838 bool _isPackagespec(String path) => |
| 717 * Returns `true` if the given absolute [path] is a pubspec file. | 839 pathContext.basename(path) == PACKAGE_SPEC_NAME; |
| 718 */ | 840 |
| 719 bool _isPubspec(String path) { | 841 bool _isPubspec(String path) => pathContext.basename(path) == PUBSPEC_NAME; |
| 720 return pathContext.basename(path) == PUBSPEC_NAME; | |
| 721 } | |
| 722 | 842 |
| 723 /** | 843 /** |
| 724 * Merges [info] context into its parent. | 844 * Merges [info] context into its parent. |
| 725 */ | 845 */ |
| 726 void _mergeContext(_ContextInfo info) { | 846 void _mergeContext(_ContextInfo info) { |
| 727 // destroy the context | 847 // destroy the context |
| 728 _destroyContext(info.folder); | 848 _destroyContext(info.folder); |
| 729 // add files to the parent context | 849 // add files to the parent context |
| 730 _ContextInfo parentInfo = info.parent; | 850 _ContextInfo parentInfo = info.parent; |
| 731 if (parentInfo != null) { | 851 if (parentInfo != null) { |
| 732 parentInfo.children.remove(info); | 852 parentInfo.children.remove(info); |
| 733 ChangeSet changeSet = new ChangeSet(); | 853 ChangeSet changeSet = new ChangeSet(); |
| 734 info.sources.forEach((path, source) { | 854 info.sources.forEach((path, source) { |
| 735 parentInfo.sources[path] = source; | 855 parentInfo.sources[path] = source; |
| 736 changeSet.addedSource(source); | 856 changeSet.addedSource(source); |
| 737 }); | 857 }); |
| 738 applyChangesToContext(parentInfo.folder, changeSet); | 858 applyChangesToContext(parentInfo.folder, changeSet); |
| 739 } | 859 } |
| 740 } | 860 } |
| 741 | 861 |
| 862 Packages _readPackagespec(File specFile) { | |
| 863 try { | |
| 864 String contents = specFile.readAsStringSync(); | |
| 865 Map<String, Uri> map = | |
| 866 pkgfile.parse(UTF8.encode(contents), new Uri.file(specFile.path)); | |
| 867 return new MapPackages(map); | |
| 868 } catch (_) { | |
| 869 //TODO(pquitslund): consider creating an error for the spec file. | |
| 870 return null; | |
| 871 } | |
| 872 } | |
| 873 | |
| 742 /** | 874 /** |
| 743 * Recompute the package URI resolver for the context described by [info], | 875 * Recompute the package URI resolver for the context described by [info], |
| 744 * and update the client appropriately. | 876 * and update the client appropriately. |
| 745 */ | 877 */ |
| 746 void _recomputePackageUriResolver(_ContextInfo info) { | 878 void _recomputePackageUriResolver(_ContextInfo info) { |
| 747 // TODO(paulberry): when computePackageMap is changed into an | 879 // TODO(paulberry): when computePackageMap is changed into an |
| 748 // asynchronous API call, we'll want to suspend analysis for this context | 880 // asynchronous API call, we'll want to suspend analysis for this context |
| 749 // while we're rerunning "pub list", since any analysis we complete while | 881 // while we're rerunning "pub list", since any analysis we complete while |
| 750 // "pub list" is in progress is just going to get thrown away anyhow. | 882 // "pub list" is in progress is just going to get thrown away anyhow. |
| 751 UriResolver packageUriResolver = | 883 UriResolver packageUriResolver = |
| 752 _computePackageUriResolver(info.folder, info); | 884 _computePackageUriResolver(info.folder, info); |
| 753 updateContextPackageUriResolver(info.folder, packageUriResolver); | 885 updateContextPackageUriResolver(info.folder, packageUriResolver, null); |
| 754 } | 886 } |
| 755 | 887 |
| 756 /** | 888 /** |
| 757 * Create and return a source representing the given [file] within the given | 889 * Create and return a source representing the given [file] within the given |
| 758 * [context]. | 890 * [context]. |
| 759 */ | 891 */ |
| 760 static Source createSourceInContext(AnalysisContext context, File file) { | 892 static Source createSourceInContext(AnalysisContext context, File file) { |
| 761 // TODO(brianwilkerson) Optimize this, by allowing support for source | 893 // TODO(brianwilkerson) Optimize this, by allowing support for source |
| 762 // factories to restore URI's from a file path rather than a source. | 894 // factories to restore URI's from a file path rather than a source. |
| 763 Source source = file.createSource(); | 895 Source source = file.createSource(); |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 889 * The package root for this context, or null if there is no package root. | 1021 * The package root for this context, or null if there is no package root. |
| 890 */ | 1022 */ |
| 891 String packageRoot; | 1023 String packageRoot; |
| 892 | 1024 |
| 893 /** | 1025 /** |
| 894 * The [_ContextInfo] that encloses this one. | 1026 * The [_ContextInfo] that encloses this one. |
| 895 */ | 1027 */ |
| 896 _ContextInfo parent; | 1028 _ContextInfo parent; |
| 897 | 1029 |
| 898 /** | 1030 /** |
| 899 * The `pubspec.yaml` file path for this context. | 1031 * The package description file path for this context. |
| 900 */ | 1032 */ |
| 901 String pubspecPath; | 1033 String packageDescriptionPath; |
| 902 | 1034 |
| 903 /** | 1035 /** |
| 904 * Stream subscription we are using to watch the context's directory for | 1036 * Stream subscription we are using to watch the context's directory for |
| 905 * changes. | 1037 * changes. |
| 906 */ | 1038 */ |
| 907 StreamSubscription<WatchEvent> changeSubscription; | 1039 StreamSubscription<WatchEvent> changeSubscription; |
| 908 | 1040 |
| 909 /** | 1041 /** |
| 910 * Stream subscriptions we are using to watch the files | 1042 * Stream subscriptions we are using to watch the files |
| 911 * used to determine the package map. | 1043 * used to determine the package map. |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 924 */ | 1056 */ |
| 925 Map<String, Source> sources = new HashMap<String, Source>(); | 1057 Map<String, Source> sources = new HashMap<String, Source>(); |
| 926 | 1058 |
| 927 /** | 1059 /** |
| 928 * Info returned by the last call to | 1060 * Info returned by the last call to |
| 929 * [OptimizingPubPackageMapProvider.computePackageMap], or `null` if the | 1061 * [OptimizingPubPackageMapProvider.computePackageMap], or `null` if the |
| 930 * package map hasn't been computed for this context yet. | 1062 * package map hasn't been computed for this context yet. |
| 931 */ | 1063 */ |
| 932 OptimizingPubPackageMapInfo packageMapInfo; | 1064 OptimizingPubPackageMapInfo packageMapInfo; |
| 933 | 1065 |
| 934 _ContextInfo(Folder folder, File pubspecFile, this.children, this.packageRoot) | 1066 _ContextInfo(Folder folder, File pubspecFile, this.children, this.packageRoot) |
|
Paul Berry
2015/07/17 20:49:13
Rename pubspecFile to packageDescriptionFile to be
pquitslund
2015/07/20 20:50:22
Done.
| |
| 935 : folder = folder, | 1067 : folder = folder, |
| 936 pathFilter = new PathFilter(folder.path, null) { | 1068 pathFilter = new PathFilter(folder.path, null) { |
| 937 pubspecPath = pubspecFile.path; | 1069 packageDescriptionPath = pubspecFile.path; |
| 938 for (_ContextInfo child in children) { | 1070 for (_ContextInfo child in children) { |
| 939 child.parent = this; | 1071 child.parent = this; |
| 940 } | 1072 } |
| 941 } | 1073 } |
| 942 | 1074 |
| 943 /** | 1075 /** |
| 944 * Returns `true` if this context is root folder based. | 1076 * Returns `true` if this context is root folder based. |
| 945 */ | 1077 */ |
| 946 bool get isRoot => parent == null; | 1078 bool get isRoot => parent == null; |
| 947 | 1079 |
| 948 /** | 1080 /** |
| 949 * Returns `true` if [path] is excluded, as it is in one of the children. | 1081 * Returns `true` if [path] is excluded, as it is in one of the children. |
| 950 */ | 1082 */ |
| 951 bool excludes(String path) { | 1083 bool excludes(String path) { |
| 952 return children.any((child) { | 1084 return children.any((child) { |
| 953 return child.folder.contains(path); | 1085 return child.folder.contains(path); |
| 954 }); | 1086 }); |
| 955 } | 1087 } |
| 956 | 1088 |
| 1089 /** | |
| 1090 * Returns `true` if [resource] is excluded, as it is in one of the children. | |
| 1091 */ | |
| 1092 bool excludesResource(Resource resource) => excludes(resource.path); | |
| 1093 | |
| 957 /// Returns `true` if [path] should be ignored. | 1094 /// Returns `true` if [path] should be ignored. |
| 958 bool ignored(String path) => pathFilter.ignored(path); | 1095 bool ignored(String path) => pathFilter.ignored(path); |
| 959 | 1096 |
| 960 /** | 1097 /** |
| 961 * Returns `true` if [resource] is excluded, as it is in one of the children. | 1098 * Returns `true` if [path] is the package description file for this context |
| 1099 * (pubspec.yaml or .packages). | |
| 962 */ | 1100 */ |
| 963 bool excludesResource(Resource resource) { | 1101 bool isPathToPackageDescription(String path) => |
| 964 return excludes(resource.path); | 1102 path == packageDescriptionPath; |
| 965 } | |
| 966 | |
| 967 /** | |
| 968 * Returns `true` if [path] is the pubspec file of this context. | |
| 969 */ | |
| 970 bool isPubspec(String path) { | |
| 971 return path == pubspecPath; | |
| 972 } | |
| 973 } | 1103 } |
| OLD | NEW |