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

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

Issue 1251663002: Remove redundant context lookups from option-processing code. (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
« no previous file with comments | « no previous file | pkg/analysis_server/test/context_manager_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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:convert';
10 import 'dart:core' hide Resource; 10 import 'dart:core' hide Resource;
(...skipping 11 matching lines...) Expand all
22 import 'package:analyzer/src/generated/source.dart'; 22 import 'package:analyzer/src/generated/source.dart';
23 import 'package:analyzer/src/generated/source_io.dart'; 23 import 'package:analyzer/src/generated/source_io.dart';
24 import 'package:package_config/packages.dart'; 24 import 'package:package_config/packages.dart';
25 import 'package:package_config/packages_file.dart' as pkgfile show parse; 25 import 'package:package_config/packages_file.dart' as pkgfile show parse;
26 import 'package:package_config/src/packages_impl.dart' show MapPackages; 26 import 'package:package_config/src/packages_impl.dart' show MapPackages;
27 import 'package:path/path.dart' as pathos; 27 import 'package:path/path.dart' as pathos;
28 import 'package:watcher/watcher.dart'; 28 import 'package:watcher/watcher.dart';
29 import 'package:yaml/yaml.dart'; 29 import 'package:yaml/yaml.dart';
30 30
31 /** 31 /**
32 * Information tracked by the [ContextManager] for each context.
33 */
34 class ContextInfo {
35 /**
36 * The [Folder] for which this information object is created.
37 */
38 final Folder folder;
39
40 /// The [PathFilter] used to filter sources from being analyzed.
41 final PathFilter pathFilter;
42
43 /**
44 * The enclosed pubspec-based contexts.
45 */
46 final List<ContextInfo> children;
47
48 /**
49 * The package root for this context, or null if there is no package root.
50 */
51 String packageRoot;
52
53 /**
54 * The [ContextInfo] that encloses this one.
55 */
56 ContextInfo parent;
57
58 /**
59 * The package description file path for this context.
60 */
61 String packageDescriptionPath;
62
63 /**
64 * Stream subscription we are using to watch the context's directory for
65 * changes.
66 */
67 StreamSubscription<WatchEvent> changeSubscription;
68
69 /**
70 * Stream subscriptions we are using to watch the files
71 * used to determine the package map.
72 */
73 final List<StreamSubscription<WatchEvent>> dependencySubscriptions =
74 <StreamSubscription<WatchEvent>>[];
75
76 /**
77 * The analysis context that was created for the [folder].
78 */
79 AnalysisContext context;
80
81 /**
82 * Map from full path to the [Source] object, for each source that has been
83 * added to the context.
84 */
85 Map<String, Source> sources = new HashMap<String, Source>();
86
87 /**
88 * Info returned by the last call to
89 * [OptimizingPubPackageMapProvider.computePackageMap], or `null` if the
90 * package map hasn't been computed for this context yet.
91 */
92 OptimizingPubPackageMapInfo packageMapInfo;
93
94 ContextInfo(
95 Folder folder, File packagespecFile, this.children, this.packageRoot)
96 : folder = folder,
97 pathFilter = new PathFilter(folder.path, null) {
98 packageDescriptionPath = packagespecFile.path;
99 for (ContextInfo child in children) {
100 child.parent = this;
101 }
102 }
103
104 /**
105 * Returns `true` if this context is root folder based.
106 */
107 bool get isRoot => parent == null;
108
109 /**
110 * Returns `true` if [path] is excluded, as it is in one of the children.
111 */
112 bool excludes(String path) {
113 return children.any((child) {
114 return child.folder.contains(path);
115 });
116 }
117
118 /**
119 * Returns `true` if [resource] is excluded, as it is in one of the children.
120 */
121 bool excludesResource(Resource resource) => excludes(resource.path);
122
123 /// Returns `true` if [path] should be ignored.
124 bool ignored(String path) => pathFilter.ignored(path);
125
126 /**
127 * Returns `true` if [path] is the package description file for this context
128 * (pubspec.yaml or .packages).
129 */
130 bool isPathToPackageDescription(String path) =>
131 path == packageDescriptionPath;
132 }
133
134 /**
32 * Class that maintains a mapping from included/excluded paths to a set of 135 * Class that maintains a mapping from included/excluded paths to a set of
33 * folders that should correspond to analysis contexts. 136 * folders that should correspond to analysis contexts.
34 */ 137 */
35 abstract class ContextManager { 138 abstract class ContextManager {
36 // TODO(brianwilkerson) Support: 139 // TODO(brianwilkerson) Support:
37 // setting the default analysis options 140 // setting the default analysis options
38 // setting the default content cache 141 // setting the default content cache
39 // setting the default SDK 142 // setting the default SDK
40 // maintaining AnalysisContext.folderMap (or remove it) 143 // maintaining AnalysisContext.folderMap (or remove it)
41 // telling server when a context has been added or removed (see onContextsCh anged) 144 // telling server when a context has been added or removed (see onContextsCh anged)
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 * File name of pubspec files. 280 * File name of pubspec files.
178 */ 281 */
179 static const String PUBSPEC_NAME = 'pubspec.yaml'; 282 static const String PUBSPEC_NAME = 'pubspec.yaml';
180 283
181 /** 284 /**
182 * File name of package spec files. 285 * File name of package spec files.
183 */ 286 */
184 static const String PACKAGE_SPEC_NAME = '.packages'; 287 static const String PACKAGE_SPEC_NAME = '.packages';
185 288
186 /** 289 /**
187 * [_ContextInfo] object for each included directory in the most 290 * [ContextInfo] object for each included directory in the most
188 * recent successful call to [setRoots]. 291 * recent successful call to [setRoots].
189 */ 292 */
190 Map<Folder, _ContextInfo> _contexts = new HashMap<Folder, _ContextInfo>(); 293 Map<Folder, ContextInfo> _contexts = new HashMap<Folder, ContextInfo>();
191 294
192 /** 295 /**
193 * The [ResourceProvider] using which paths are converted into [Resource]s. 296 * The [ResourceProvider] using which paths are converted into [Resource]s.
194 */ 297 */
195 final ResourceProvider resourceProvider; 298 final ResourceProvider resourceProvider;
196 299
197 /** 300 /**
198 * The context used to work with file system paths. 301 * The context used to work with file system paths.
199 */ 302 */
200 pathos.Context pathContext; 303 pathos.Context pathContext;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 ContextManagerCallbacks callbacks; 351 ContextManagerCallbacks callbacks;
249 352
250 ContextManagerImpl(this.resourceProvider, this.packageResolverProvider, 353 ContextManagerImpl(this.resourceProvider, this.packageResolverProvider,
251 this._packageMapProvider, this._instrumentationService) { 354 this._packageMapProvider, this._instrumentationService) {
252 pathContext = resourceProvider.pathContext; 355 pathContext = resourceProvider.pathContext;
253 } 356 }
254 357
255 @override 358 @override
256 List<AnalysisContext> contextsInAnalysisRoot(Folder analysisRoot) { 359 List<AnalysisContext> contextsInAnalysisRoot(Folder analysisRoot) {
257 List<AnalysisContext> contexts = <AnalysisContext>[]; 360 List<AnalysisContext> contexts = <AnalysisContext>[];
258 _contexts.forEach((Folder contextFolder, _ContextInfo info) { 361 _contexts.forEach((Folder contextFolder, ContextInfo info) {
259 if (analysisRoot.isOrContains(contextFolder.path)) { 362 if (analysisRoot.isOrContains(contextFolder.path)) {
260 contexts.add(info.context); 363 contexts.add(info.context);
261 } 364 }
262 }); 365 });
263 return contexts; 366 return contexts;
264 } 367 }
265 368
369 /**
370 * For testing: get the [ContextInfo] object for the given [folder], if any.
371 */
372 ContextInfo getContextInfoFor(Folder folder) => _contexts[folder];
373
266 @override 374 @override
267 bool isInAnalysisRoot(String path) { 375 bool isInAnalysisRoot(String path) {
268 // check if excluded 376 // check if excluded
269 if (_isExcluded(path)) { 377 if (_isExcluded(path)) {
270 return false; 378 return false;
271 } 379 }
272 // check if in of the roots 380 // check if in of the roots
273 for (Folder root in _contexts.keys) { 381 for (Folder root in _contexts.keys) {
274 if (root.contains(path)) { 382 if (root.contains(path)) {
275 return true; 383 return true;
276 } 384 }
277 } 385 }
278 // no 386 // no
279 return false; 387 return false;
280 } 388 }
281 389
282 /// Process [options] for the context [folder]. 390 /**
283 void processOptionsForContext(Folder folder, Map<String, YamlNode> options) { 391 * Process [options] for the context having info [info].
284 _ContextInfo info = _contexts[folder]; 392 */
285 if (info == null) { 393 void processOptionsForContext(
286 return; 394 ContextInfo info, Map<String, YamlNode> options) {
287 }
288 YamlMap analyzer = options['analyzer']; 395 YamlMap analyzer = options['analyzer'];
289 if (analyzer == null) { 396 if (analyzer == null) {
290 // No options for analyzer. 397 // No options for analyzer.
291 return; 398 return;
292 } 399 }
293 400
294 // Set ignore patterns. 401 // Set ignore patterns.
295 YamlList exclude = analyzer['exclude']; 402 YamlList exclude = analyzer['exclude'];
296 if (exclude != null) { 403 if (exclude != null) {
297 setIgnorePatternsForContext(folder, exclude); 404 setIgnorePatternsForContext(info, exclude);
298 } 405 }
299 } 406 }
300 407
301 @override 408 @override
302 void refresh(List<Resource> roots) { 409 void refresh(List<Resource> roots) {
303 // Destroy old contexts 410 // Destroy old contexts
304 List<Folder> contextFolders = _contexts.keys.toList(); 411 List<Folder> contextFolders = _contexts.keys.toList();
305 if (roots == null) { 412 if (roots == null) {
306 contextFolders.forEach(_destroyContext); 413 contextFolders.forEach(_destroyContext);
307 } else { 414 } else {
308 roots.forEach((Resource resource) { 415 roots.forEach((Resource resource) {
309 contextFolders.forEach((Folder contextFolder) { 416 contextFolders.forEach((Folder contextFolder) {
310 if (resource is Folder && resource.isOrContains(contextFolder.path)) { 417 if (resource is Folder && resource.isOrContains(contextFolder.path)) {
311 _destroyContext(contextFolder); 418 _destroyContext(contextFolder);
312 } 419 }
313 }); 420 });
314 }); 421 });
315 } 422 }
316 423
317 // Rebuild contexts based on the data last sent to setRoots(). 424 // Rebuild contexts based on the data last sent to setRoots().
318 setRoots(includedPaths, excludedPaths, packageRoots); 425 setRoots(includedPaths, excludedPaths, packageRoots);
319 } 426 }
320 427
321 /// Sets the [ignorePatterns] for the context [folder]. 428 /**
322 void setIgnorePatternsForContext(Folder folder, List<String> ignorePatterns) { 429 * Sets the [ignorePatterns] for the context having info [info].
323 _ContextInfo info = _contexts[folder]; 430 */
324 if (info == null) { 431 void setIgnorePatternsForContext(
325 return; 432 ContextInfo info, List<String> ignorePatterns) {
326 } 433 info.pathFilter.setIgnorePatterns(ignorePatterns);
327 var pathFilter = info.pathFilter;
328 pathFilter.setIgnorePatterns(ignorePatterns);
329 } 434 }
330 435
331 @override 436 @override
332 void setRoots(List<String> includedPaths, List<String> excludedPaths, 437 void setRoots(List<String> includedPaths, List<String> excludedPaths,
333 Map<String, String> packageRoots) { 438 Map<String, String> packageRoots) {
334 this.packageRoots = packageRoots; 439 this.packageRoots = packageRoots;
335 440
336 // Normalize all package root sources by mapping them to folders on the 441 // Normalize all package root sources by mapping them to folders on the
337 // filesystem. Ignore any package root sources that aren't folders. 442 // filesystem. Ignore any package root sources that aren't folders.
338 normalizedPackageRoots = <String, String>{}; 443 normalizedPackageRoots = <String, String>{};
(...skipping 25 matching lines...) Expand all
364 // destroy old contexts 469 // destroy old contexts
365 for (Folder contextFolder in contextFolders) { 470 for (Folder contextFolder in contextFolders) {
366 bool isIncluded = includedFolders.any((folder) { 471 bool isIncluded = includedFolders.any((folder) {
367 return folder.isOrContains(contextFolder.path); 472 return folder.isOrContains(contextFolder.path);
368 }); 473 });
369 if (!isIncluded) { 474 if (!isIncluded) {
370 _destroyContext(contextFolder); 475 _destroyContext(contextFolder);
371 } 476 }
372 } 477 }
373 // Update package roots for existing contexts 478 // Update package roots for existing contexts
374 _contexts.forEach((Folder folder, _ContextInfo info) { 479 _contexts.forEach((Folder folder, ContextInfo info) {
375 String newPackageRoot = normalizedPackageRoots[folder.path]; 480 String newPackageRoot = normalizedPackageRoots[folder.path];
376 if (info.packageRoot != newPackageRoot) { 481 if (info.packageRoot != newPackageRoot) {
377 info.packageRoot = newPackageRoot; 482 info.packageRoot = newPackageRoot;
378 _recomputePackageUriResolver(info); 483 _recomputePackageUriResolver(info);
379 } 484 }
380 }); 485 });
381 // create new contexts 486 // create new contexts
382 for (Folder includedFolder in includedFolders) { 487 for (Folder includedFolder in includedFolders) {
383 bool wasIncluded = contextFolders.any((folder) { 488 bool wasIncluded = contextFolders.any((folder) {
384 return folder.isOrContains(includedFolder.path); 489 return folder.isOrContains(includedFolder.path);
(...skipping 24 matching lines...) Expand all
409 _contexts.forEach((folder, info) { 514 _contexts.forEach((folder, info) {
410 ChangeSet changeSet = new ChangeSet(); 515 ChangeSet changeSet = new ChangeSet();
411 _addPreviouslyExcludedSources(info, changeSet, folder, oldExcludedPaths); 516 _addPreviouslyExcludedSources(info, changeSet, folder, oldExcludedPaths);
412 callbacks.applyChangesToContext(folder, changeSet); 517 callbacks.applyChangesToContext(folder, changeSet);
413 }); 518 });
414 } 519 }
415 520
416 /** 521 /**
417 * Resursively adds all Dart and HTML files to the [changeSet]. 522 * Resursively adds all Dart and HTML files to the [changeSet].
418 */ 523 */
419 void _addPreviouslyExcludedSources(_ContextInfo info, ChangeSet changeSet, 524 void _addPreviouslyExcludedSources(ContextInfo info, ChangeSet changeSet,
420 Folder folder, List<String> oldExcludedPaths) { 525 Folder folder, List<String> oldExcludedPaths) {
421 if (info.excludesResource(folder)) { 526 if (info.excludesResource(folder)) {
422 return; 527 return;
423 } 528 }
424 List<Resource> children; 529 List<Resource> children;
425 try { 530 try {
426 children = folder.getChildren(); 531 children = folder.getChildren();
427 } on FileSystemException { 532 } on FileSystemException {
428 // The folder no longer exists, or cannot be read, to there's nothing to 533 // The folder no longer exists, or cannot be read, to there's nothing to
429 // do. 534 // do.
(...skipping 26 matching lines...) Expand all
456 continue; 561 continue;
457 } 562 }
458 _addPreviouslyExcludedSources(info, changeSet, child, oldExcludedPaths); 563 _addPreviouslyExcludedSources(info, changeSet, child, oldExcludedPaths);
459 } 564 }
460 } 565 }
461 } 566 }
462 567
463 /** 568 /**
464 * Resursively adds all Dart and HTML files to the [changeSet]. 569 * Resursively adds all Dart and HTML files to the [changeSet].
465 */ 570 */
466 void _addSourceFiles(ChangeSet changeSet, Folder folder, _ContextInfo info) { 571 void _addSourceFiles(ChangeSet changeSet, Folder folder, ContextInfo info) {
467 if (info.excludesResource(folder) || folder.shortName.startsWith('.')) { 572 if (info.excludesResource(folder) || folder.shortName.startsWith('.')) {
468 return; 573 return;
469 } 574 }
470 List<Resource> children = null; 575 List<Resource> children = null;
471 try { 576 try {
472 children = folder.getChildren(); 577 children = folder.getChildren();
473 } on FileSystemException { 578 } on FileSystemException {
474 // The directory either doesn't exist or cannot be read. Either way, there 579 // The directory either doesn't exist or cannot be read. Either way, there
475 // are no children that need to be added. 580 // are no children that need to be added.
476 return; 581 return;
(...skipping 17 matching lines...) Expand all
494 continue; 599 continue;
495 } 600 }
496 _addSourceFiles(changeSet, child, info); 601 _addSourceFiles(changeSet, child, info);
497 } 602 }
498 } 603 }
499 } 604 }
500 605
501 /** 606 /**
502 * Cancel all dependency subscriptions for the given context. 607 * Cancel all dependency subscriptions for the given context.
503 */ 608 */
504 void _cancelDependencySubscriptions(_ContextInfo info) { 609 void _cancelDependencySubscriptions(ContextInfo info) {
505 for (StreamSubscription<WatchEvent> s in info.dependencySubscriptions) { 610 for (StreamSubscription<WatchEvent> s in info.dependencySubscriptions) {
506 s.cancel(); 611 s.cancel();
507 } 612 }
508 info.dependencySubscriptions.clear(); 613 info.dependencySubscriptions.clear();
509 } 614 }
510 615
511 void _checkForPackagespecUpdate( 616 void _checkForPackagespecUpdate(
512 String path, _ContextInfo info, Folder folder) { 617 String path, ContextInfo info, Folder folder) {
513 // Check to see if this is the .packages file for this context and if so, 618 // Check to see if this is the .packages file for this context and if so,
514 // update the context's source factory. 619 // update the context's source factory.
515 if (pathContext.basename(path) == PACKAGE_SPEC_NAME && 620 if (pathContext.basename(path) == PACKAGE_SPEC_NAME &&
516 info.isPathToPackageDescription(path)) { 621 info.isPathToPackageDescription(path)) {
517 File packagespec = resourceProvider.getFile(path); 622 File packagespec = resourceProvider.getFile(path);
518 if (packagespec.exists) { 623 if (packagespec.exists) {
519 Packages packages = _readPackagespec(packagespec); 624 Packages packages = _readPackagespec(packagespec);
520 if (packages != null) { 625 if (packages != null) {
521 callbacks.updateContextPackageUriResolver(folder, null, packages); 626 callbacks.updateContextPackageUriResolver(folder, null, packages);
522 } 627 }
523 } 628 }
524 } 629 }
525 } 630 }
526 631
527 /** 632 /**
528 * Compute the set of files that are being flushed, this is defined as 633 * Compute the set of files that are being flushed, this is defined as
529 * the set of sources in the removed context (context.sources), that are 634 * the set of sources in the removed context (context.sources), that are
530 * orphaned by this context being removed (no other context includes this 635 * orphaned by this context being removed (no other context includes this
531 * file.) 636 * file.)
532 */ 637 */
533 List<String> _computeFlushedFiles(Folder folder) { 638 List<String> _computeFlushedFiles(Folder folder) {
534 AnalysisContext context = _contexts[folder].context; 639 AnalysisContext context = _contexts[folder].context;
535 HashSet<String> flushedFiles = new HashSet<String>(); 640 HashSet<String> flushedFiles = new HashSet<String>();
536 for (Source source in context.sources) { 641 for (Source source in context.sources) {
537 flushedFiles.add(source.fullName); 642 flushedFiles.add(source.fullName);
538 } 643 }
539 for (_ContextInfo contextInfo in _contexts.values) { 644 for (ContextInfo contextInfo in _contexts.values) {
540 AnalysisContext contextN = contextInfo.context; 645 AnalysisContext contextN = contextInfo.context;
541 if (context != contextN) { 646 if (context != contextN) {
542 for (Source source in contextN.sources) { 647 for (Source source in contextN.sources) {
543 flushedFiles.remove(source.fullName); 648 flushedFiles.remove(source.fullName);
544 } 649 }
545 } 650 }
546 } 651 }
547 return flushedFiles.toList(growable: false); 652 return flushedFiles.toList(growable: false);
548 } 653 }
549 654
550 /** 655 /**
551 * Compute the appropriate package URI resolver for [folder], and store 656 * Compute the appropriate package URI resolver for [folder], and store
552 * dependency information in [info]. Return `null` if no package map can 657 * dependency information in [info]. Return `null` if no package map can
553 * be computed. 658 * be computed.
554 */ 659 */
555 UriResolver _computePackageUriResolver(Folder folder, _ContextInfo info) { 660 UriResolver _computePackageUriResolver(Folder folder, ContextInfo info) {
556 _cancelDependencySubscriptions(info); 661 _cancelDependencySubscriptions(info);
557 if (info.packageRoot != null) { 662 if (info.packageRoot != null) {
558 info.packageMapInfo = null; 663 info.packageMapInfo = null;
559 JavaFile packagesDir = new JavaFile(info.packageRoot); 664 JavaFile packagesDir = new JavaFile(info.packageRoot);
560 Map<String, List<Folder>> packageMap = new Map<String, List<Folder>>(); 665 Map<String, List<Folder>> packageMap = new Map<String, List<Folder>>();
561 if (packagesDir.isDirectory()) { 666 if (packagesDir.isDirectory()) {
562 for (JavaFile file in packagesDir.listFiles()) { 667 for (JavaFile file in packagesDir.listFiles()) {
563 // Ensure symlinks in packages directory are canonicalized 668 // Ensure symlinks in packages directory are canonicalized
564 // to prevent 'type X cannot be assigned to type X' warnings 669 // to prevent 'type X cannot be assigned to type X' warnings
565 String path; 670 String path;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
619 return new PackageMapUriResolver( 724 return new PackageMapUriResolver(
620 resourceProvider, packageMapInfo.packageMap); 725 resourceProvider, packageMapInfo.packageMap);
621 // TODO(paulberry): if any of the dependencies is outside of [folder], 726 // TODO(paulberry): if any of the dependencies is outside of [folder],
622 // we'll need to watch their parent folders as well. 727 // we'll need to watch their parent folders as well.
623 } 728 }
624 } 729 }
625 730
626 /** 731 /**
627 * Create a new empty context associated with [folder]. 732 * Create a new empty context associated with [folder].
628 */ 733 */
629 _ContextInfo _createContext( 734 ContextInfo _createContext(
630 Folder folder, File packagespecFile, List<_ContextInfo> children) { 735 Folder folder, File packagespecFile, List<ContextInfo> children) {
631 _ContextInfo info = new _ContextInfo( 736 ContextInfo info = new ContextInfo(
632 folder, packagespecFile, children, normalizedPackageRoots[folder.path]); 737 folder, packagespecFile, children, normalizedPackageRoots[folder.path]);
633 _contexts[folder] = info; 738 _contexts[folder] = info;
634 var options = analysisOptionsProvider.getOptions(folder); 739 Map<String, YamlNode> options = analysisOptionsProvider.getOptions(folder);
635 processOptionsForContext(folder, options); 740 processOptionsForContext(info, options);
636 info.changeSubscription = folder.changes.listen((WatchEvent event) { 741 info.changeSubscription = folder.changes.listen((WatchEvent event) {
637 _handleWatchEvent(folder, info, event); 742 _handleWatchEvent(folder, info, event);
638 }); 743 });
639 try { 744 try {
640 Packages packages; 745 Packages packages;
641 UriResolver packageUriResolver; 746 UriResolver packageUriResolver;
642 747
643 if (ENABLE_PACKAGESPEC_SUPPORT) { 748 if (ENABLE_PACKAGESPEC_SUPPORT) {
644 // Try .packages first. 749 // Try .packages first.
645 if (pathos.basename(packagespecFile.path) == PACKAGE_SPEC_NAME) { 750 if (pathos.basename(packagespecFile.path) == PACKAGE_SPEC_NAME) {
(...skipping 20 matching lines...) Expand all
666 * 771 *
667 * If there are subfolders with 'pubspec.yaml' files, separate contexts are 772 * If there are subfolders with 'pubspec.yaml' files, separate contexts are
668 * created for them and excluded from the context associated with the 773 * created for them and excluded from the context associated with the
669 * [folder]. 774 * [folder].
670 * 775 *
671 * If [withPackageSpecOnly] is `true`, a context will be created only if there 776 * If [withPackageSpecOnly] is `true`, a context will be created only if there
672 * is a 'pubspec.yaml' or '.packages' file in the [folder]. 777 * is a 'pubspec.yaml' or '.packages' file in the [folder].
673 * 778 *
674 * Returns created contexts. 779 * Returns created contexts.
675 */ 780 */
676 List<_ContextInfo> _createContexts(Folder folder, bool withPackageSpecOnly) { 781 List<ContextInfo> _createContexts(Folder folder, bool withPackageSpecOnly) {
677 // Try to find subfolders with pubspecs or .packages files. 782 // Try to find subfolders with pubspecs or .packages files.
678 List<_ContextInfo> children = <_ContextInfo>[]; 783 List<ContextInfo> children = <ContextInfo>[];
679 try { 784 try {
680 for (Resource child in folder.getChildren()) { 785 for (Resource child in folder.getChildren()) {
681 if (child is Folder) { 786 if (child is Folder) {
682 children.addAll(_createContexts(child, true)); 787 children.addAll(_createContexts(child, true));
683 } 788 }
684 } 789 }
685 } on FileSystemException { 790 } on FileSystemException {
686 // The directory either doesn't exist or cannot be read. Either way, there 791 // The directory either doesn't exist or cannot be read. Either way, there
687 // are no subfolders that need to be added. 792 // are no subfolders that need to be added.
688 } 793 }
689 794
690 File packageSpec; 795 File packageSpec;
691 796
692 if (ENABLE_PACKAGESPEC_SUPPORT) { 797 if (ENABLE_PACKAGESPEC_SUPPORT) {
693 // Start by looking for .packages. 798 // Start by looking for .packages.
694 packageSpec = folder.getChild(PACKAGE_SPEC_NAME); 799 packageSpec = folder.getChild(PACKAGE_SPEC_NAME);
695 } 800 }
696 801
697 // Fall back to looking for a pubspec. 802 // Fall back to looking for a pubspec.
698 if (packageSpec == null || !packageSpec.exists) { 803 if (packageSpec == null || !packageSpec.exists) {
699 packageSpec = folder.getChild(PUBSPEC_NAME); 804 packageSpec = folder.getChild(PUBSPEC_NAME);
700 } 805 }
701 806
702 if (packageSpec.exists) { 807 if (packageSpec.exists) {
703 return <_ContextInfo>[ 808 return <ContextInfo>[
704 _createContextWithSources(folder, packageSpec, children) 809 _createContextWithSources(folder, packageSpec, children)
705 ]; 810 ];
706 } 811 }
707 // No packagespec? Done. 812 // No packagespec? Done.
708 if (withPackageSpecOnly) { 813 if (withPackageSpecOnly) {
709 return children; 814 return children;
710 } 815 }
711 // OK, create a context without a packagespec. 816 // OK, create a context without a packagespec.
712 return <_ContextInfo>[ 817 return <ContextInfo>[
713 _createContextWithSources(folder, packageSpec, children) 818 _createContextWithSources(folder, packageSpec, children)
714 ]; 819 ];
715 } 820 }
716 821
717 /** 822 /**
718 * Create a new context associated with the given [folder]. The [pubspecFile] 823 * Create a new context associated with the given [folder]. The [pubspecFile]
719 * is the `pubspec.yaml` file contained in the folder. Add any sources that 824 * is the `pubspec.yaml` file contained in the folder. Add any sources that
720 * are not included in one of the [children] to the context. 825 * are not included in one of the [children] to the context.
721 */ 826 */
722 _ContextInfo _createContextWithSources( 827 ContextInfo _createContextWithSources(
723 Folder folder, File pubspecFile, List<_ContextInfo> children) { 828 Folder folder, File pubspecFile, List<ContextInfo> children) {
724 _ContextInfo info = _createContext(folder, pubspecFile, children); 829 ContextInfo info = _createContext(folder, pubspecFile, children);
725 ChangeSet changeSet = new ChangeSet(); 830 ChangeSet changeSet = new ChangeSet();
726 _addSourceFiles(changeSet, folder, info); 831 _addSourceFiles(changeSet, folder, info);
727 callbacks.applyChangesToContext(folder, changeSet); 832 callbacks.applyChangesToContext(folder, changeSet);
728 return info; 833 return info;
729 } 834 }
730 835
731 /** 836 /**
732 * Clean up and destroy the context associated with the given folder. 837 * Clean up and destroy the context associated with the given folder.
733 */ 838 */
734 void _destroyContext(Folder folder) { 839 void _destroyContext(Folder folder) {
735 _ContextInfo info = _contexts[folder]; 840 ContextInfo info = _contexts[folder];
736 info.changeSubscription.cancel(); 841 info.changeSubscription.cancel();
737 _cancelDependencySubscriptions(info); 842 _cancelDependencySubscriptions(info);
738 callbacks.removeContext(folder, _computeFlushedFiles(folder)); 843 callbacks.removeContext(folder, _computeFlushedFiles(folder));
739 _contexts.remove(folder); 844 _contexts.remove(folder);
740 } 845 }
741 846
742 /** 847 /**
743 * Extract a new [packagespecFile]-based context from [oldInfo]. 848 * Extract a new [packagespecFile]-based context from [oldInfo].
744 */ 849 */
745 void _extractContext(_ContextInfo oldInfo, File packagespecFile) { 850 void _extractContext(ContextInfo oldInfo, File packagespecFile) {
746 Folder newFolder = packagespecFile.parent; 851 Folder newFolder = packagespecFile.parent;
747 _ContextInfo newInfo = _createContext(newFolder, packagespecFile, []); 852 ContextInfo newInfo = _createContext(newFolder, packagespecFile, []);
748 newInfo.parent = oldInfo; 853 newInfo.parent = oldInfo;
749 // prepare sources to extract 854 // prepare sources to extract
750 Map<String, Source> extractedSources = new HashMap<String, Source>(); 855 Map<String, Source> extractedSources = new HashMap<String, Source>();
751 oldInfo.sources.forEach((path, source) { 856 oldInfo.sources.forEach((path, source) {
752 if (newFolder.contains(path)) { 857 if (newFolder.contains(path)) {
753 extractedSources[path] = source; 858 extractedSources[path] = source;
754 } 859 }
755 }); 860 });
756 // update new context 861 // update new context
757 { 862 {
758 ChangeSet changeSet = new ChangeSet(); 863 ChangeSet changeSet = new ChangeSet();
759 extractedSources.forEach((path, source) { 864 extractedSources.forEach((path, source) {
760 newInfo.sources[path] = source; 865 newInfo.sources[path] = source;
761 changeSet.addedSource(source); 866 changeSet.addedSource(source);
762 }); 867 });
763 callbacks.applyChangesToContext(newFolder, changeSet); 868 callbacks.applyChangesToContext(newFolder, changeSet);
764 } 869 }
765 // update old context 870 // update old context
766 { 871 {
767 ChangeSet changeSet = new ChangeSet(); 872 ChangeSet changeSet = new ChangeSet();
768 extractedSources.forEach((path, source) { 873 extractedSources.forEach((path, source) {
769 oldInfo.sources.remove(path); 874 oldInfo.sources.remove(path);
770 changeSet.removedSource(source); 875 changeSet.removedSource(source);
771 }); 876 });
772 callbacks.applyChangesToContext(oldInfo.folder, changeSet); 877 callbacks.applyChangesToContext(oldInfo.folder, changeSet);
773 } 878 }
774 } 879 }
775 880
776 void _handleWatchEvent(Folder folder, _ContextInfo info, WatchEvent event) { 881 void _handleWatchEvent(Folder folder, ContextInfo info, WatchEvent event) {
777 // TODO(brianwilkerson) If a file is explicitly included in one context 882 // TODO(brianwilkerson) If a file is explicitly included in one context
778 // but implicitly referenced in another context, we will only send a 883 // but implicitly referenced in another context, we will only send a
779 // changeSet to the context that explicitly includes the file (because 884 // changeSet to the context that explicitly includes the file (because
780 // that's the only context that's watching the file). 885 // that's the only context that's watching the file).
781 _instrumentationService.logWatchEvent( 886 _instrumentationService.logWatchEvent(
782 folder.path, event.path, event.type.toString()); 887 folder.path, event.path, event.type.toString());
783 String path = event.path; 888 String path = event.path;
784 // maybe excluded globally 889 // maybe excluded globally
785 if (_isExcluded(path)) { 890 if (_isExcluded(path)) {
786 return; 891 return;
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
947 } 1052 }
948 1053
949 bool _isPackagespec(String path) => 1054 bool _isPackagespec(String path) =>
950 pathContext.basename(path) == PACKAGE_SPEC_NAME; 1055 pathContext.basename(path) == PACKAGE_SPEC_NAME;
951 1056
952 bool _isPubspec(String path) => pathContext.basename(path) == PUBSPEC_NAME; 1057 bool _isPubspec(String path) => pathContext.basename(path) == PUBSPEC_NAME;
953 1058
954 /** 1059 /**
955 * Merges [info] context into its parent. 1060 * Merges [info] context into its parent.
956 */ 1061 */
957 void _mergeContext(_ContextInfo info) { 1062 void _mergeContext(ContextInfo info) {
958 // destroy the context 1063 // destroy the context
959 _destroyContext(info.folder); 1064 _destroyContext(info.folder);
960 // add files to the parent context 1065 // add files to the parent context
961 _ContextInfo parentInfo = info.parent; 1066 ContextInfo parentInfo = info.parent;
962 if (parentInfo != null) { 1067 if (parentInfo != null) {
963 parentInfo.children.remove(info); 1068 parentInfo.children.remove(info);
964 ChangeSet changeSet = new ChangeSet(); 1069 ChangeSet changeSet = new ChangeSet();
965 info.sources.forEach((path, source) { 1070 info.sources.forEach((path, source) {
966 parentInfo.sources[path] = source; 1071 parentInfo.sources[path] = source;
967 changeSet.addedSource(source); 1072 changeSet.addedSource(source);
968 }); 1073 });
969 callbacks.applyChangesToContext(parentInfo.folder, changeSet); 1074 callbacks.applyChangesToContext(parentInfo.folder, changeSet);
970 } 1075 }
971 } 1076 }
972 1077
973 Packages _readPackagespec(File specFile) { 1078 Packages _readPackagespec(File specFile) {
974 try { 1079 try {
975 String contents = specFile.readAsStringSync(); 1080 String contents = specFile.readAsStringSync();
976 Map<String, Uri> map = 1081 Map<String, Uri> map =
977 pkgfile.parse(UTF8.encode(contents), new Uri.file(specFile.path)); 1082 pkgfile.parse(UTF8.encode(contents), new Uri.file(specFile.path));
978 return new MapPackages(map); 1083 return new MapPackages(map);
979 } catch (_) { 1084 } catch (_) {
980 //TODO(pquitslund): consider creating an error for the spec file. 1085 //TODO(pquitslund): consider creating an error for the spec file.
981 return null; 1086 return null;
982 } 1087 }
983 } 1088 }
984 1089
985 /** 1090 /**
986 * Recompute the package URI resolver for the context described by [info], 1091 * Recompute the package URI resolver for the context described by [info],
987 * and update the client appropriately. 1092 * and update the client appropriately.
988 */ 1093 */
989 void _recomputePackageUriResolver(_ContextInfo info) { 1094 void _recomputePackageUriResolver(ContextInfo info) {
990 // TODO(paulberry): when computePackageMap is changed into an 1095 // TODO(paulberry): when computePackageMap is changed into an
991 // asynchronous API call, we'll want to suspend analysis for this context 1096 // asynchronous API call, we'll want to suspend analysis for this context
992 // while we're rerunning "pub list", since any analysis we complete while 1097 // while we're rerunning "pub list", since any analysis we complete while
993 // "pub list" is in progress is just going to get thrown away anyhow. 1098 // "pub list" is in progress is just going to get thrown away anyhow.
994 UriResolver packageUriResolver = 1099 UriResolver packageUriResolver =
995 _computePackageUriResolver(info.folder, info); 1100 _computePackageUriResolver(info.folder, info);
996 callbacks.updateContextPackageUriResolver( 1101 callbacks.updateContextPackageUriResolver(
997 info.folder, packageUriResolver, null); 1102 info.folder, packageUriResolver, null);
998 } 1103 }
999 1104
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1037 */ 1142 */
1038 final List<AnalysisContext> removed; 1143 final List<AnalysisContext> removed;
1039 1144
1040 /** 1145 /**
1041 * Initialize a newly created event to indicate which contexts have changed. 1146 * Initialize a newly created event to indicate which contexts have changed.
1042 */ 1147 */
1043 ContextsChangedEvent({this.added: AnalysisContext.EMPTY_LIST, 1148 ContextsChangedEvent({this.added: AnalysisContext.EMPTY_LIST,
1044 this.changed: AnalysisContext.EMPTY_LIST, 1149 this.changed: AnalysisContext.EMPTY_LIST,
1045 this.removed: AnalysisContext.EMPTY_LIST}); 1150 this.removed: AnalysisContext.EMPTY_LIST});
1046 } 1151 }
1047
1048 /**
1049 * Information tracked by the [ContextManager] for each context.
1050 */
1051 class _ContextInfo {
1052 /**
1053 * The [Folder] for which this information object is created.
1054 */
1055 final Folder folder;
1056
1057 /// The [PathFilter] used to filter sources from being analyzed.
1058 final PathFilter pathFilter;
1059
1060 /**
1061 * The enclosed pubspec-based contexts.
1062 */
1063 final List<_ContextInfo> children;
1064
1065 /**
1066 * The package root for this context, or null if there is no package root.
1067 */
1068 String packageRoot;
1069
1070 /**
1071 * The [_ContextInfo] that encloses this one.
1072 */
1073 _ContextInfo parent;
1074
1075 /**
1076 * The package description file path for this context.
1077 */
1078 String packageDescriptionPath;
1079
1080 /**
1081 * Stream subscription we are using to watch the context's directory for
1082 * changes.
1083 */
1084 StreamSubscription<WatchEvent> changeSubscription;
1085
1086 /**
1087 * Stream subscriptions we are using to watch the files
1088 * used to determine the package map.
1089 */
1090 final List<StreamSubscription<WatchEvent>> dependencySubscriptions =
1091 <StreamSubscription<WatchEvent>>[];
1092
1093 /**
1094 * The analysis context that was created for the [folder].
1095 */
1096 AnalysisContext context;
1097
1098 /**
1099 * Map from full path to the [Source] object, for each source that has been
1100 * added to the context.
1101 */
1102 Map<String, Source> sources = new HashMap<String, Source>();
1103
1104 /**
1105 * Info returned by the last call to
1106 * [OptimizingPubPackageMapProvider.computePackageMap], or `null` if the
1107 * package map hasn't been computed for this context yet.
1108 */
1109 OptimizingPubPackageMapInfo packageMapInfo;
1110
1111 _ContextInfo(
1112 Folder folder, File packagespecFile, this.children, this.packageRoot)
1113 : folder = folder,
1114 pathFilter = new PathFilter(folder.path, null) {
1115 packageDescriptionPath = packagespecFile.path;
1116 for (_ContextInfo child in children) {
1117 child.parent = this;
1118 }
1119 }
1120
1121 /**
1122 * Returns `true` if this context is root folder based.
1123 */
1124 bool get isRoot => parent == null;
1125
1126 /**
1127 * Returns `true` if [path] is excluded, as it is in one of the children.
1128 */
1129 bool excludes(String path) {
1130 return children.any((child) {
1131 return child.folder.contains(path);
1132 });
1133 }
1134
1135 /**
1136 * Returns `true` if [resource] is excluded, as it is in one of the children.
1137 */
1138 bool excludesResource(Resource resource) => excludes(resource.path);
1139
1140 /// Returns `true` if [path] should be ignored.
1141 bool ignored(String path) => pathFilter.ignored(path);
1142
1143 /**
1144 * Returns `true` if [path] is the package description file for this context
1145 * (pubspec.yaml or .packages).
1146 */
1147 bool isPathToPackageDescription(String path) =>
1148 path == packageDescriptionPath;
1149 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analysis_server/test/context_manager_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698