| 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 |