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

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

Issue 679763002: Add package root support to analysis server. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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 | Annotate | Revision Log
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 9
10 import 'package:analyzer/file_system/file_system.dart'; 10 import 'package:analyzer/file_system/file_system.dart';
11 import 'package:analyzer/source/package_map_provider.dart'; 11 import 'package:analyzer/source/package_map_provider.dart';
12 import 'package:analyzer/source/package_map_resolver.dart';
12 import 'package:analyzer/src/generated/engine.dart'; 13 import 'package:analyzer/src/generated/engine.dart';
13 import 'package:analyzer/src/generated/source.dart'; 14 import 'package:analyzer/src/generated/source.dart';
15 import 'package:analyzer/src/generated/source_io.dart';
16 import 'package:analyzer/src/generated/java_io.dart';
14 import 'package:path/path.dart' as pathos; 17 import 'package:path/path.dart' as pathos;
15 import 'package:watcher/watcher.dart'; 18 import 'package:watcher/watcher.dart';
16 19
17 20
18 /** 21 /**
19 * File name of pubspec files. 22 * File name of pubspec files.
20 */ 23 */
21 const String PUBSPEC_NAME = 'pubspec.yaml'; 24 const String PUBSPEC_NAME = 'pubspec.yaml';
22 25
23 26
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 59
57 /** 60 /**
58 * The list of included paths (folders and files) most recently passed to 61 * The list of included paths (folders and files) most recently passed to
59 * [setRoots]. 62 * [setRoots].
60 */ 63 */
61 List<String> includedPaths = <String>[]; 64 List<String> includedPaths = <String>[];
62 65
63 /** 66 /**
64 * The map of package roots most recently passed to [setRoots]. 67 * The map of package roots most recently passed to [setRoots].
65 */ 68 */
66 Map<String, String> packageRoots = <String, String>{}; 69 Map<String, String> packageRoots = <String, String>{};
scheglov 2014/10/24 18:45:18 Are we going to use it? Should we just use it inst
Paul Berry 2014/10/24 20:26:49 We do use it, in refresh().
67 70
68 /** 71 /**
72 * Same as [packageRoots], except that source folders have been normalized
73 * and non-folders have been removed.
74 */
75 Map<String, String> normalizedPackageRoots = <String, String>{};
76
77 /**
69 * Provider which is used to determine the mapping from package name to 78 * Provider which is used to determine the mapping from package name to
70 * package folder. 79 * package folder.
71 */ 80 */
72 final PackageMapProvider packageMapProvider; 81 final PackageMapProvider _packageMapProvider;
73 82
74 ContextManager(this.resourceProvider, this.packageMapProvider) { 83 ContextManager(this.resourceProvider, this._packageMapProvider) {
75 pathContext = resourceProvider.pathContext; 84 pathContext = resourceProvider.pathContext;
76 } 85 }
77 86
78 /** 87 /**
79 * Called when a new context needs to be created. 88 * Called when a new context needs to be created.
80 */ 89 */
81 void addContext(Folder folder, Map<String, List<Folder>> packageMap); 90 void addContext(Folder folder, UriResolver packageUriResolver);
82 91
83 /** 92 /**
84 * Called when the set of files associated with a context have changed (or 93 * Called when the set of files associated with a context have changed (or
85 * some of those files have been modified). [changeSet] is the set of 94 * some of those files have been modified). [changeSet] is the set of
86 * changes that need to be applied to the context. 95 * changes that need to be applied to the context.
87 */ 96 */
88 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet); 97 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet);
89 98
90 /** 99 /**
91 * Returns `true` if the given absolute [path] is in one of the current 100 * Returns `true` if the given absolute [path] is in one of the current
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 // Rebuild contexts based on the data last sent to setRoots(). 132 // Rebuild contexts based on the data last sent to setRoots().
124 setRoots(includedPaths, excludedPaths, packageRoots); 133 setRoots(includedPaths, excludedPaths, packageRoots);
125 } 134 }
126 135
127 /** 136 /**
128 * Change the set of paths which should be used as starting points to 137 * Change the set of paths which should be used as starting points to
129 * determine the context directories. 138 * determine the context directories.
130 */ 139 */
131 void setRoots(List<String> includedPaths, List<String> excludedPaths, 140 void setRoots(List<String> includedPaths, List<String> excludedPaths,
132 Map<String, String> packageRoots) { 141 Map<String, String> packageRoots) {
133 // TODO(paulberry): process package roots.
134 this.packageRoots = packageRoots; 142 this.packageRoots = packageRoots;
143
144 // Normalize all package root sources by mapping them to folders on the
145 // filesystem. Ignore any package root sources that aren't folders.
146 normalizedPackageRoots = <String, String>{};
147 packageRoots.forEach((String sourcePath, String targetPath) {
148 Resource resource = resourceProvider.getResource(sourcePath);
149 if (resource is Folder) {
150 normalizedPackageRoots[resource.path] = targetPath;
151 }
152 });
153
135 List<Folder> contextFolders = _contexts.keys.toList(); 154 List<Folder> contextFolders = _contexts.keys.toList();
136 // included 155 // included
137 Set<Folder> includedFolders = new HashSet<Folder>(); 156 Set<Folder> includedFolders = new HashSet<Folder>();
138 for (int i = 0; i < includedPaths.length; i++) { 157 for (int i = 0; i < includedPaths.length; i++) {
139 String path = includedPaths[i]; 158 String path = includedPaths[i];
140 Resource resource = resourceProvider.getResource(path); 159 Resource resource = resourceProvider.getResource(path);
141 if (resource is Folder) { 160 if (resource is Folder) {
142 includedFolders.add(resource); 161 includedFolders.add(resource);
143 } else { 162 } else {
144 // TODO(scheglov) implemented separate files analysis 163 // TODO(scheglov) implemented separate files analysis
145 throw new UnimplementedError( 164 throw new UnimplementedError(
146 '$path is not a folder. ' 165 '$path is not a folder. '
147 'Only support for folder analysis is implemented currently.'); 166 'Only support for folder analysis is implemented currently.');
148 } 167 }
149 } 168 }
150 this.includedPaths = includedPaths; 169 this.includedPaths = includedPaths;
151 // excluded 170 // excluded
152 List<String> oldExcludedPaths = this.excludedPaths; 171 List<String> oldExcludedPaths = this.excludedPaths;
153 this.excludedPaths = excludedPaths; 172 this.excludedPaths = excludedPaths;
154 // destroy old contexts 173 // destroy old contexts
155 for (Folder contextFolder in contextFolders) { 174 for (Folder contextFolder in contextFolders) {
156 bool isIncluded = includedFolders.any((folder) { 175 bool isIncluded = includedFolders.any((folder) {
157 return folder.isOrContains(contextFolder.path); 176 return folder.isOrContains(contextFolder.path);
158 }); 177 });
159 if (!isIncluded) { 178 if (!isIncluded) {
160 _destroyContext(contextFolder); 179 _destroyContext(contextFolder);
161 } 180 }
162 } 181 }
182 // Update package roots for existing contexts
183 _contexts.forEach((Folder folder, _ContextInfo info) {
184 String newPackageRoot = normalizedPackageRoots[folder.path];
185 if (info.packageRoot != newPackageRoot) {
186 info.packageRoot = newPackageRoot;
187 _recomputePackageUriResolver(info);
188 }
189 });
163 // create new contexts 190 // create new contexts
164 for (Folder includedFolder in includedFolders) { 191 for (Folder includedFolder in includedFolders) {
165 bool wasIncluded = contextFolders.any((folder) { 192 bool wasIncluded = contextFolders.any((folder) {
166 return folder.isOrContains(includedFolder.path); 193 return folder.isOrContains(includedFolder.path);
167 }); 194 });
168 if (!wasIncluded) { 195 if (!wasIncluded) {
169 _createContexts(includedFolder, false); 196 _createContexts(includedFolder, false);
170 } 197 }
171 } 198 }
172 // remove newly excluded sources 199 // remove newly excluded sources
(...skipping 18 matching lines...) Expand all
191 _contexts.forEach((folder, info) { 218 _contexts.forEach((folder, info) {
192 ChangeSet changeSet = new ChangeSet(); 219 ChangeSet changeSet = new ChangeSet();
193 _addPreviouslyExcludedSources(info, changeSet, folder, oldExcludedPaths); 220 _addPreviouslyExcludedSources(info, changeSet, folder, oldExcludedPaths);
194 applyChangesToContext(folder, changeSet); 221 applyChangesToContext(folder, changeSet);
195 }); 222 });
196 } 223 }
197 224
198 /** 225 /**
199 * Called when the package map for a context has changed. 226 * Called when the package map for a context has changed.
200 */ 227 */
201 void updateContextPackageMap(Folder contextFolder, Map<String, 228 void updateContextPackageUriResolver(Folder contextFolder,
202 List<Folder>> packageMap); 229 UriResolver packageUriResolver);
203 230
204 /** 231 /**
205 * Resursively adds all Dart and HTML files to the [changeSet]. 232 * Resursively adds all Dart and HTML files to the [changeSet].
206 */ 233 */
207 void _addPreviouslyExcludedSources(_ContextInfo info, ChangeSet changeSet, 234 void _addPreviouslyExcludedSources(_ContextInfo info, ChangeSet changeSet,
208 Folder folder, List<String> oldExcludedPaths) { 235 Folder folder, List<String> oldExcludedPaths) {
209 if (info.excludesResource(folder)) { 236 if (info.excludesResource(folder)) {
210 return; 237 return;
211 } 238 }
212 List<Resource> children = folder.getChildren(); 239 List<Resource> children = folder.getChildren();
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 } else if (child is Folder) { 286 } else if (child is Folder) {
260 if (child.shortName == PACKAGES_NAME) { 287 if (child.shortName == PACKAGES_NAME) {
261 continue; 288 continue;
262 } 289 }
263 _addSourceFiles(changeSet, child, info); 290 _addSourceFiles(changeSet, child, info);
264 } 291 }
265 } 292 }
266 } 293 }
267 294
268 /** 295 /**
296 * Compute the appropriate package URI resolver for [folder], and store
297 * dependency information in [info].
298 */
299 UriResolver _computePackageUriResolver(Folder folder, _ContextInfo info) {
300 UriResolver packageUriResolver;
301 if (info.packageRoot != null) {
302 info.packageMapDependencies = new Set<String>();
303 packageUriResolver = new PackageUriResolver(
304 [new JavaFile(info.packageRoot)]);
305 } else {
306 PackageMapInfo packageMapInfo =
307 _packageMapProvider.computePackageMap(folder);
308 info.packageMapDependencies = packageMapInfo.dependencies;
309 packageUriResolver = new PackageMapUriResolver(
310 resourceProvider, packageMapInfo.packageMap);
311 // TODO(paulberry): if any of the dependencies is outside of [folder],
312 // we'll need to watch their parent folders as well.
313 }
314 return packageUriResolver;
315 }
316
317 /**
269 * Create a new empty context associated with [folder]. 318 * Create a new empty context associated with [folder].
270 */ 319 */
271 _ContextInfo _createContext(Folder folder, List<_ContextInfo> children) { 320 _ContextInfo _createContext(Folder folder, List<_ContextInfo> children) {
272 _ContextInfo info = new _ContextInfo(folder, children); 321 _ContextInfo info = new _ContextInfo(folder, children,
322 normalizedPackageRoots[folder.path]);
273 _contexts[folder] = info; 323 _contexts[folder] = info;
274 info.changeSubscription = folder.changes.listen((WatchEvent event) { 324 info.changeSubscription = folder.changes.listen((WatchEvent event) {
275 _handleWatchEvent(folder, info, event); 325 _handleWatchEvent(folder, info, event);
276 }); 326 });
277 PackageMapInfo packageMapInfo = 327 UriResolver packageUriResolver = _computePackageUriResolver(folder, info);
278 packageMapProvider.computePackageMap(folder); 328 addContext(folder, packageUriResolver);
279 info.packageMapDependencies = packageMapInfo.dependencies;
280 // TODO(paulberry): if any of the dependencies is outside of [folder],
281 // we'll need to watch their parent folders as well.
282 addContext(folder, packageMapInfo.packageMap);
283 return info; 329 return info;
284 } 330 }
285 331
286 /** 332 /**
287 * Create a new context associated with [folder] and fills its with sources. 333 * Create a new context associated with [folder] and fills its with sources.
288 */ 334 */
289 _ContextInfo _createContextWithSources(Folder folder, 335 _ContextInfo _createContextWithSources(Folder folder,
290 List<_ContextInfo> children) { 336 List<_ContextInfo> children) {
291 _ContextInfo info = _createContext(folder, children); 337 _ContextInfo info = _createContext(folder, children);
292 ChangeSet changeSet = new ChangeSet(); 338 ChangeSet changeSet = new ChangeSet();
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 Source source = info.sources[path]; 478 Source source = info.sources[path];
433 if (source != null) { 479 if (source != null) {
434 ChangeSet changeSet = new ChangeSet(); 480 ChangeSet changeSet = new ChangeSet();
435 changeSet.changedSource(source); 481 changeSet.changedSource(source);
436 applyChangesToContext(folder, changeSet); 482 applyChangesToContext(folder, changeSet);
437 } 483 }
438 break; 484 break;
439 } 485 }
440 486
441 if (info.packageMapDependencies.contains(path)) { 487 if (info.packageMapDependencies.contains(path)) {
442 // TODO(paulberry): when computePackageMap is changed into an 488 _recomputePackageUriResolver(info);
443 // asynchronous API call, we'll want to suspend analysis for this context
444 // while we're rerunning "pub list", since any analysis we complete while
445 // "pub list" is in progress is just going to get thrown away anyhow.
446 PackageMapInfo packageMapInfo =
447 packageMapProvider.computePackageMap(folder);
448 info.packageMapDependencies = packageMapInfo.dependencies;
449 updateContextPackageMap(folder, packageMapInfo.packageMap);
450 } 489 }
451 } 490 }
452 491
453 /** 492 /**
454 * Returns `true` if the given [path] is excluded by [excludedPaths]. 493 * Returns `true` if the given [path] is excluded by [excludedPaths].
455 */ 494 */
456 bool _isExcluded(String path) { 495 bool _isExcluded(String path) {
457 return _isExcludedBy(excludedPaths, path); 496 return _isExcludedBy(excludedPaths, path);
458 } 497 }
459 498
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
498 parentInfo.children.remove(info); 537 parentInfo.children.remove(info);
499 ChangeSet changeSet = new ChangeSet(); 538 ChangeSet changeSet = new ChangeSet();
500 info.sources.forEach((path, source) { 539 info.sources.forEach((path, source) {
501 parentInfo.sources[path] = source; 540 parentInfo.sources[path] = source;
502 changeSet.addedSource(source); 541 changeSet.addedSource(source);
503 }); 542 });
504 applyChangesToContext(parentInfo.folder, changeSet); 543 applyChangesToContext(parentInfo.folder, changeSet);
505 } 544 }
506 } 545 }
507 546
547 /**
548 * Recompute the package URI resolver for the context described by [info],
549 * and update the client appropriately.
550 */
551 void _recomputePackageUriResolver(_ContextInfo info) {
552 // TODO(paulberry): when computePackageMap is changed into an
553 // asynchronous API call, we'll want to suspend analysis for this context
554 // while we're rerunning "pub list", since any analysis we complete while
555 // "pub list" is in progress is just going to get thrown away anyhow.
556 UriResolver packageUriResolver =
557 _computePackageUriResolver(info.folder, info);
558 updateContextPackageUriResolver(info.folder, packageUriResolver);
559 }
560
508 static bool _shouldFileBeAnalyzed(File file) { 561 static bool _shouldFileBeAnalyzed(File file) {
509 if (!(AnalysisEngine.isDartFileName(file.path) || 562 if (!(AnalysisEngine.isDartFileName(file.path) ||
510 AnalysisEngine.isHtmlFileName(file.path))) { 563 AnalysisEngine.isHtmlFileName(file.path))) {
511 return false; 564 return false;
512 } 565 }
513 // Emacs creates dummy links to track the fact that a file is open for 566 // Emacs creates dummy links to track the fact that a file is open for
514 // editing and has unsaved changes (e.g. having unsaved changes to 567 // editing and has unsaved changes (e.g. having unsaved changes to
515 // 'foo.dart' causes a link '.#foo.dart' to be created, which points to the 568 // 'foo.dart' causes a link '.#foo.dart' to be created, which points to the
516 // non-existent file 'username@hostname.pid'. To avoid these dummy links 569 // non-existent file 'username@hostname.pid'. To avoid these dummy links
517 // causing the analyzer to thrash, just ignore links to non-existent files. 570 // causing the analyzer to thrash, just ignore links to non-existent files.
518 return file.exists; 571 return file.exists;
519 } 572 }
520 } 573 }
521 574
522 /** 575 /**
523 * Information tracked by the [ContextManager] for each context. 576 * Information tracked by the [ContextManager] for each context.
524 */ 577 */
525 class _ContextInfo { 578 class _ContextInfo {
526 /** 579 /**
527 * The [Folder] for which this information object is created. 580 * The [Folder] for which this information object is created.
528 */ 581 */
529 final Folder folder; 582 final Folder folder;
530 583
531 /** 584 /**
532 * The enclosed pubspec-based contexts. 585 * The enclosed pubspec-based contexts.
533 */ 586 */
534 final List<_ContextInfo> children; 587 final List<_ContextInfo> children;
535 588
536 /** 589 /**
590 * The package root for this context, or null if there is no package root.
591 */
592 String packageRoot;
593
594 /**
537 * The [_ContextInfo] that encloses this one. 595 * The [_ContextInfo] that encloses this one.
538 */ 596 */
539 _ContextInfo parent; 597 _ContextInfo parent;
540 598
541 /** 599 /**
542 * The `pubspec.yaml` file path for this context. 600 * The `pubspec.yaml` file path for this context.
543 */ 601 */
544 String pubspecPath; 602 String pubspecPath;
545 603
546 /** 604 /**
547 * Stream subscription we are using to watch the context's directory for 605 * Stream subscription we are using to watch the context's directory for
548 * changes. 606 * changes.
549 */ 607 */
550 StreamSubscription<WatchEvent> changeSubscription; 608 StreamSubscription<WatchEvent> changeSubscription;
551 609
552 /** 610 /**
553 * Map from full path to the [Source] object, for each source that has been 611 * Map from full path to the [Source] object, for each source that has been
554 * added to the context. 612 * added to the context.
555 */ 613 */
556 Map<String, Source> sources = new HashMap<String, Source>(); 614 Map<String, Source> sources = new HashMap<String, Source>();
557 615
558 /** 616 /**
559 * Dependencies of the context's package map. 617 * Dependencies of the context's package map.
560 * If any of these files changes, the package map needs to be recomputed. 618 * If any of these files changes, the package map needs to be recomputed.
561 */ 619 */
562 Set<String> packageMapDependencies; 620 Set<String> packageMapDependencies;
563 621
564 _ContextInfo(this.folder, this.children) { 622 _ContextInfo(this.folder, this.children, this.packageRoot) {
565 pubspecPath = folder.getChild(PUBSPEC_NAME).path; 623 pubspecPath = folder.getChild(PUBSPEC_NAME).path;
566 for (_ContextInfo child in children) { 624 for (_ContextInfo child in children) {
567 child.parent = this; 625 child.parent = this;
568 } 626 }
569 } 627 }
570 628
571 /** 629 /**
572 * Returns `true` if this context is root folder based. 630 * Returns `true` if this context is root folder based.
573 */ 631 */
574 bool get isRoot => parent == null; 632 bool get isRoot => parent == null;
(...skipping 14 matching lines...) Expand all
589 return excludes(resource.path); 647 return excludes(resource.path);
590 } 648 }
591 649
592 /** 650 /**
593 * Returns `true` if [path] is the pubspec file of this context. 651 * Returns `true` if [path] is the pubspec file of this context.
594 */ 652 */
595 bool isPubspec(String path) { 653 bool isPubspec(String path) {
596 return path == pubspecPath; 654 return path == pubspecPath;
597 } 655 }
598 } 656 }
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