Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(872)

Side by Side Diff: pkg/analysis_server/lib/src/context_manager.dart

Issue 1242023008: Server .packages support. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Cleanup. Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « pkg/analysis_server/lib/src/analysis_server.dart ('k') | pkg/analysis_server/test/context_manager_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698