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 |