OLD | NEW |
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'; |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 continue; | 265 continue; |
266 } | 266 } |
267 // ignore if was not excluded | 267 // ignore if was not excluded |
268 bool wasExcluded = | 268 bool wasExcluded = |
269 _isExcludedBy(oldExcludedPaths, path) && | 269 _isExcludedBy(oldExcludedPaths, path) && |
270 !_isExcludedBy(excludedPaths, path); | 270 !_isExcludedBy(excludedPaths, path); |
271 if (!wasExcluded) { | 271 if (!wasExcluded) { |
272 continue; | 272 continue; |
273 } | 273 } |
274 // do add the file | 274 // do add the file |
275 Source source = child.createSource(); | 275 Source source = createSourceInContext(info.context, child); |
276 changeSet.addedSource(source); | 276 changeSet.addedSource(source); |
277 info.sources[path] = source; | 277 info.sources[path] = source; |
278 } else if (child is Folder) { | 278 } else if (child is Folder) { |
279 if (child.shortName == PACKAGES_NAME) { | 279 if (child.shortName == PACKAGES_NAME) { |
280 continue; | 280 continue; |
281 } | 281 } |
282 _addPreviouslyExcludedSources(info, changeSet, child, oldExcludedPaths); | 282 _addPreviouslyExcludedSources(info, changeSet, child, oldExcludedPaths); |
283 } | 283 } |
284 } | 284 } |
285 } | 285 } |
286 | 286 |
287 /** | 287 /** |
288 * Resursively adds all Dart and HTML files to the [changeSet]. | 288 * Resursively adds all Dart and HTML files to the [changeSet]. |
289 */ | 289 */ |
290 void _addSourceFiles(ChangeSet changeSet, Folder folder, _ContextInfo info, | 290 void _addSourceFiles(ChangeSet changeSet, Folder folder, _ContextInfo info) { |
291 bool pubspecExists, bool createPackageUri) { | |
292 if (info.excludesResource(folder) || folder.shortName.startsWith('.')) { | 291 if (info.excludesResource(folder) || folder.shortName.startsWith('.')) { |
293 return; | 292 return; |
294 } | 293 } |
295 List<Resource> children = folder.getChildren(); | 294 List<Resource> children = folder.getChildren(); |
296 for (Resource child in children) { | 295 for (Resource child in children) { |
297 String path = child.path; | 296 String path = child.path; |
298 // ignore excluded files or folders | 297 // ignore excluded files or folders |
299 if (_isExcluded(path)) { | 298 if (_isExcluded(path)) { |
300 continue; | 299 continue; |
301 } | 300 } |
302 // add files, recurse into folders | 301 // add files, recurse into folders |
303 if (child is File) { | 302 if (child is File) { |
304 if (_shouldFileBeAnalyzed(child)) { | 303 if (_shouldFileBeAnalyzed(child)) { |
305 Source source = child.createSource(); | 304 Source source = createSourceInContext(info.context, child); |
306 if (createPackageUri) { | |
307 // | |
308 // It should be possible to generate the uri by executing: | |
309 // | |
310 // Uri uri = info.context.sourceFactory.restoreUri(source); | |
311 // | |
312 // but for some reason this doesn't produce the same result as the | |
313 // code below. This needs to be investigated. | |
314 // (See https://code.google.com/p/dart/issues/detail?id=22463). | |
315 // | |
316 String packagePath = info.folder.path; | |
317 String packageName = | |
318 resourceProvider.pathContext.basename(packagePath); | |
319 String libPath = | |
320 resourceProvider.pathContext.join(packagePath, LIB_DIR_NAME); | |
321 String relPath = source.fullName.substring(libPath.length); | |
322 Uri uri = | |
323 Uri.parse('${PackageMapUriResolver.PACKAGE_SCHEME}:$packageName$
relPath'); | |
324 source = child.createSource(uri); | |
325 } | |
326 changeSet.addedSource(source); | 305 changeSet.addedSource(source); |
327 info.sources[path] = source; | 306 info.sources[path] = source; |
328 } | 307 } |
329 } else if (child is Folder) { | 308 } else if (child is Folder) { |
330 String shortName = child.shortName; | 309 String shortName = child.shortName; |
331 if (shortName == PACKAGES_NAME) { | 310 if (shortName == PACKAGES_NAME) { |
332 continue; | 311 continue; |
333 } | 312 } |
334 if (pubspecExists && | 313 _addSourceFiles(changeSet, child, info); |
335 !createPackageUri && | |
336 shortName == LIB_DIR_NAME && | |
337 child.parent == info.folder) { | |
338 _addSourceFiles(changeSet, child, info, pubspecExists, true); | |
339 } else { | |
340 _addSourceFiles( | |
341 changeSet, | |
342 child, | |
343 info, | |
344 pubspecExists, | |
345 createPackageUri); | |
346 } | |
347 } | 314 } |
348 } | 315 } |
349 } | 316 } |
350 | 317 |
351 /** | 318 /** |
352 * Compute the appropriate package URI resolver for [folder], and store | 319 * Compute the appropriate package URI resolver for [folder], and store |
353 * dependency information in [info]. Return `null` if no package map can | 320 * dependency information in [info]. Return `null` if no package map can |
354 * be computed. | 321 * be computed. |
355 */ | 322 */ |
356 UriResolver _computePackageUriResolver(Folder folder, _ContextInfo info) { | 323 UriResolver _computePackageUriResolver(Folder folder, _ContextInfo info) { |
(...skipping 30 matching lines...) Expand all Loading... |
387 _contexts[folder] = info; | 354 _contexts[folder] = info; |
388 info.changeSubscription = folder.changes.listen((WatchEvent event) { | 355 info.changeSubscription = folder.changes.listen((WatchEvent event) { |
389 _handleWatchEvent(folder, info, event); | 356 _handleWatchEvent(folder, info, event); |
390 }); | 357 }); |
391 UriResolver packageUriResolver = _computePackageUriResolver(folder, info); | 358 UriResolver packageUriResolver = _computePackageUriResolver(folder, info); |
392 info.context = addContext(folder, packageUriResolver); | 359 info.context = addContext(folder, packageUriResolver); |
393 return info; | 360 return info; |
394 } | 361 } |
395 | 362 |
396 /** | 363 /** |
| 364 * Create a new context associated with the given [folder]. The [pubspecFile] |
| 365 * is the `pubspec.yaml` file contained in the folder. Add any sources that |
| 366 * are not included in one of the [children] to the context. |
| 367 */ |
| 368 _ContextInfo _createContextWithSources(Folder folder, File pubspecFile, |
| 369 List<_ContextInfo> children) { |
| 370 _ContextInfo info = _createContext(folder, pubspecFile, children); |
| 371 ChangeSet changeSet = new ChangeSet(); |
| 372 _addSourceFiles(changeSet, folder, info); |
| 373 applyChangesToContext(folder, changeSet); |
| 374 return info; |
| 375 } |
| 376 |
| 377 /** |
397 * Creates a new context associated with [folder]. | 378 * Creates a new context associated with [folder]. |
398 * | 379 * |
399 * If there are subfolders with 'pubspec.yaml' files, separate contexts | 380 * If there are subfolders with 'pubspec.yaml' files, separate contexts |
400 * are created for them, and excluded from the context associated with | 381 * are created for them, and excluded from the context associated with |
401 * [folder]. | 382 * [folder]. |
402 * | 383 * |
403 * If [folder] itself contains a 'pubspec.yaml' file, subfolders are ignored. | 384 * If [folder] itself contains a 'pubspec.yaml' file, subfolders are ignored. |
404 * | 385 * |
405 * If [withPubspecOnly] is `true`, a context will be created only if there | 386 * If [withPubspecOnly] is `true`, a context will be created only if there |
406 * is a 'pubspec.yaml' file in [folder]. | 387 * is a 'pubspec.yaml' file in [folder]. |
407 * | 388 * |
408 * Returns create pubspec-based contexts. | 389 * Returns create pubspec-based contexts. |
409 */ | 390 */ |
410 List<_ContextInfo> _createContexts(Folder folder, bool withPubspecOnly) { | 391 List<_ContextInfo> _createContexts(Folder folder, bool withPubspecOnly) { |
411 // check whether there is a pubspec in the folder | 392 // check whether there is a pubspec in the folder |
412 File pubspecFile = folder.getChild(PUBSPEC_NAME); | 393 File pubspecFile = folder.getChild(PUBSPEC_NAME); |
413 bool pubspecExists = pubspecFile.exists; | 394 if (pubspecFile.exists) { |
414 if (pubspecExists) { | 395 _ContextInfo info = |
415 _ContextInfo info = _createContextWithSources( | 396 _createContextWithSources(folder, pubspecFile, <_ContextInfo>[]); |
416 folder, | |
417 pubspecFile, | |
418 pubspecExists, | |
419 <_ContextInfo>[]); | |
420 return [info]; | 397 return [info]; |
421 } | 398 } |
422 // try to find subfolders with pubspec files | 399 // try to find subfolders with pubspec files |
423 List<_ContextInfo> children = <_ContextInfo>[]; | 400 List<_ContextInfo> children = <_ContextInfo>[]; |
424 for (Resource child in folder.getChildren()) { | 401 for (Resource child in folder.getChildren()) { |
425 if (child is Folder) { | 402 if (child is Folder) { |
426 List<_ContextInfo> childContexts = _createContexts(child, true); | 403 List<_ContextInfo> childContexts = _createContexts(child, true); |
427 children.addAll(childContexts); | 404 children.addAll(childContexts); |
428 } | 405 } |
429 } | 406 } |
430 // no pubspec, done | 407 // no pubspec, done |
431 if (withPubspecOnly) { | 408 if (withPubspecOnly) { |
432 return children; | 409 return children; |
433 } | 410 } |
434 // OK, create a context without a pubspec | 411 // OK, create a context without a pubspec |
435 _createContextWithSources(folder, pubspecFile, pubspecExists, children); | 412 _createContextWithSources(folder, pubspecFile, children); |
436 return children; | 413 return children; |
437 } | 414 } |
438 | 415 |
439 /** | 416 /** |
440 * Create a new context associated with the given [folder]. The [pubspecFile] | |
441 * is the `pubspec.yaml` file contained in the folder, and [pubspecExists] is | |
442 * `true` if the file exists. Add any sources that are not included in one of | |
443 * the [children] to the context. | |
444 */ | |
445 _ContextInfo _createContextWithSources(Folder folder, File pubspecFile, | |
446 bool pubspecExists, List<_ContextInfo> children) { | |
447 _ContextInfo info = _createContext(folder, pubspecFile, children); | |
448 ChangeSet changeSet = new ChangeSet(); | |
449 _addSourceFiles(changeSet, folder, info, pubspecExists, false); | |
450 applyChangesToContext(folder, changeSet); | |
451 return info; | |
452 } | |
453 | |
454 /** | |
455 * Clean up and destroy the context associated with the given folder. | 417 * Clean up and destroy the context associated with the given folder. |
456 */ | 418 */ |
457 void _destroyContext(Folder folder) { | 419 void _destroyContext(Folder folder) { |
458 _contexts[folder].changeSubscription.cancel(); | 420 _contexts[folder].changeSubscription.cancel(); |
459 _contexts.remove(folder); | 421 _contexts.remove(folder); |
460 removeContext(folder); | 422 removeContext(folder); |
461 } | 423 } |
462 | 424 |
463 /** | 425 /** |
464 * Extract a new [pubspecFile]-based context from [oldInfo]. | 426 * Extract a new [pubspecFile]-based context from [oldInfo]. |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 _extractContext(info, resource); | 478 _extractContext(info, resource); |
517 return; | 479 return; |
518 } | 480 } |
519 // If the file went away and was replaced by a folder before we | 481 // If the file went away and was replaced by a folder before we |
520 // had a chance to process the event, resource might be a Folder. In | 482 // had a chance to process the event, resource might be a Folder. In |
521 // that case don't add it. | 483 // that case don't add it. |
522 if (resource is File) { | 484 if (resource is File) { |
523 File file = resource; | 485 File file = resource; |
524 if (_shouldFileBeAnalyzed(file)) { | 486 if (_shouldFileBeAnalyzed(file)) { |
525 ChangeSet changeSet = new ChangeSet(); | 487 ChangeSet changeSet = new ChangeSet(); |
526 Source source = file.createSource(); | 488 Source source = createSourceInContext(info.context, file); |
527 changeSet.addedSource(source); | 489 changeSet.addedSource(source); |
528 applyChangesToContext(folder, changeSet); | 490 applyChangesToContext(folder, changeSet); |
529 info.sources[path] = source; | 491 info.sources[path] = source; |
530 } | 492 } |
531 } | 493 } |
532 break; | 494 break; |
533 case ChangeType.REMOVE: | 495 case ChangeType.REMOVE: |
534 // pubspec was removed, merge the context into its parent | 496 // pubspec was removed, merge the context into its parent |
535 if (info.isPubspec(path) && !info.isRoot) { | 497 if (info.isPubspec(path) && !info.isRoot) { |
536 _mergeContext(info); | 498 _mergeContext(info); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
621 void _recomputePackageUriResolver(_ContextInfo info) { | 583 void _recomputePackageUriResolver(_ContextInfo info) { |
622 // TODO(paulberry): when computePackageMap is changed into an | 584 // TODO(paulberry): when computePackageMap is changed into an |
623 // asynchronous API call, we'll want to suspend analysis for this context | 585 // asynchronous API call, we'll want to suspend analysis for this context |
624 // while we're rerunning "pub list", since any analysis we complete while | 586 // while we're rerunning "pub list", since any analysis we complete while |
625 // "pub list" is in progress is just going to get thrown away anyhow. | 587 // "pub list" is in progress is just going to get thrown away anyhow. |
626 UriResolver packageUriResolver = | 588 UriResolver packageUriResolver = |
627 _computePackageUriResolver(info.folder, info); | 589 _computePackageUriResolver(info.folder, info); |
628 updateContextPackageUriResolver(info.folder, packageUriResolver); | 590 updateContextPackageUriResolver(info.folder, packageUriResolver); |
629 } | 591 } |
630 | 592 |
| 593 /** |
| 594 * Create and return a source representing the given [file] within the given |
| 595 * [context]. |
| 596 */ |
| 597 static Source createSourceInContext(AnalysisContext context, File file) { |
| 598 // TODO(brianwilkerson) Optimize this, by allowing support for source |
| 599 // factories to restore URI's from a file path rather than a source. |
| 600 Source source = file.createSource(); |
| 601 if (context == null) { |
| 602 return source; |
| 603 } |
| 604 Uri uri = context.sourceFactory.restoreUri(source); |
| 605 return file.createSource(uri); |
| 606 } |
| 607 |
631 static bool _shouldFileBeAnalyzed(File file) { | 608 static bool _shouldFileBeAnalyzed(File file) { |
632 if (!(AnalysisEngine.isDartFileName(file.path) || | 609 if (!(AnalysisEngine.isDartFileName(file.path) || |
633 AnalysisEngine.isHtmlFileName(file.path))) { | 610 AnalysisEngine.isHtmlFileName(file.path))) { |
634 return false; | 611 return false; |
635 } | 612 } |
636 // Emacs creates dummy links to track the fact that a file is open for | 613 // Emacs creates dummy links to track the fact that a file is open for |
637 // editing and has unsaved changes (e.g. having unsaved changes to | 614 // editing and has unsaved changes (e.g. having unsaved changes to |
638 // 'foo.dart' causes a link '.#foo.dart' to be created, which points to the | 615 // 'foo.dart' causes a link '.#foo.dart' to be created, which points to the |
639 // non-existent file 'username@hostname.pid'. To avoid these dummy links | 616 // non-existent file 'username@hostname.pid'. To avoid these dummy links |
640 // causing the analyzer to thrash, just ignore links to non-existent files. | 617 // causing the analyzer to thrash, just ignore links to non-existent files. |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
722 return excludes(resource.path); | 699 return excludes(resource.path); |
723 } | 700 } |
724 | 701 |
725 /** | 702 /** |
726 * Returns `true` if [path] is the pubspec file of this context. | 703 * Returns `true` if [path] is the pubspec file of this context. |
727 */ | 704 */ |
728 bool isPubspec(String path) { | 705 bool isPubspec(String path) { |
729 return path == pubspecPath; | 706 return path == pubspecPath; |
730 } | 707 } |
731 } | 708 } |
OLD | NEW |