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

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: 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/src/generated/engine.dart'; 18 import 'package:analyzer/src/generated/engine.dart';
18 import 'package:analyzer/src/generated/java_io.dart'; 19 import 'package:analyzer/src/generated/java_io.dart';
19 import 'package:analyzer/src/generated/source.dart'; 20 import 'package:analyzer/src/generated/source.dart';
20 import 'package:analyzer/src/generated/source_io.dart'; 21 import 'package:analyzer/src/generated/source_io.dart';
22 import 'package:package_config/packages.dart';
23 import 'package:package_config/packages_file.dart' as pkgfile show parse;
24 import 'package:package_config/src/packages_impl.dart' show MapPackages;
21 import 'package:path/path.dart' as pathos; 25 import 'package:path/path.dart' as pathos;
22 import 'package:watcher/watcher.dart'; 26 import 'package:watcher/watcher.dart';
23 27
24 /** 28 /**
25 * Class that maintains a mapping from included/excluded paths to a set of 29 * Class that maintains a mapping from included/excluded paths to a set of
26 * folders that should correspond to analysis contexts. 30 * folders that should correspond to analysis contexts.
27 */ 31 */
28 abstract class AbstractContextManager implements ContextManager { 32 abstract class AbstractContextManager implements ContextManager {
29 /** 33 /**
30 * The name of the `lib` directory. 34 * The name of the `lib` directory.
31 */ 35 */
32 static const String LIB_DIR_NAME = 'lib'; 36 static const String LIB_DIR_NAME = 'lib';
33 37
34 /** 38 /**
35 * The name of `packages` folders. 39 * The name of `packages` folders.
36 */ 40 */
37 static const String PACKAGES_NAME = 'packages'; 41 static const String PACKAGES_NAME = 'packages';
38 42
39 /** 43 /**
40 * File name of pubspec files. 44 * File name of pubspec files.
41 */ 45 */
42 static const String PUBSPEC_NAME = 'pubspec.yaml'; 46 static const String PUBSPEC_NAME = 'pubspec.yaml';
43 47
44 /** 48 /**
49 * File name of package spec files.
50 */
51 static const String PACKAGE_SPEC_NAME = '.packages';
52
53 /**
45 * [_ContextInfo] object for each included directory in the most 54 * [_ContextInfo] object for each included directory in the most
46 * recent successful call to [setRoots]. 55 * recent successful call to [setRoots].
47 */ 56 */
48 Map<Folder, _ContextInfo> _contexts = new HashMap<Folder, _ContextInfo>(); 57 Map<Folder, _ContextInfo> _contexts = new HashMap<Folder, _ContextInfo>();
49 58
50 /** 59 /**
51 * The [ResourceProvider] using which paths are converted into [Resource]s. 60 * The [ResourceProvider] using which paths are converted into [Resource]s.
52 */ 61 */
53 final ResourceProvider resourceProvider; 62 final ResourceProvider resourceProvider;
54 63
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
99 final InstrumentationService _instrumentationService; 108 final InstrumentationService _instrumentationService;
100 109
101 AbstractContextManager(this.resourceProvider, this.packageResolverProvider, 110 AbstractContextManager(this.resourceProvider, this.packageResolverProvider,
102 this._packageMapProvider, this._instrumentationService) { 111 this._packageMapProvider, this._instrumentationService) {
103 pathContext = resourceProvider.pathContext; 112 pathContext = resourceProvider.pathContext;
104 } 113 }
105 114
106 /** 115 /**
107 * Create and return a new analysis context. 116 * Create and return a new analysis context.
108 */ 117 */
109 AnalysisContext addContext(Folder folder, UriResolver packageUriResolver); 118 AnalysisContext addContext(
119 Folder folder, UriResolver packageUriResolver, Packages packages);
110 120
111 /** 121 /**
112 * Called when the set of files associated with a context have changed (or 122 * Called when the set of files associated with a context have changed (or
113 * some of those files have been modified). [changeSet] is the set of 123 * some of those files have been modified). [changeSet] is the set of
114 * changes that need to be applied to the context. 124 * changes that need to be applied to the context.
115 */ 125 */
116 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet); 126 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet);
117 127
118 /** 128 /**
119 * We are about to start computing the package map. 129 * We are about to start computing the package map.
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 301
292 /** 302 /**
293 * Return `true` if the given [file] should be analyzed. 303 * Return `true` if the given [file] should be analyzed.
294 */ 304 */
295 bool shouldFileBeAnalyzed(File file); 305 bool shouldFileBeAnalyzed(File file);
296 306
297 /** 307 /**
298 * Called when the package map for a context has changed. 308 * Called when the package map for a context has changed.
299 */ 309 */
300 void updateContextPackageUriResolver( 310 void updateContextPackageUriResolver(
301 Folder contextFolder, UriResolver packageUriResolver); 311 Folder contextFolder, UriResolver packageUriResolver, Packages packages);
302 312
303 /** 313 /**
304 * Resursively adds all Dart and HTML files to the [changeSet]. 314 * Resursively adds all Dart and HTML files to the [changeSet].
305 */ 315 */
306 void _addPreviouslyExcludedSources(_ContextInfo info, ChangeSet changeSet, 316 void _addPreviouslyExcludedSources(_ContextInfo info, ChangeSet changeSet,
307 Folder folder, List<String> oldExcludedPaths) { 317 Folder folder, List<String> oldExcludedPaths) {
308 if (info.excludesResource(folder)) { 318 if (info.excludesResource(folder)) {
309 return; 319 return;
310 } 320 }
311 List<Resource> children; 321 List<Resource> children;
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
384 /** 394 /**
385 * Cancel all dependency subscriptions for the given context. 395 * Cancel all dependency subscriptions for the given context.
386 */ 396 */
387 void _cancelDependencySubscriptions(_ContextInfo info) { 397 void _cancelDependencySubscriptions(_ContextInfo info) {
388 for (StreamSubscription<WatchEvent> s in info.dependencySubscriptions) { 398 for (StreamSubscription<WatchEvent> s in info.dependencySubscriptions) {
389 s.cancel(); 399 s.cancel();
390 } 400 }
391 info.dependencySubscriptions.clear(); 401 info.dependencySubscriptions.clear();
392 } 402 }
393 403
404 void _checkForPackagespecUpdate(
405 String path, _ContextInfo info, Folder folder) {
406 // Check to see if this is the .packages file for this context and if so,
407 // update the context's source factory.
408 if (pathContext.basename(path) == PACKAGE_SPEC_NAME &&
409 info.isPathToPackageDescription(path)) {
410 File packagespec = resourceProvider.getFile(path);
411 if (packagespec.exists) {
412 Packages packages = _readPackagespec(packagespec);
413 updateContextPackageUriResolver(folder, null, packages);
414 }
415 }
416 }
417
394 /** 418 /**
395 * Compute the appropriate package URI resolver for [folder], and store 419 * Compute the appropriate package URI resolver for [folder], and store
396 * dependency information in [info]. Return `null` if no package map can 420 * dependency information in [info]. Return `null` if no package map can
397 * be computed. 421 * be computed.
398 */ 422 */
399 UriResolver _computePackageUriResolver(Folder folder, _ContextInfo info) { 423 UriResolver _computePackageUriResolver(Folder folder, _ContextInfo info) {
400 _cancelDependencySubscriptions(info); 424 _cancelDependencySubscriptions(info);
401 if (info.packageRoot != null) { 425 if (info.packageRoot != null) {
402 info.packageMapInfo = null; 426 info.packageMapInfo = null;
403 JavaFile packagesDir = new JavaFile(info.packageRoot); 427 JavaFile packagesDir = new JavaFile(info.packageRoot);
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
464 resourceProvider, packageMapInfo.packageMap); 488 resourceProvider, packageMapInfo.packageMap);
465 // TODO(paulberry): if any of the dependencies is outside of [folder], 489 // TODO(paulberry): if any of the dependencies is outside of [folder],
466 // we'll need to watch their parent folders as well. 490 // we'll need to watch their parent folders as well.
467 } 491 }
468 } 492 }
469 493
470 /** 494 /**
471 * Create a new empty context associated with [folder]. 495 * Create a new empty context associated with [folder].
472 */ 496 */
473 _ContextInfo _createContext( 497 _ContextInfo _createContext(
474 Folder folder, File pubspecFile, List<_ContextInfo> children) { 498 Folder folder, File pubspecFile, List<_ContextInfo> children) {
Brian Wilkerson 2015/07/17 18:02:57 Perhaps rename 'pubspecFile' to 'packageSpec' for
pquitslund 2015/07/17 19:30:02 Done.
475 _ContextInfo info = new _ContextInfo( 499 _ContextInfo info = new _ContextInfo(
476 folder, pubspecFile, children, normalizedPackageRoots[folder.path]); 500 folder, pubspecFile, children, normalizedPackageRoots[folder.path]);
477 _contexts[folder] = info; 501 _contexts[folder] = info;
478 info.changeSubscription = folder.changes.listen((WatchEvent event) { 502 info.changeSubscription = folder.changes.listen((WatchEvent event) {
479 _handleWatchEvent(folder, info, event); 503 _handleWatchEvent(folder, info, event);
480 }); 504 });
481 try { 505 try {
482 UriResolver packageUriResolver = _computePackageUriResolver(folder, info); 506 Packages packages;
483 info.context = addContext(folder, packageUriResolver); 507 UriResolver packageUriResolver;
508
509 // Try .packages first.
510 if (pathos.basename(pubspecFile.path) == PACKAGE_SPEC_NAME) {
511 packages = _readPackagespec(pubspecFile);
512 }
513
514 // Next resort to a package uri resolver.
515 if (packages == null) {
516 packageUriResolver = _computePackageUriResolver(folder, info);
517 }
518
519 info.context = addContext(folder, packageUriResolver, packages);
484 info.context.name = folder.path; 520 info.context.name = folder.path;
485 } catch (_) { 521 } catch (_) {
486 info.changeSubscription.cancel(); 522 info.changeSubscription.cancel();
487 rethrow; 523 rethrow;
488 } 524 }
489 return info; 525 return info;
490 } 526 }
491 527
492 /** 528 /**
493 * Potentially create a new context associated with the given [folder]. 529 * Potentially create a new context associated with the given [folder].
494 * 530 *
495 * If there are subfolders with 'pubspec.yaml' files, separate contexts are 531 * If there are subfolders with 'pubspec.yaml' files, separate contexts are
496 * created for them and excluded from the context associated with the 532 * created for them and excluded from the context associated with the
497 * [folder]. 533 * [folder].
498 * 534 *
499 * If [withPubspecOnly] is `true`, a context will be created only if there 535 * If [withPackageSpecOnly] is `true`, a context will be created only if there
500 * is a 'pubspec.yaml' file in the [folder]. 536 * is a 'pubspec.yaml' or '.packages' file in the [folder].
501 * 537 *
502 * Returns create pubspec-based contexts. 538 * Returns created contexts.
503 */ 539 */
504 List<_ContextInfo> _createContexts(Folder folder, bool withPubspecOnly) { 540 List<_ContextInfo> _createContexts(Folder folder, bool withPackageSpecOnly) {
505 // try to find subfolders with pubspec files 541 // Try to find subfolders with pubspecs or .packages files.
506 List<_ContextInfo> children = <_ContextInfo>[]; 542 List<_ContextInfo> children = <_ContextInfo>[];
507 try { 543 try {
508 for (Resource child in folder.getChildren()) { 544 for (Resource child in folder.getChildren()) {
509 if (child is Folder) { 545 if (child is Folder) {
510 children.addAll(_createContexts(child, true)); 546 children.addAll(_createContexts(child, true));
511 } 547 }
512 } 548 }
513 } on FileSystemException { 549 } on FileSystemException {
514 // The directory either doesn't exist or cannot be read. Either way, there 550 // The directory either doesn't exist or cannot be read. Either way, there
515 // are no subfolders that need to be added. 551 // are no subfolders that need to be added.
516 } 552 }
517 // check whether there is a pubspec in the folder 553
518 File pubspecFile = folder.getChild(PUBSPEC_NAME); 554 // Start by looking for .packages.
519 if (pubspecFile.exists) { 555 File packageSpec = folder.getChild(PACKAGE_SPEC_NAME);
556
557 // Fall back to looking for a pubspec.
558 if (!packageSpec.exists) {
559 packageSpec = folder.getChild(PUBSPEC_NAME);
560 }
561
562 if (packageSpec.exists) {
520 return <_ContextInfo>[ 563 return <_ContextInfo>[
521 _createContextWithSources(folder, pubspecFile, children) 564 _createContextWithSources(folder, packageSpec, children)
522 ]; 565 ];
523 } 566 }
524 // no pubspec, done 567 // No packagespec? Done.
525 if (withPubspecOnly) { 568 if (withPackageSpecOnly) {
526 return children; 569 return children;
527 } 570 }
528 // OK, create a context without a pubspec 571 // OK, create a context without a packagespec.
529 return <_ContextInfo>[ 572 return <_ContextInfo>[
530 _createContextWithSources(folder, pubspecFile, children) 573 _createContextWithSources(folder, packageSpec, children)
531 ]; 574 ];
532 } 575 }
533 576
534 /** 577 /**
535 * Create a new context associated with the given [folder]. The [pubspecFile] 578 * Create a new context associated with the given [folder]. The [pubspecFile]
536 * is the `pubspec.yaml` file contained in the folder. Add any sources that 579 * is the `pubspec.yaml` file contained in the folder. Add any sources that
537 * are not included in one of the [children] to the context. 580 * are not included in one of the [children] to the context.
538 */ 581 */
539 _ContextInfo _createContextWithSources( 582 _ContextInfo _createContextWithSources(
540 Folder folder, File pubspecFile, List<_ContextInfo> children) { 583 Folder folder, File pubspecFile, List<_ContextInfo> children) {
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
606 if (info.excludes(path)) { 649 if (info.excludes(path)) {
607 return; 650 return;
608 } 651 }
609 // handle the change 652 // handle the change
610 switch (event.type) { 653 switch (event.type) {
611 case ChangeType.ADD: 654 case ChangeType.ADD:
612 if (_isInPackagesDir(path, folder)) { 655 if (_isInPackagesDir(path, folder)) {
613 return; 656 return;
614 } 657 }
615 Resource resource = resourceProvider.getResource(path); 658 Resource resource = resourceProvider.getResource(path);
616 // pubspec was added in a sub-folder, extract a new context 659
617 if (_isPubspec(path) && info.isRoot && !info.isPubspec(path)) { 660 String directoryPath = pathContext.dirname(path);
618 _extractContext(info, resource); 661
619 return; 662 // Check to see if we need to create a new context.
663 if (info.isRoot) {
664
665 // Only create a new context if this is not the same directory
666 // described by our info object.
667 if (info.folder.path != directoryPath) {
Brian Wilkerson 2015/07/17 18:02:57 If a .packages file is added to the context's root
pquitslund 2015/07/17 19:30:02 Actually, I think this is handled in _createContex
668 if (pathContext.basename(path) == PUBSPEC_NAME) {
669 // Check for a sibling .packages file.
670 if (!resourceProvider
671 .getFile(pathos.join(directoryPath, '.packages')).exists) {
Brian Wilkerson 2015/07/17 18:02:58 nit: use PACKAGE_SPEC_NAME (here and below)
pquitslund 2015/07/17 19:30:02 Done.
672 _extractContext(info, resource);
673 return;
674 }
675 }
676 if (pathContext.basename(path) == PACKAGE_SPEC_NAME) {
677 // Check for a sibling pubspec.yaml file.
678 if (!resourceProvider
679 .getFile(pathos.join(directoryPath, 'pubspec.yaml')).exists) {
Brian Wilkerson 2015/07/17 18:02:57 nit: use PUBSPEC_NAME (here and below)
pquitslund 2015/07/17 19:30:02 Done.
680 _extractContext(info, resource);
681 return;
682 }
683 }
684 }
620 } 685 }
686
621 // If the file went away and was replaced by a folder before we 687 // If the file went away and was replaced by a folder before we
622 // had a chance to process the event, resource might be a Folder. In 688 // had a chance to process the event, resource might be a Folder. In
623 // that case don't add it. 689 // that case don't add it.
624 if (resource is File) { 690 if (resource is File) {
625 File file = resource; 691 File file = resource;
626 if (shouldFileBeAnalyzed(file)) { 692 if (shouldFileBeAnalyzed(file)) {
627 ChangeSet changeSet = new ChangeSet(); 693 ChangeSet changeSet = new ChangeSet();
628 Source source = createSourceInContext(info.context, file); 694 Source source = createSourceInContext(info.context, file);
629 changeSet.addedSource(source); 695 changeSet.addedSource(source);
630 applyChangesToContext(folder, changeSet); 696 applyChangesToContext(folder, changeSet);
631 info.sources[path] = source; 697 info.sources[path] = source;
632 } 698 }
633 } 699 }
634 break; 700 break;
635 case ChangeType.REMOVE: 701 case ChangeType.REMOVE:
636 // pubspec was removed, merge the context into its parent 702
637 if (info.isPubspec(path) && !info.isRoot) { 703 // If package spec info is removed, check to see if we can merge context s.
638 _mergeContext(info); 704 // Note that it's important to verify that there is NEITHER a .packages nor a
639 return; 705 // lingering pubspec.yaml before merging.
706 if (!info.isRoot) {
707 String directoryPath = pathContext.dirname(path);
708
709 // Only merge if this is the same directory described by our info obje ct.
710 if (info.folder.path == directoryPath) {
711 if (pathContext.basename(path) == PUBSPEC_NAME) {
712 // Check for a sibling .packages file.
713 if (!resourceProvider
714 .getFile(pathos.join(directoryPath, '.packages')).exists) {
715 _mergeContext(info);
716 return;
717 }
718 }
719 if (pathContext.basename(path) == PACKAGE_SPEC_NAME) {
720 // Check for a sibling pubspec.yaml file.
721 if (!resourceProvider
722 .getFile(pathos.join(directoryPath, 'pubspec.yaml')).exists) {
723 _mergeContext(info);
724 return;
725 }
726 }
727 }
640 } 728 }
729
641 List<Source> sources = info.context.getSourcesWithFullName(path); 730 List<Source> sources = info.context.getSourcesWithFullName(path);
642 if (!sources.isEmpty) { 731 if (!sources.isEmpty) {
643 ChangeSet changeSet = new ChangeSet(); 732 ChangeSet changeSet = new ChangeSet();
644 sources.forEach((Source source) { 733 sources.forEach((Source source) {
645 changeSet.removedSource(source); 734 changeSet.removedSource(source);
646 }); 735 });
647 applyChangesToContext(folder, changeSet); 736 applyChangesToContext(folder, changeSet);
648 info.sources.remove(path); 737 info.sources.remove(path);
649 } 738 }
650 break; 739 break;
651 case ChangeType.MODIFY: 740 case ChangeType.MODIFY:
Brian Wilkerson 2015/07/17 18:02:57 Do we handle changes to the .packages file somewhe
pquitslund 2015/07/17 19:30:02 Yes. That's outside the switch. (See below.) Ce
652 List<Source> sources = info.context.getSourcesWithFullName(path); 741 List<Source> sources = info.context.getSourcesWithFullName(path);
653 if (!sources.isEmpty) { 742 if (!sources.isEmpty) {
654 ChangeSet changeSet = new ChangeSet(); 743 ChangeSet changeSet = new ChangeSet();
655 sources.forEach((Source source) { 744 sources.forEach((Source source) {
656 changeSet.changedSource(source); 745 changeSet.changedSource(source);
657 }); 746 });
658 applyChangesToContext(folder, changeSet); 747 applyChangesToContext(folder, changeSet);
659 } 748 }
660 break; 749 break;
661 } 750 }
662 751
752 //TODO(pquitslund): find the right place for this
753 _checkForPackagespecUpdate(path, info, folder);
pquitslund 2015/07/17 19:30:02 Here's where we test for .packages changes.
754
663 if (info.packageMapInfo != null && 755 if (info.packageMapInfo != null &&
664 info.packageMapInfo.isChangedDependency(path, resourceProvider)) { 756 info.packageMapInfo.isChangedDependency(path, resourceProvider)) {
665 _recomputePackageUriResolver(info); 757 _recomputePackageUriResolver(info);
666 } 758 }
667 } 759 }
668 760
669 /** 761 /**
670 * Returns `true` if the given [path] is excluded by [excludedPaths]. 762 * Returns `true` if the given [path] is excluded by [excludedPaths].
671 */ 763 */
672 bool _isExcluded(String path) { 764 bool _isExcluded(String path) => _isExcludedBy(excludedPaths, path);
673 return _isExcludedBy(excludedPaths, path);
674 }
675 765
676 /** 766 /**
677 * Returns `true` if the given [path] is excluded by [excludedPaths]. 767 * Returns `true` if the given [path] is excluded by [excludedPaths].
678 */ 768 */
679 bool _isExcludedBy(List<String> excludedPaths, String path) { 769 bool _isExcludedBy(List<String> excludedPaths, String path) {
680 return excludedPaths.any((excludedPath) { 770 return excludedPaths.any((excludedPath) {
681 if (pathContext.isWithin(excludedPath, path)) { 771 if (pathContext.isWithin(excludedPath, path)) {
682 return true; 772 return true;
683 } 773 }
684 return path == excludedPath; 774 return path == excludedPath;
685 }); 775 });
686 } 776 }
687 777
688 /** 778 /**
689 * Determine if the path from [folder] to [path] contains a 'packages' 779 * Determine if the path from [folder] to [path] contains a 'packages'
690 * directory. 780 * directory.
691 */ 781 */
692 bool _isInPackagesDir(String path, Folder folder) { 782 bool _isInPackagesDir(String path, Folder folder) {
693 String relativePath = pathContext.relative(path, from: folder.path); 783 String relativePath = pathContext.relative(path, from: folder.path);
694 List<String> pathParts = pathContext.split(relativePath); 784 List<String> pathParts = pathContext.split(relativePath);
695 return pathParts.contains(PACKAGES_NAME); 785 return pathParts.contains(PACKAGES_NAME);
696 } 786 }
697 787
698 /** 788 /**
699 * Returns `true` if the given absolute [path] is a pubspec file.
700 */
701 bool _isPubspec(String path) {
702 return pathContext.basename(path) == PUBSPEC_NAME;
703 }
704
705 /**
706 * Merges [info] context into its parent. 789 * Merges [info] context into its parent.
707 */ 790 */
708 void _mergeContext(_ContextInfo info) { 791 void _mergeContext(_ContextInfo info) {
709 // destroy the context 792 // destroy the context
710 _destroyContext(info.folder); 793 _destroyContext(info.folder);
711 // add files to the parent context 794 // add files to the parent context
712 _ContextInfo parentInfo = info.parent; 795 _ContextInfo parentInfo = info.parent;
713 if (parentInfo != null) { 796 if (parentInfo != null) {
714 parentInfo.children.remove(info); 797 parentInfo.children.remove(info);
715 ChangeSet changeSet = new ChangeSet(); 798 ChangeSet changeSet = new ChangeSet();
716 info.sources.forEach((path, source) { 799 info.sources.forEach((path, source) {
717 parentInfo.sources[path] = source; 800 parentInfo.sources[path] = source;
718 changeSet.addedSource(source); 801 changeSet.addedSource(source);
719 }); 802 });
720 applyChangesToContext(parentInfo.folder, changeSet); 803 applyChangesToContext(parentInfo.folder, changeSet);
721 } 804 }
722 } 805 }
723 806
807 Packages _readPackagespec(File specFile) {
808 //TODO(pquitslund): error-handling?
Brian Wilkerson 2015/07/17 18:02:57 Yes. If we cannot read the file, I think we should
pquitslund 2015/07/17 19:30:02 Cool. Added a try/catch and a TODO to create an e
809 String contents = specFile.readAsStringSync();
810 Map<String, Uri> map =
811 pkgfile.parse(UTF8.encode(contents), new Uri.file(specFile.path));
812 return new MapPackages(map);
813 }
814
724 /** 815 /**
725 * Recompute the package URI resolver for the context described by [info], 816 * Recompute the package URI resolver for the context described by [info],
726 * and update the client appropriately. 817 * and update the client appropriately.
727 */ 818 */
728 void _recomputePackageUriResolver(_ContextInfo info) { 819 void _recomputePackageUriResolver(_ContextInfo info) {
729 // TODO(paulberry): when computePackageMap is changed into an 820 // TODO(paulberry): when computePackageMap is changed into an
730 // asynchronous API call, we'll want to suspend analysis for this context 821 // asynchronous API call, we'll want to suspend analysis for this context
731 // while we're rerunning "pub list", since any analysis we complete while 822 // while we're rerunning "pub list", since any analysis we complete while
732 // "pub list" is in progress is just going to get thrown away anyhow. 823 // "pub list" is in progress is just going to get thrown away anyhow.
733 UriResolver packageUriResolver = 824 UriResolver packageUriResolver =
734 _computePackageUriResolver(info.folder, info); 825 _computePackageUriResolver(info.folder, info);
735 updateContextPackageUriResolver(info.folder, packageUriResolver); 826 updateContextPackageUriResolver(info.folder, packageUriResolver, null);
736 } 827 }
737 828
738 /** 829 /**
739 * Create and return a source representing the given [file] within the given 830 * Create and return a source representing the given [file] within the given
740 * [context]. 831 * [context].
741 */ 832 */
742 static Source createSourceInContext(AnalysisContext context, File file) { 833 static Source createSourceInContext(AnalysisContext context, File file) {
743 // TODO(brianwilkerson) Optimize this, by allowing support for source 834 // TODO(brianwilkerson) Optimize this, by allowing support for source
744 // factories to restore URI's from a file path rather than a source. 835 // factories to restore URI's from a file path rather than a source.
745 Source source = file.createSource(); 836 Source source = file.createSource();
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
868 * The package root for this context, or null if there is no package root. 959 * The package root for this context, or null if there is no package root.
869 */ 960 */
870 String packageRoot; 961 String packageRoot;
871 962
872 /** 963 /**
873 * The [_ContextInfo] that encloses this one. 964 * The [_ContextInfo] that encloses this one.
874 */ 965 */
875 _ContextInfo parent; 966 _ContextInfo parent;
876 967
877 /** 968 /**
878 * The `pubspec.yaml` file path for this context. 969 * The package description file path for this context.
879 */ 970 */
880 String pubspecPath; 971 String packageDescriptionPath;
881 972
882 /** 973 /**
883 * Stream subscription we are using to watch the context's directory for 974 * Stream subscription we are using to watch the context's directory for
884 * changes. 975 * changes.
885 */ 976 */
886 StreamSubscription<WatchEvent> changeSubscription; 977 StreamSubscription<WatchEvent> changeSubscription;
887 978
888 /** 979 /**
889 * Stream subscriptions we are using to watch the files 980 * Stream subscriptions we are using to watch the files
890 * used to determine the package map. 981 * used to determine the package map.
(...skipping 13 matching lines...) Expand all
904 Map<String, Source> sources = new HashMap<String, Source>(); 995 Map<String, Source> sources = new HashMap<String, Source>();
905 996
906 /** 997 /**
907 * Info returned by the last call to 998 * Info returned by the last call to
908 * [OptimizingPubPackageMapProvider.computePackageMap], or `null` if the 999 * [OptimizingPubPackageMapProvider.computePackageMap], or `null` if the
909 * package map hasn't been computed for this context yet. 1000 * package map hasn't been computed for this context yet.
910 */ 1001 */
911 OptimizingPubPackageMapInfo packageMapInfo; 1002 OptimizingPubPackageMapInfo packageMapInfo;
912 1003
913 _ContextInfo(this.folder, File pubspecFile, this.children, this.packageRoot) { 1004 _ContextInfo(this.folder, File pubspecFile, this.children, this.packageRoot) {
914 pubspecPath = pubspecFile.path; 1005 packageDescriptionPath = pubspecFile.path;
915 for (_ContextInfo child in children) { 1006 for (_ContextInfo child in children) {
916 child.parent = this; 1007 child.parent = this;
917 } 1008 }
918 } 1009 }
919 1010
920 /** 1011 /**
921 * Returns `true` if this context is root folder based. 1012 * Returns `true` if this context is root folder based.
922 */ 1013 */
923 bool get isRoot => parent == null; 1014 bool get isRoot => parent == null;
924 1015
925 /** 1016 /**
926 * Returns `true` if [path] is excluded, as it is in one of the children. 1017 * Returns `true` if [path] is excluded, as it is in one of the children.
927 */ 1018 */
928 bool excludes(String path) { 1019 bool excludes(String path) {
929 return children.any((child) { 1020 return children.any((child) {
930 return child.folder.contains(path); 1021 return child.folder.contains(path);
931 }); 1022 });
932 } 1023 }
933 1024
934 /** 1025 /**
935 * Returns `true` if [resource] is excluded, as it is in one of the children. 1026 * Returns `true` if [resource] is excluded, as it is in one of the children.
936 */ 1027 */
937 bool excludesResource(Resource resource) { 1028 bool excludesResource(Resource resource) => excludes(resource.path);
938 return excludes(resource.path);
939 }
940 1029
941 /** 1030 /**
942 * Returns `true` if [path] is the pubspec file of this context. 1031 * Returns `true` if [path] is the package description file for this context
1032 * (pubspec.yaml or .packages).
943 */ 1033 */
944 bool isPubspec(String path) { 1034 bool isPathToPackageDescription(String path) =>
945 return path == pubspecPath; 1035 path == packageDescriptionPath;
946 }
947 } 1036 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698