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

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: More merging/nits. 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/analysis_options_provider.dart'; 17 import 'package:analyzer/source/analysis_options_provider.dart';
17 import 'package:analyzer/source/package_map_resolver.dart'; 18 import 'package:analyzer/source/package_map_resolver.dart';
18 import 'package:analyzer/source/path_filter.dart'; 19 import 'package:analyzer/source/path_filter.dart';
19 import 'package:analyzer/src/generated/engine.dart'; 20 import 'package:analyzer/src/generated/engine.dart';
20 import 'package:analyzer/src/generated/java_io.dart'; 21 import 'package:analyzer/src/generated/java_io.dart';
21 import 'package:analyzer/src/generated/source.dart'; 22 import 'package:analyzer/src/generated/source.dart';
22 import 'package:analyzer/src/generated/source_io.dart'; 23 import 'package:analyzer/src/generated/source_io.dart';
24 import 'package:package_config/packages.dart';
25 import 'package:package_config/packages_file.dart' as pkgfile show parse;
26 import 'package:package_config/src/packages_impl.dart' show MapPackages;
23 import 'package:path/path.dart' as pathos; 27 import 'package:path/path.dart' as pathos;
24 import 'package:watcher/watcher.dart'; 28 import 'package:watcher/watcher.dart';
25 import 'package:yaml/yaml.dart'; 29 import 'package:yaml/yaml.dart';
26 30
27 /** 31 /**
28 * Class that maintains a mapping from included/excluded paths to a set of 32 * Class that maintains a mapping from included/excluded paths to a set of
29 * folders that should correspond to analysis contexts. 33 * folders that should correspond to analysis contexts.
30 */ 34 */
31 abstract class AbstractContextManager implements ContextManager { 35 abstract class AbstractContextManager implements ContextManager {
36
37 /**
38 * Temporary flag to hide WIP .packages support (DEP 5).
39 */
40 static bool ENABLE_PACKAGESPEC_SUPPORT = false;
41
32 /** 42 /**
33 * The name of the `lib` directory. 43 * The name of the `lib` directory.
34 */ 44 */
35 static const String LIB_DIR_NAME = 'lib'; 45 static const String LIB_DIR_NAME = 'lib';
36 46
37 /** 47 /**
38 * The name of `packages` folders. 48 * The name of `packages` folders.
39 */ 49 */
40 static const String PACKAGES_NAME = 'packages'; 50 static const String PACKAGES_NAME = 'packages';
41 51
42 /** 52 /**
43 * File name of pubspec files. 53 * File name of pubspec files.
44 */ 54 */
45 static const String PUBSPEC_NAME = 'pubspec.yaml'; 55 static const String PUBSPEC_NAME = 'pubspec.yaml';
46 56
47 /** 57 /**
58 * File name of package spec files.
59 */
60 static const String PACKAGE_SPEC_NAME = '.packages';
61
62 /**
48 * [_ContextInfo] object for each included directory in the most 63 * [_ContextInfo] object for each included directory in the most
49 * recent successful call to [setRoots]. 64 * recent successful call to [setRoots].
50 */ 65 */
51 Map<Folder, _ContextInfo> _contexts = new HashMap<Folder, _ContextInfo>(); 66 Map<Folder, _ContextInfo> _contexts = new HashMap<Folder, _ContextInfo>();
52 67
53 /** 68 /**
54 * The [ResourceProvider] using which paths are converted into [Resource]s. 69 * The [ResourceProvider] using which paths are converted into [Resource]s.
55 */ 70 */
56 final ResourceProvider resourceProvider; 71 final ResourceProvider resourceProvider;
57 72
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
106 final InstrumentationService _instrumentationService; 121 final InstrumentationService _instrumentationService;
107 122
108 AbstractContextManager(this.resourceProvider, this.packageResolverProvider, 123 AbstractContextManager(this.resourceProvider, this.packageResolverProvider,
109 this._packageMapProvider, this._instrumentationService) { 124 this._packageMapProvider, this._instrumentationService) {
110 pathContext = resourceProvider.pathContext; 125 pathContext = resourceProvider.pathContext;
111 } 126 }
112 127
113 /** 128 /**
114 * Create and return a new analysis context. 129 * Create and return a new analysis context.
115 */ 130 */
116 AnalysisContext addContext(Folder folder, UriResolver packageUriResolver); 131 AnalysisContext addContext(
132 Folder folder, UriResolver packageUriResolver, Packages packages);
117 133
118 /** 134 /**
119 * Called when the set of files associated with a context have changed (or 135 * Called when the set of files associated with a context have changed (or
120 * some of those files have been modified). [changeSet] is the set of 136 * some of those files have been modified). [changeSet] is the set of
121 * changes that need to be applied to the context. 137 * changes that need to be applied to the context.
122 */ 138 */
123 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet); 139 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet);
124 140
125 /** 141 /**
126 * We are about to start computing the package map. 142 * We are about to start computing the package map.
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 return contexts; 179 return contexts;
164 } 180 }
165 181
166 /** 182 /**
167 * We have finished computing the package map. 183 * We have finished computing the package map.
168 */ 184 */
169 void endComputePackageMap() { 185 void endComputePackageMap() {
170 // Do nothing. 186 // Do nothing.
171 } 187 }
172 188
173 /// Sets the [ignorePatterns] for the context [folder]. 189 @override
174 void setIgnorePatternsForContext(Folder folder, List<String> ignorePatterns) { 190 bool isInAnalysisRoot(String path) {
175 _ContextInfo info = _contexts[folder]; 191 // check if excluded
176 if (info == null) { 192 if (_isExcluded(path)) {
177 return; 193 return false;
178 } 194 }
179 var pathFilter = info.pathFilter; 195 // check if in of the roots
180 pathFilter.setIgnorePatterns(ignorePatterns); 196 for (Folder root in _contexts.keys) {
197 if (root.contains(path)) {
198 return true;
199 }
200 }
201 // no
202 return false;
181 } 203 }
182 204
183 /// Process [options] for the context [folder]. 205 /// Process [options] for the context [folder].
184 void processOptionsForContext(Folder folder, Map<String, YamlNode> options) { 206 void processOptionsForContext(Folder folder, Map<String, YamlNode> options) {
185 _ContextInfo info = _contexts[folder]; 207 _ContextInfo info = _contexts[folder];
186 if (info == null) { 208 if (info == null) {
187 return; 209 return;
188 } 210 }
189 YamlMap analyzer = options['analyzer']; 211 YamlMap analyzer = options['analyzer'];
190 if (analyzer == null) { 212 if (analyzer == null) {
191 // No options for analyzer. 213 // No options for analyzer.
192 return; 214 return;
193 } 215 }
194 216
195 // Set ignore patterns. 217 // Set ignore patterns.
196 YamlList exclude = analyzer['exclude']; 218 YamlList exclude = analyzer['exclude'];
197 if (exclude != null) { 219 if (exclude != null) {
198 setIgnorePatternsForContext(folder, exclude); 220 setIgnorePatternsForContext(folder, exclude);
199 } 221 }
200 } 222 }
201 223
202 @override 224 @override
203 bool isInAnalysisRoot(String path) {
204 // check if excluded
205 if (_isExcluded(path)) {
206 return false;
207 }
208 // check if in of the roots
209 for (Folder root in _contexts.keys) {
210 if (root.contains(path)) {
211 return true;
212 }
213 }
214 // no
215 return false;
216 }
217
218 @override
219 void refresh(List<Resource> roots) { 225 void refresh(List<Resource> roots) {
220 // Destroy old contexts 226 // Destroy old contexts
221 List<Folder> contextFolders = _contexts.keys.toList(); 227 List<Folder> contextFolders = _contexts.keys.toList();
222 if (roots == null) { 228 if (roots == null) {
223 contextFolders.forEach(_destroyContext); 229 contextFolders.forEach(_destroyContext);
224 } else { 230 } else {
225 roots.forEach((Resource resource) { 231 roots.forEach((Resource resource) {
226 contextFolders.forEach((Folder contextFolder) { 232 contextFolders.forEach((Folder contextFolder) {
227 if (resource is Folder && resource.isOrContains(contextFolder.path)) { 233 if (resource is Folder && resource.isOrContains(contextFolder.path)) {
228 _destroyContext(contextFolder); 234 _destroyContext(contextFolder);
229 } 235 }
230 }); 236 });
231 }); 237 });
232 } 238 }
233 239
234 // Rebuild contexts based on the data last sent to setRoots(). 240 // Rebuild contexts based on the data last sent to setRoots().
235 setRoots(includedPaths, excludedPaths, packageRoots); 241 setRoots(includedPaths, excludedPaths, packageRoots);
236 } 242 }
237 243
238 /** 244 /**
239 * Remove the context associated with the given [folder]. 245 * Remove the context associated with the given [folder].
240 */ 246 */
241 void removeContext(Folder folder); 247 void removeContext(Folder folder);
242 248
249 /// Sets the [ignorePatterns] for the context [folder].
250 void setIgnorePatternsForContext(Folder folder, List<String> ignorePatterns) {
251 _ContextInfo info = _contexts[folder];
252 if (info == null) {
253 return;
254 }
255 var pathFilter = info.pathFilter;
256 pathFilter.setIgnorePatterns(ignorePatterns);
257 }
258
243 @override 259 @override
244 void setRoots(List<String> includedPaths, List<String> excludedPaths, 260 void setRoots(List<String> includedPaths, List<String> excludedPaths,
245 Map<String, String> packageRoots) { 261 Map<String, String> packageRoots) {
246 this.packageRoots = packageRoots; 262 this.packageRoots = packageRoots;
247 263
248 // Normalize all package root sources by mapping them to folders on the 264 // Normalize all package root sources by mapping them to folders on the
249 // filesystem. Ignore any package root sources that aren't folders. 265 // filesystem. Ignore any package root sources that aren't folders.
250 normalizedPackageRoots = <String, String>{}; 266 normalizedPackageRoots = <String, String>{};
251 packageRoots.forEach((String sourcePath, String targetPath) { 267 packageRoots.forEach((String sourcePath, String targetPath) {
252 Resource resource = resourceProvider.getResource(sourcePath); 268 Resource resource = resourceProvider.getResource(sourcePath);
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
327 343
328 /** 344 /**
329 * Return `true` if the given [file] should be analyzed. 345 * Return `true` if the given [file] should be analyzed.
330 */ 346 */
331 bool shouldFileBeAnalyzed(File file); 347 bool shouldFileBeAnalyzed(File file);
332 348
333 /** 349 /**
334 * Called when the package map for a context has changed. 350 * Called when the package map for a context has changed.
335 */ 351 */
336 void updateContextPackageUriResolver( 352 void updateContextPackageUriResolver(
337 Folder contextFolder, UriResolver packageUriResolver); 353 Folder contextFolder, UriResolver packageUriResolver, Packages packages);
338 354
339 /** 355 /**
340 * Resursively adds all Dart and HTML files to the [changeSet]. 356 * Resursively adds all Dart and HTML files to the [changeSet].
341 */ 357 */
342 void _addPreviouslyExcludedSources(_ContextInfo info, ChangeSet changeSet, 358 void _addPreviouslyExcludedSources(_ContextInfo info, ChangeSet changeSet,
343 Folder folder, List<String> oldExcludedPaths) { 359 Folder folder, List<String> oldExcludedPaths) {
344 if (info.excludesResource(folder)) { 360 if (info.excludesResource(folder)) {
345 return; 361 return;
346 } 362 }
347 List<Resource> children; 363 List<Resource> children;
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
424 /** 440 /**
425 * Cancel all dependency subscriptions for the given context. 441 * Cancel all dependency subscriptions for the given context.
426 */ 442 */
427 void _cancelDependencySubscriptions(_ContextInfo info) { 443 void _cancelDependencySubscriptions(_ContextInfo info) {
428 for (StreamSubscription<WatchEvent> s in info.dependencySubscriptions) { 444 for (StreamSubscription<WatchEvent> s in info.dependencySubscriptions) {
429 s.cancel(); 445 s.cancel();
430 } 446 }
431 info.dependencySubscriptions.clear(); 447 info.dependencySubscriptions.clear();
432 } 448 }
433 449
450 void _checkForPackagespecUpdate(
451 String path, _ContextInfo info, Folder folder) {
452 // Check to see if this is the .packages file for this context and if so,
453 // update the context's source factory.
454 if (pathContext.basename(path) == PACKAGE_SPEC_NAME &&
455 info.isPathToPackageDescription(path)) {
456 File packagespec = resourceProvider.getFile(path);
457 if (packagespec.exists) {
458 Packages packages = _readPackagespec(packagespec);
459 if (packages != null) {
460 updateContextPackageUriResolver(folder, null, packages);
461 }
462 }
463 }
464 }
465
434 /** 466 /**
435 * Compute the appropriate package URI resolver for [folder], and store 467 * Compute the appropriate package URI resolver for [folder], and store
436 * dependency information in [info]. Return `null` if no package map can 468 * dependency information in [info]. Return `null` if no package map can
437 * be computed. 469 * be computed.
438 */ 470 */
439 UriResolver _computePackageUriResolver(Folder folder, _ContextInfo info) { 471 UriResolver _computePackageUriResolver(Folder folder, _ContextInfo info) {
440 _cancelDependencySubscriptions(info); 472 _cancelDependencySubscriptions(info);
441 if (info.packageRoot != null) { 473 if (info.packageRoot != null) {
442 info.packageMapInfo = null; 474 info.packageMapInfo = null;
443 JavaFile packagesDir = new JavaFile(info.packageRoot); 475 JavaFile packagesDir = new JavaFile(info.packageRoot);
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
504 resourceProvider, packageMapInfo.packageMap); 536 resourceProvider, packageMapInfo.packageMap);
505 // TODO(paulberry): if any of the dependencies is outside of [folder], 537 // TODO(paulberry): if any of the dependencies is outside of [folder],
506 // we'll need to watch their parent folders as well. 538 // we'll need to watch their parent folders as well.
507 } 539 }
508 } 540 }
509 541
510 /** 542 /**
511 * Create a new empty context associated with [folder]. 543 * Create a new empty context associated with [folder].
512 */ 544 */
513 _ContextInfo _createContext( 545 _ContextInfo _createContext(
514 Folder folder, File pubspecFile, List<_ContextInfo> children) { 546 Folder folder, File packagespecFile, List<_ContextInfo> children) {
515 _ContextInfo info = new _ContextInfo( 547 _ContextInfo info = new _ContextInfo(
516 folder, pubspecFile, children, normalizedPackageRoots[folder.path]); 548 folder, packagespecFile, children, normalizedPackageRoots[folder.path]);
517 _contexts[folder] = info; 549 _contexts[folder] = info;
518 var options = analysisOptionsProvider.getOptions(folder); 550 var options = analysisOptionsProvider.getOptions(folder);
519 processOptionsForContext(folder, options); 551 processOptionsForContext(folder, options);
520 info.changeSubscription = folder.changes.listen((WatchEvent event) { 552 info.changeSubscription = folder.changes.listen((WatchEvent event) {
521 _handleWatchEvent(folder, info, event); 553 _handleWatchEvent(folder, info, event);
522 }); 554 });
523 try { 555 try {
524 UriResolver packageUriResolver = _computePackageUriResolver(folder, info); 556 Packages packages;
525 info.context = addContext(folder, packageUriResolver); 557 UriResolver packageUriResolver;
558
559 if (ENABLE_PACKAGESPEC_SUPPORT) {
560 // Try .packages first.
561 if (pathos.basename(packagespecFile.path) == PACKAGE_SPEC_NAME) {
562 packages = _readPackagespec(packagespecFile);
563 }
564 }
565
566 // Next resort to a package uri resolver.
567 if (packages == null) {
568 packageUriResolver = _computePackageUriResolver(folder, info);
569 }
570
571 info.context = addContext(folder, packageUriResolver, packages);
526 info.context.name = folder.path; 572 info.context.name = folder.path;
527 } catch (_) { 573 } catch (_) {
528 info.changeSubscription.cancel(); 574 info.changeSubscription.cancel();
529 rethrow; 575 rethrow;
530 } 576 }
531 return info; 577 return info;
532 } 578 }
533 579
534 /** 580 /**
535 * Potentially create a new context associated with the given [folder]. 581 * Potentially create a new context associated with the given [folder].
536 * 582 *
537 * If there are subfolders with 'pubspec.yaml' files, separate contexts are 583 * If there are subfolders with 'pubspec.yaml' files, separate contexts are
538 * created for them and excluded from the context associated with the 584 * created for them and excluded from the context associated with the
539 * [folder]. 585 * [folder].
540 * 586 *
541 * If [withPubspecOnly] is `true`, a context will be created only if there 587 * If [withPackageSpecOnly] is `true`, a context will be created only if there
542 * is a 'pubspec.yaml' file in the [folder]. 588 * is a 'pubspec.yaml' or '.packages' file in the [folder].
543 * 589 *
544 * Returns create pubspec-based contexts. 590 * Returns created contexts.
545 */ 591 */
546 List<_ContextInfo> _createContexts(Folder folder, bool withPubspecOnly) { 592 List<_ContextInfo> _createContexts(Folder folder, bool withPackageSpecOnly) {
547 // try to find subfolders with pubspec files 593 // Try to find subfolders with pubspecs or .packages files.
548 List<_ContextInfo> children = <_ContextInfo>[]; 594 List<_ContextInfo> children = <_ContextInfo>[];
549 try { 595 try {
550 for (Resource child in folder.getChildren()) { 596 for (Resource child in folder.getChildren()) {
551 if (child is Folder) { 597 if (child is Folder) {
552 children.addAll(_createContexts(child, true)); 598 children.addAll(_createContexts(child, true));
553 } 599 }
554 } 600 }
555 } on FileSystemException { 601 } on FileSystemException {
556 // The directory either doesn't exist or cannot be read. Either way, there 602 // The directory either doesn't exist or cannot be read. Either way, there
557 // are no subfolders that need to be added. 603 // are no subfolders that need to be added.
558 } 604 }
559 // check whether there is a pubspec in the folder 605
560 File pubspecFile = folder.getChild(PUBSPEC_NAME); 606 File packageSpec;
561 if (pubspecFile.exists) { 607
608 if (ENABLE_PACKAGESPEC_SUPPORT) {
609 // Start by looking for .packages.
610 packageSpec = folder.getChild(PACKAGE_SPEC_NAME);
611 }
612
613 // Fall back to looking for a pubspec.
614 if (packageSpec == null || !packageSpec.exists) {
615 packageSpec = folder.getChild(PUBSPEC_NAME);
616 }
617
618 if (packageSpec.exists) {
562 return <_ContextInfo>[ 619 return <_ContextInfo>[
563 _createContextWithSources(folder, pubspecFile, children) 620 _createContextWithSources(folder, packageSpec, children)
564 ]; 621 ];
565 } 622 }
566 // no pubspec, done 623 // No packagespec? Done.
567 if (withPubspecOnly) { 624 if (withPackageSpecOnly) {
568 return children; 625 return children;
569 } 626 }
570 // OK, create a context without a pubspec 627 // OK, create a context without a packagespec.
571 return <_ContextInfo>[ 628 return <_ContextInfo>[
572 _createContextWithSources(folder, pubspecFile, children) 629 _createContextWithSources(folder, packageSpec, children)
573 ]; 630 ];
574 } 631 }
575 632
576 /** 633 /**
577 * Create a new context associated with the given [folder]. The [pubspecFile] 634 * Create a new context associated with the given [folder]. The [pubspecFile]
578 * is the `pubspec.yaml` file contained in the folder. Add any sources that 635 * is the `pubspec.yaml` file contained in the folder. Add any sources that
579 * are not included in one of the [children] to the context. 636 * are not included in one of the [children] to the context.
580 */ 637 */
581 _ContextInfo _createContextWithSources( 638 _ContextInfo _createContextWithSources(
582 Folder folder, File pubspecFile, List<_ContextInfo> children) { 639 Folder folder, File pubspecFile, List<_ContextInfo> children) {
583 _ContextInfo info = _createContext(folder, pubspecFile, children); 640 _ContextInfo info = _createContext(folder, pubspecFile, children);
584 ChangeSet changeSet = new ChangeSet(); 641 ChangeSet changeSet = new ChangeSet();
585 _addSourceFiles(changeSet, folder, info); 642 _addSourceFiles(changeSet, folder, info);
586 applyChangesToContext(folder, changeSet); 643 applyChangesToContext(folder, changeSet);
587 return info; 644 return info;
588 } 645 }
589 646
590 /** 647 /**
591 * Clean up and destroy the context associated with the given folder. 648 * Clean up and destroy the context associated with the given folder.
592 */ 649 */
593 void _destroyContext(Folder folder) { 650 void _destroyContext(Folder folder) {
594 _ContextInfo info = _contexts[folder]; 651 _ContextInfo info = _contexts[folder];
595 info.changeSubscription.cancel(); 652 info.changeSubscription.cancel();
596 _cancelDependencySubscriptions(info); 653 _cancelDependencySubscriptions(info);
597 removeContext(folder); 654 removeContext(folder);
598 _contexts.remove(folder); 655 _contexts.remove(folder);
599 } 656 }
600 657
601 /** 658 /**
602 * Extract a new [pubspecFile]-based context from [oldInfo]. 659 * Extract a new [packagespecFile]-based context from [oldInfo].
603 */ 660 */
604 void _extractContext(_ContextInfo oldInfo, File pubspecFile) { 661 void _extractContext(_ContextInfo oldInfo, File packagespecFile) {
605 Folder newFolder = pubspecFile.parent; 662 Folder newFolder = packagespecFile.parent;
606 _ContextInfo newInfo = _createContext(newFolder, pubspecFile, []); 663 _ContextInfo newInfo = _createContext(newFolder, packagespecFile, []);
607 newInfo.parent = oldInfo; 664 newInfo.parent = oldInfo;
608 // prepare sources to extract 665 // prepare sources to extract
609 Map<String, Source> extractedSources = new HashMap<String, Source>(); 666 Map<String, Source> extractedSources = new HashMap<String, Source>();
610 oldInfo.sources.forEach((path, source) { 667 oldInfo.sources.forEach((path, source) {
611 if (newFolder.contains(path)) { 668 if (newFolder.contains(path)) {
612 extractedSources[path] = source; 669 extractedSources[path] = source;
613 } 670 }
614 }); 671 });
615 // update new context 672 // update new context
616 { 673 {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
650 } 707 }
651 if (info.ignored(path)) { 708 if (info.ignored(path)) {
652 return; 709 return;
653 } 710 }
654 // handle the change 711 // handle the change
655 switch (event.type) { 712 switch (event.type) {
656 case ChangeType.ADD: 713 case ChangeType.ADD:
657 if (_isInPackagesDir(path, folder)) { 714 if (_isInPackagesDir(path, folder)) {
658 return; 715 return;
659 } 716 }
717
660 Resource resource = resourceProvider.getResource(path); 718 Resource resource = resourceProvider.getResource(path);
661 // pubspec was added in a sub-folder, extract a new context 719
662 if (_isPubspec(path) && info.isRoot && !info.isPubspec(path)) { 720 if (ENABLE_PACKAGESPEC_SUPPORT) {
663 _extractContext(info, resource); 721 String directoryPath = pathContext.dirname(path);
664 return; 722
723 // Check to see if we need to create a new context.
724 if (info.isRoot) {
725
726 // Only create a new context if this is not the same directory
727 // described by our info object.
728 if (info.folder.path != directoryPath) {
729 if (_isPubspec(path)) {
730 // Check for a sibling .packages file.
731 if (!resourceProvider.getFile(
732 pathos.join(directoryPath, PACKAGE_SPEC_NAME)).exists) {
733 _extractContext(info, resource);
734 return;
735 }
736 }
737 if (_isPackagespec(path)) {
738 // Check for a sibling pubspec.yaml file.
739 if (!resourceProvider
740 .getFile(pathos.join(directoryPath, PUBSPEC_NAME)).exists) {
741 _extractContext(info, resource);
742 return;
743 }
744 }
745 }
746 }
747 } else {
748 // pubspec was added in a sub-folder, extract a new context
749 if (_isPubspec(path) &&
750 info.isRoot &&
751 !info.isPathToPackageDescription(path)) {
752 _extractContext(info, resource);
753 return;
754 }
665 } 755 }
756
666 // If the file went away and was replaced by a folder before we 757 // If the file went away and was replaced by a folder before we
667 // had a chance to process the event, resource might be a Folder. In 758 // had a chance to process the event, resource might be a Folder. In
668 // that case don't add it. 759 // that case don't add it.
669 if (resource is File) { 760 if (resource is File) {
670 File file = resource; 761 File file = resource;
671 if (shouldFileBeAnalyzed(file)) { 762 if (shouldFileBeAnalyzed(file)) {
672 ChangeSet changeSet = new ChangeSet(); 763 ChangeSet changeSet = new ChangeSet();
673 Source source = createSourceInContext(info.context, file); 764 Source source = createSourceInContext(info.context, file);
674 changeSet.addedSource(source); 765 changeSet.addedSource(source);
675 applyChangesToContext(folder, changeSet); 766 applyChangesToContext(folder, changeSet);
676 info.sources[path] = source; 767 info.sources[path] = source;
677 } 768 }
678 } 769 }
679 break; 770 break;
680 case ChangeType.REMOVE: 771 case ChangeType.REMOVE:
681 // pubspec was removed, merge the context into its parent 772
682 if (info.isPubspec(path) && !info.isRoot) { 773 // If package spec info is removed, check to see if we can merge context s.
683 _mergeContext(info); 774 // Note that it's important to verify that there is NEITHER a .packages nor a
684 return; 775 // lingering pubspec.yaml before merging.
776 if (!info.isRoot) {
777 if (ENABLE_PACKAGESPEC_SUPPORT) {
778 String directoryPath = pathContext.dirname(path);
779
780 // Only merge if this is the same directory described by our info ob ject.
781 if (info.folder.path == directoryPath) {
782 if (_isPubspec(path)) {
783 // Check for a sibling .packages file.
784 if (!resourceProvider.getFile(
785 pathos.join(directoryPath, PACKAGE_SPEC_NAME)).exists) {
786 _mergeContext(info);
787 return;
788 }
789 }
790 if (_isPackagespec(path)) {
791 // Check for a sibling pubspec.yaml file.
792 if (!resourceProvider
793 .getFile(pathos.join(directoryPath, PUBSPEC_NAME)).exists) {
794 _mergeContext(info);
795 return;
796 }
797 }
798 }
799 } else {
800 if (info.isPathToPackageDescription(path)) {
801 _mergeContext(info);
802 return;
803 }
804 }
685 } 805 }
806
686 List<Source> sources = info.context.getSourcesWithFullName(path); 807 List<Source> sources = info.context.getSourcesWithFullName(path);
687 if (!sources.isEmpty) { 808 if (!sources.isEmpty) {
688 ChangeSet changeSet = new ChangeSet(); 809 ChangeSet changeSet = new ChangeSet();
689 sources.forEach((Source source) { 810 sources.forEach((Source source) {
690 changeSet.removedSource(source); 811 changeSet.removedSource(source);
691 }); 812 });
692 applyChangesToContext(folder, changeSet); 813 applyChangesToContext(folder, changeSet);
693 info.sources.remove(path); 814 info.sources.remove(path);
694 } 815 }
695 break; 816 break;
696 case ChangeType.MODIFY: 817 case ChangeType.MODIFY:
697 List<Source> sources = info.context.getSourcesWithFullName(path); 818 List<Source> sources = info.context.getSourcesWithFullName(path);
698 if (!sources.isEmpty) { 819 if (!sources.isEmpty) {
699 ChangeSet changeSet = new ChangeSet(); 820 ChangeSet changeSet = new ChangeSet();
700 sources.forEach((Source source) { 821 sources.forEach((Source source) {
701 changeSet.changedSource(source); 822 changeSet.changedSource(source);
702 }); 823 });
703 applyChangesToContext(folder, changeSet); 824 applyChangesToContext(folder, changeSet);
704 } 825 }
705 break; 826 break;
706 } 827 }
707 828
829 //TODO(pquitslund): find the right place for this
830 _checkForPackagespecUpdate(path, info, folder);
831
708 if (info.packageMapInfo != null && 832 if (info.packageMapInfo != null &&
709 info.packageMapInfo.isChangedDependency(path, resourceProvider)) { 833 info.packageMapInfo.isChangedDependency(path, resourceProvider)) {
710 _recomputePackageUriResolver(info); 834 _recomputePackageUriResolver(info);
711 } 835 }
712 } 836 }
713 837
714 /** 838 /**
715 * Returns `true` if the given [path] is excluded by [excludedPaths]. 839 * Returns `true` if the given [path] is excluded by [excludedPaths].
716 */ 840 */
717 bool _isExcluded(String path) { 841 bool _isExcluded(String path) => _isExcludedBy(excludedPaths, path);
718 return _isExcludedBy(excludedPaths, path);
719 }
720 842
721 /** 843 /**
722 * Returns `true` if the given [path] is excluded by [excludedPaths]. 844 * Returns `true` if the given [path] is excluded by [excludedPaths].
723 */ 845 */
724 bool _isExcludedBy(List<String> excludedPaths, String path) { 846 bool _isExcludedBy(List<String> excludedPaths, String path) {
725 return excludedPaths.any((excludedPath) { 847 return excludedPaths.any((excludedPath) {
726 if (pathContext.isWithin(excludedPath, path)) { 848 if (pathContext.isWithin(excludedPath, path)) {
727 return true; 849 return true;
728 } 850 }
729 return path == excludedPath; 851 return path == excludedPath;
730 }); 852 });
731 } 853 }
732 854
733 /** 855 /**
734 * Determine if the path from [folder] to [path] contains a 'packages' 856 * Determine if the path from [folder] to [path] contains a 'packages'
735 * directory. 857 * directory.
736 */ 858 */
737 bool _isInPackagesDir(String path, Folder folder) { 859 bool _isInPackagesDir(String path, Folder folder) {
738 String relativePath = pathContext.relative(path, from: folder.path); 860 String relativePath = pathContext.relative(path, from: folder.path);
739 List<String> pathParts = pathContext.split(relativePath); 861 List<String> pathParts = pathContext.split(relativePath);
740 return pathParts.contains(PACKAGES_NAME); 862 return pathParts.contains(PACKAGES_NAME);
741 } 863 }
742 864
743 /** 865 bool _isPackagespec(String path) =>
744 * Returns `true` if the given absolute [path] is a pubspec file. 866 pathContext.basename(path) == PACKAGE_SPEC_NAME;
745 */ 867
746 bool _isPubspec(String path) { 868 bool _isPubspec(String path) => pathContext.basename(path) == PUBSPEC_NAME;
747 return pathContext.basename(path) == PUBSPEC_NAME;
748 }
749 869
750 /** 870 /**
751 * Merges [info] context into its parent. 871 * Merges [info] context into its parent.
752 */ 872 */
753 void _mergeContext(_ContextInfo info) { 873 void _mergeContext(_ContextInfo info) {
754 // destroy the context 874 // destroy the context
755 _destroyContext(info.folder); 875 _destroyContext(info.folder);
756 // add files to the parent context 876 // add files to the parent context
757 _ContextInfo parentInfo = info.parent; 877 _ContextInfo parentInfo = info.parent;
758 if (parentInfo != null) { 878 if (parentInfo != null) {
759 parentInfo.children.remove(info); 879 parentInfo.children.remove(info);
760 ChangeSet changeSet = new ChangeSet(); 880 ChangeSet changeSet = new ChangeSet();
761 info.sources.forEach((path, source) { 881 info.sources.forEach((path, source) {
762 parentInfo.sources[path] = source; 882 parentInfo.sources[path] = source;
763 changeSet.addedSource(source); 883 changeSet.addedSource(source);
764 }); 884 });
765 applyChangesToContext(parentInfo.folder, changeSet); 885 applyChangesToContext(parentInfo.folder, changeSet);
766 } 886 }
767 } 887 }
768 888
889 Packages _readPackagespec(File specFile) {
890 try {
891 String contents = specFile.readAsStringSync();
892 Map<String, Uri> map =
893 pkgfile.parse(UTF8.encode(contents), new Uri.file(specFile.path));
894 return new MapPackages(map);
895 } catch (_) {
896 //TODO(pquitslund): consider creating an error for the spec file.
897 return null;
898 }
899 }
900
769 /** 901 /**
770 * Recompute the package URI resolver for the context described by [info], 902 * Recompute the package URI resolver for the context described by [info],
771 * and update the client appropriately. 903 * and update the client appropriately.
772 */ 904 */
773 void _recomputePackageUriResolver(_ContextInfo info) { 905 void _recomputePackageUriResolver(_ContextInfo info) {
774 // TODO(paulberry): when computePackageMap is changed into an 906 // TODO(paulberry): when computePackageMap is changed into an
775 // asynchronous API call, we'll want to suspend analysis for this context 907 // asynchronous API call, we'll want to suspend analysis for this context
776 // while we're rerunning "pub list", since any analysis we complete while 908 // while we're rerunning "pub list", since any analysis we complete while
777 // "pub list" is in progress is just going to get thrown away anyhow. 909 // "pub list" is in progress is just going to get thrown away anyhow.
778 UriResolver packageUriResolver = 910 UriResolver packageUriResolver =
779 _computePackageUriResolver(info.folder, info); 911 _computePackageUriResolver(info.folder, info);
780 updateContextPackageUriResolver(info.folder, packageUriResolver); 912 updateContextPackageUriResolver(info.folder, packageUriResolver, null);
781 } 913 }
782 914
783 /** 915 /**
784 * Create and return a source representing the given [file] within the given 916 * Create and return a source representing the given [file] within the given
785 * [context]. 917 * [context].
786 */ 918 */
787 static Source createSourceInContext(AnalysisContext context, File file) { 919 static Source createSourceInContext(AnalysisContext context, File file) {
788 // TODO(brianwilkerson) Optimize this, by allowing support for source 920 // TODO(brianwilkerson) Optimize this, by allowing support for source
789 // factories to restore URI's from a file path rather than a source. 921 // factories to restore URI's from a file path rather than a source.
790 Source source = file.createSource(); 922 Source source = file.createSource();
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
916 * The package root for this context, or null if there is no package root. 1048 * The package root for this context, or null if there is no package root.
917 */ 1049 */
918 String packageRoot; 1050 String packageRoot;
919 1051
920 /** 1052 /**
921 * The [_ContextInfo] that encloses this one. 1053 * The [_ContextInfo] that encloses this one.
922 */ 1054 */
923 _ContextInfo parent; 1055 _ContextInfo parent;
924 1056
925 /** 1057 /**
926 * The `pubspec.yaml` file path for this context. 1058 * The package description file path for this context.
927 */ 1059 */
928 String pubspecPath; 1060 String packageDescriptionPath;
929 1061
930 /** 1062 /**
931 * Stream subscription we are using to watch the context's directory for 1063 * Stream subscription we are using to watch the context's directory for
932 * changes. 1064 * changes.
933 */ 1065 */
934 StreamSubscription<WatchEvent> changeSubscription; 1066 StreamSubscription<WatchEvent> changeSubscription;
935 1067
936 /** 1068 /**
937 * Stream subscriptions we are using to watch the files 1069 * Stream subscriptions we are using to watch the files
938 * used to determine the package map. 1070 * used to determine the package map.
(...skipping 12 matching lines...) Expand all
951 */ 1083 */
952 Map<String, Source> sources = new HashMap<String, Source>(); 1084 Map<String, Source> sources = new HashMap<String, Source>();
953 1085
954 /** 1086 /**
955 * Info returned by the last call to 1087 * Info returned by the last call to
956 * [OptimizingPubPackageMapProvider.computePackageMap], or `null` if the 1088 * [OptimizingPubPackageMapProvider.computePackageMap], or `null` if the
957 * package map hasn't been computed for this context yet. 1089 * package map hasn't been computed for this context yet.
958 */ 1090 */
959 OptimizingPubPackageMapInfo packageMapInfo; 1091 OptimizingPubPackageMapInfo packageMapInfo;
960 1092
961 _ContextInfo(Folder folder, File pubspecFile, this.children, this.packageRoot) 1093 _ContextInfo(
1094 Folder folder, File packagespecFile, this.children, this.packageRoot)
962 : folder = folder, 1095 : folder = folder,
963 pathFilter = new PathFilter(folder.path, null) { 1096 pathFilter = new PathFilter(folder.path, null) {
964 pubspecPath = pubspecFile.path; 1097 packageDescriptionPath = packagespecFile.path;
965 for (_ContextInfo child in children) { 1098 for (_ContextInfo child in children) {
966 child.parent = this; 1099 child.parent = this;
967 } 1100 }
968 } 1101 }
969 1102
970 /** 1103 /**
971 * Returns `true` if this context is root folder based. 1104 * Returns `true` if this context is root folder based.
972 */ 1105 */
973 bool get isRoot => parent == null; 1106 bool get isRoot => parent == null;
974 1107
975 /** 1108 /**
976 * Returns `true` if [path] is excluded, as it is in one of the children. 1109 * Returns `true` if [path] is excluded, as it is in one of the children.
977 */ 1110 */
978 bool excludes(String path) { 1111 bool excludes(String path) {
979 return children.any((child) { 1112 return children.any((child) {
980 return child.folder.contains(path); 1113 return child.folder.contains(path);
981 }); 1114 });
982 } 1115 }
983 1116
1117 /**
1118 * Returns `true` if [resource] is excluded, as it is in one of the children.
1119 */
1120 bool excludesResource(Resource resource) => excludes(resource.path);
1121
984 /// Returns `true` if [path] should be ignored. 1122 /// Returns `true` if [path] should be ignored.
985 bool ignored(String path) => pathFilter.ignored(path); 1123 bool ignored(String path) => pathFilter.ignored(path);
986 1124
987 /** 1125 /**
988 * Returns `true` if [resource] is excluded, as it is in one of the children. 1126 * Returns `true` if [path] is the package description file for this context
1127 * (pubspec.yaml or .packages).
989 */ 1128 */
990 bool excludesResource(Resource resource) { 1129 bool isPathToPackageDescription(String path) =>
991 return excludes(resource.path); 1130 path == packageDescriptionPath;
992 }
993
994 /**
995 * Returns `true` if [path] is the pubspec file of this context.
996 */
997 bool isPubspec(String path) {
998 return path == pubspecPath;
999 }
1000 } 1131 }
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