| 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 import 'dart:convert'; | 9 import 'dart:convert'; |
| 10 import 'dart:core' hide Resource; | 10 import 'dart:core' hide Resource; |
| 11 | 11 |
| 12 import 'package:analysis_server/src/analysis_server.dart'; | 12 import 'package:analysis_server/src/analysis_server.dart'; |
| 13 import 'package:analyzer/file_system/file_system.dart'; | 13 import 'package:analyzer/file_system/file_system.dart'; |
| 14 import 'package:analyzer/instrumentation/instrumentation.dart'; | 14 import 'package:analyzer/instrumentation/instrumentation.dart'; |
| 15 import 'package:analyzer/plugin/embedded_resolver_provider.dart'; | 15 import 'package:analyzer/plugin/embedded_resolver_provider.dart'; |
| 16 import 'package:analyzer/plugin/options.dart'; | 16 import 'package:analyzer/plugin/options.dart'; |
| 17 import 'package:analyzer/plugin/resolver_provider.dart'; | 17 import 'package:analyzer/plugin/resolver_provider.dart'; |
| 18 import 'package:analyzer/source/analysis_options_provider.dart'; | 18 import 'package:analyzer/source/analysis_options_provider.dart'; |
| 19 import 'package:analyzer/source/embedder.dart'; | 19 import 'package:analyzer/source/embedder.dart'; |
| 20 import 'package:analyzer/source/package_map_provider.dart'; | 20 import 'package:analyzer/source/package_map_provider.dart'; |
| 21 import 'package:analyzer/source/package_map_resolver.dart'; | 21 import 'package:analyzer/source/package_map_resolver.dart'; |
| 22 import 'package:analyzer/source/path_filter.dart'; | 22 import 'package:analyzer/source/path_filter.dart'; |
| 23 import 'package:analyzer/source/pub_package_map_provider.dart'; | 23 import 'package:analyzer/source/pub_package_map_provider.dart'; |
| 24 import 'package:analyzer/source/sdk_ext.dart'; | 24 import 'package:analyzer/source/sdk_ext.dart'; |
| 25 import 'package:analyzer/src/context/context.dart' as context; | 25 import 'package:analyzer/src/context/context.dart' as context; |
| 26 import 'package:analyzer/src/context/source.dart'; | 26 import 'package:analyzer/src/context/source.dart'; |
| 27 import 'package:analyzer/src/generated/engine.dart'; | 27 import 'package:analyzer/src/generated/engine.dart'; |
| 28 import 'package:analyzer/src/generated/java_engine.dart'; | 28 import 'package:analyzer/src/generated/java_engine.dart'; |
| 29 import 'package:analyzer/src/generated/java_io.dart'; | 29 import 'package:analyzer/src/generated/java_io.dart'; |
| 30 import 'package:analyzer/src/generated/sdk.dart'; |
| 30 import 'package:analyzer/src/generated/source.dart'; | 31 import 'package:analyzer/src/generated/source.dart'; |
| 31 import 'package:analyzer/src/generated/source_io.dart'; | 32 import 'package:analyzer/src/generated/source_io.dart'; |
| 32 import 'package:analyzer/src/task/options.dart'; | 33 import 'package:analyzer/src/task/options.dart'; |
| 33 import 'package:analyzer/src/util/absolute_path.dart'; | 34 import 'package:analyzer/src/util/absolute_path.dart'; |
| 34 import 'package:analyzer/src/util/glob.dart'; | 35 import 'package:analyzer/src/util/glob.dart'; |
| 35 import 'package:analyzer/src/util/yaml.dart'; | 36 import 'package:analyzer/src/util/yaml.dart'; |
| 36 import 'package:package_config/packages.dart'; | 37 import 'package:package_config/packages.dart'; |
| 37 import 'package:package_config/packages_file.dart' as pkgfile show parse; | 38 import 'package:package_config/packages_file.dart' as pkgfile show parse; |
| 38 import 'package:package_config/src/packages_impl.dart' show MapPackages; | 39 import 'package:package_config/src/packages_impl.dart' show MapPackages; |
| 39 import 'package:path/path.dart' as pathos; | 40 import 'package:path/path.dart' as pathos; |
| (...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 void computingPackageMap(bool computing); | 342 void computingPackageMap(bool computing); |
| 342 | 343 |
| 343 /** | 344 /** |
| 344 * Remove the context associated with the given [folder]. [flushedFiles] is | 345 * Remove the context associated with the given [folder]. [flushedFiles] is |
| 345 * a list of the files which will be "orphaned" by removing this context | 346 * a list of the files which will be "orphaned" by removing this context |
| 346 * (they will no longer be analyzed by any context). | 347 * (they will no longer be analyzed by any context). |
| 347 */ | 348 */ |
| 348 void removeContext(Folder folder, List<String> flushedFiles); | 349 void removeContext(Folder folder, List<String> flushedFiles); |
| 349 | 350 |
| 350 /** | 351 /** |
| 351 * Called when the disposition for a context has changed. | 352 * Called when the package resolution for the given [context] has changed. |
| 352 */ | 353 */ |
| 353 void updateContextPackageUriResolver( | 354 void updateContextPackageUriResolver(AnalysisContext context); |
| 354 Folder contextFolder, FolderDisposition disposition); | |
| 355 } | 355 } |
| 356 | 356 |
| 357 /** | 357 /** |
| 358 * Class that maintains a mapping from included/excluded paths to a set of | 358 * Class that maintains a mapping from included/excluded paths to a set of |
| 359 * folders that should correspond to analysis contexts. | 359 * folders that should correspond to analysis contexts. |
| 360 */ | 360 */ |
| 361 class ContextManagerImpl implements ContextManager { | 361 class ContextManagerImpl implements ContextManager { |
| 362 /** | 362 /** |
| 363 * The name of the `doc` directory. | 363 * The name of the `doc` directory. |
| 364 */ | 364 */ |
| (...skipping 18 matching lines...) Expand all Loading... |
| 383 * File name of package spec files. | 383 * File name of package spec files. |
| 384 */ | 384 */ |
| 385 static const String PACKAGE_SPEC_NAME = '.packages'; | 385 static const String PACKAGE_SPEC_NAME = '.packages'; |
| 386 | 386 |
| 387 /** | 387 /** |
| 388 * The [ResourceProvider] using which paths are converted into [Resource]s. | 388 * The [ResourceProvider] using which paths are converted into [Resource]s. |
| 389 */ | 389 */ |
| 390 final ResourceProvider resourceProvider; | 390 final ResourceProvider resourceProvider; |
| 391 | 391 |
| 392 /** | 392 /** |
| 393 * The manager used to access the SDK that should be associated with a |
| 394 * particular context. |
| 395 */ |
| 396 final DartSdkManager sdkManager; |
| 397 |
| 398 /** |
| 393 * The context used to work with absolute file system paths. | 399 * The context used to work with absolute file system paths. |
| 394 * | 400 * |
| 395 * TODO(scheglov) remove [pathContext]. | 401 * TODO(scheglov) remove [pathContext]. |
| 396 */ | 402 */ |
| 397 AbsolutePathContext absolutePathContext; | 403 AbsolutePathContext absolutePathContext; |
| 398 | 404 |
| 399 /** | 405 /** |
| 400 * The context used to work with file system paths. | 406 * The context used to work with file system paths. |
| 401 */ | 407 */ |
| 402 pathos.Context pathContext; | 408 pathos.Context pathContext; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 481 | 487 |
| 482 /** | 488 /** |
| 483 * Stream subscription we are using to watch each analysis root directory for | 489 * Stream subscription we are using to watch each analysis root directory for |
| 484 * changes. | 490 * changes. |
| 485 */ | 491 */ |
| 486 final Map<Folder, StreamSubscription<WatchEvent>> changeSubscriptions = | 492 final Map<Folder, StreamSubscription<WatchEvent>> changeSubscriptions = |
| 487 <Folder, StreamSubscription<WatchEvent>>{}; | 493 <Folder, StreamSubscription<WatchEvent>>{}; |
| 488 | 494 |
| 489 ContextManagerImpl( | 495 ContextManagerImpl( |
| 490 this.resourceProvider, | 496 this.resourceProvider, |
| 497 this.sdkManager, |
| 491 this.packageResolverProvider, | 498 this.packageResolverProvider, |
| 492 this.embeddedUriResolverProvider, | 499 this.embeddedUriResolverProvider, |
| 493 this._packageMapProvider, | 500 this._packageMapProvider, |
| 494 this.analyzedFilesGlobs, | 501 this.analyzedFilesGlobs, |
| 495 this._instrumentationService, | 502 this._instrumentationService, |
| 496 this.defaultContextOptions) { | 503 this.defaultContextOptions) { |
| 497 absolutePathContext = resourceProvider.absolutePathContext; | 504 absolutePathContext = resourceProvider.absolutePathContext; |
| 498 pathContext = resourceProvider.pathContext; | 505 pathContext = resourceProvider.pathContext; |
| 499 } | 506 } |
| 500 | 507 |
| (...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 921 info.context.sourceFactory = newFactory; | 928 info.context.sourceFactory = newFactory; |
| 922 return; | 929 return; |
| 923 } | 930 } |
| 924 } | 931 } |
| 925 } | 932 } |
| 926 | 933 |
| 927 // Next check for package URI updates. | 934 // Next check for package URI updates. |
| 928 if (info.isPathToPackageDescription(path)) { | 935 if (info.isPathToPackageDescription(path)) { |
| 929 Packages packages = _readPackagespec(packagespec); | 936 Packages packages = _readPackagespec(packagespec); |
| 930 if (packages != null) { | 937 if (packages != null) { |
| 931 callbacks.updateContextPackageUriResolver( | 938 _updateContextPackageUriResolver( |
| 932 folder, new PackagesFileDisposition(packages)); | 939 folder, new PackagesFileDisposition(packages)); |
| 933 } | 940 } |
| 934 } | 941 } |
| 935 } | 942 } |
| 936 } | 943 } |
| 937 } | 944 } |
| 938 | 945 |
| 939 /** | 946 /** |
| 940 * Compute the set of files that are being flushed, this is defined as | 947 * Compute the set of files that are being flushed, this is defined as |
| 941 * the set of sources in the removed context (context.sources), that are | 948 * the set of sources in the removed context (context.sources), that are |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1058 _computeFolderDisposition(folder, dependencies.add, packagespecFile); | 1065 _computeFolderDisposition(folder, dependencies.add, packagespecFile); |
| 1059 } | 1066 } |
| 1060 | 1067 |
| 1061 Map<String, Object> optionMap = readOptions(info.folder); | 1068 Map<String, Object> optionMap = readOptions(info.folder); |
| 1062 AnalysisOptions options = | 1069 AnalysisOptions options = |
| 1063 new AnalysisOptionsImpl.from(defaultContextOptions); | 1070 new AnalysisOptionsImpl.from(defaultContextOptions); |
| 1064 applyToAnalysisOptions(options, optionMap); | 1071 applyToAnalysisOptions(options, optionMap); |
| 1065 | 1072 |
| 1066 info.setDependencies(dependencies); | 1073 info.setDependencies(dependencies); |
| 1067 info.context = callbacks.addContext(folder, options, disposition); | 1074 info.context = callbacks.addContext(folder, options, disposition); |
| 1075 folderMap[folder] = info.context; |
| 1068 info.context.name = folder.path; | 1076 info.context.name = folder.path; |
| 1069 | 1077 |
| 1070 processOptionsForContext(info, optionMap); | 1078 processOptionsForContext(info, optionMap); |
| 1071 | 1079 |
| 1072 return info; | 1080 return info; |
| 1073 } | 1081 } |
| 1074 | 1082 |
| 1075 /** | 1083 /** |
| 1076 * Potentially create a new context associated with the given [folder]. | 1084 * Potentially create a new context associated with the given [folder]. |
| 1077 * | 1085 * |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1123 if (createContext) { | 1131 if (createContext) { |
| 1124 // Now that the child contexts have been created, add the sources that | 1132 // Now that the child contexts have been created, add the sources that |
| 1125 // don't belong to the children. | 1133 // don't belong to the children. |
| 1126 ChangeSet changeSet = new ChangeSet(); | 1134 ChangeSet changeSet = new ChangeSet(); |
| 1127 _addSourceFiles(changeSet, folder, parent); | 1135 _addSourceFiles(changeSet, folder, parent); |
| 1128 callbacks.applyChangesToContext(folder, changeSet); | 1136 callbacks.applyChangesToContext(folder, changeSet); |
| 1129 } | 1137 } |
| 1130 } | 1138 } |
| 1131 | 1139 |
| 1132 /** | 1140 /** |
| 1141 * Set up a [SourceFactory] that resolves packages as appropriate for the |
| 1142 * given [disposition]. |
| 1143 */ |
| 1144 SourceFactory _createSourceFactory(InternalAnalysisContext context, |
| 1145 AnalysisOptions options, FolderDisposition disposition, Folder folder) { |
| 1146 List<UriResolver> resolvers = []; |
| 1147 List<UriResolver> packageUriResolvers = |
| 1148 disposition.createPackageUriResolvers(resourceProvider); |
| 1149 |
| 1150 EmbedderUriResolver embedderUriResolver; |
| 1151 |
| 1152 // First check for a resolver provider. |
| 1153 if (embeddedUriResolverProvider != null) { |
| 1154 embedderUriResolver = embeddedUriResolverProvider(folder); |
| 1155 } |
| 1156 |
| 1157 // If no embedded URI resolver was provided, defer to a locator-backed one. |
| 1158 embedderUriResolver ??= |
| 1159 new EmbedderUriResolver(context.embedderYamlLocator.embedderYamls); |
| 1160 if (embedderUriResolver.length == 0) { |
| 1161 // The embedder uri resolver has no mappings. Use the default Dart SDK |
| 1162 // uri resolver. |
| 1163 resolvers.add(new DartUriResolver(sdkManager.getSdkForOptions(options))); |
| 1164 } else { |
| 1165 // The embedder uri resolver has mappings, use it instead of the default |
| 1166 // Dart SDK uri resolver. |
| 1167 resolvers.add(embedderUriResolver); |
| 1168 } |
| 1169 |
| 1170 resolvers.addAll(packageUriResolvers); |
| 1171 resolvers.add(new ResourceUriResolver(resourceProvider)); |
| 1172 return new SourceFactory(resolvers, disposition.packages); |
| 1173 } |
| 1174 |
| 1175 /** |
| 1133 * Clean up and destroy the context associated with the given folder. | 1176 * Clean up and destroy the context associated with the given folder. |
| 1134 */ | 1177 */ |
| 1135 void _destroyContext(ContextInfo info) { | 1178 void _destroyContext(ContextInfo info) { |
| 1136 changeSubscriptions.remove(info.folder)?.cancel(); | 1179 changeSubscriptions.remove(info.folder)?.cancel(); |
| 1137 callbacks.removeContext(info.folder, _computeFlushedFiles(info)); | 1180 callbacks.removeContext(info.folder, _computeFlushedFiles(info)); |
| 1138 bool wasRemoved = info.parent.children.remove(info); | 1181 bool wasRemoved = info.parent.children.remove(info); |
| 1139 assert(wasRemoved); | 1182 assert(wasRemoved); |
| 1140 } | 1183 } |
| 1141 | 1184 |
| 1142 /** | 1185 /** |
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1492 */ | 1535 */ |
| 1493 void _recomputeFolderDisposition(ContextInfo info) { | 1536 void _recomputeFolderDisposition(ContextInfo info) { |
| 1494 // TODO(paulberry): when computePackageMap is changed into an | 1537 // TODO(paulberry): when computePackageMap is changed into an |
| 1495 // asynchronous API call, we'll want to suspend analysis for this context | 1538 // asynchronous API call, we'll want to suspend analysis for this context |
| 1496 // while we're rerunning "pub list", since any analysis we complete while | 1539 // while we're rerunning "pub list", since any analysis we complete while |
| 1497 // "pub list" is in progress is just going to get thrown away anyhow. | 1540 // "pub list" is in progress is just going to get thrown away anyhow. |
| 1498 List<String> dependencies = <String>[]; | 1541 List<String> dependencies = <String>[]; |
| 1499 FolderDisposition disposition = _computeFolderDisposition( | 1542 FolderDisposition disposition = _computeFolderDisposition( |
| 1500 info.folder, dependencies.add, _findPackageSpecFile(info.folder)); | 1543 info.folder, dependencies.add, _findPackageSpecFile(info.folder)); |
| 1501 info.setDependencies(dependencies); | 1544 info.setDependencies(dependencies); |
| 1502 callbacks.updateContextPackageUriResolver(info.folder, disposition); | 1545 _updateContextPackageUriResolver(info.folder, disposition); |
| 1503 } | 1546 } |
| 1504 | 1547 |
| 1505 /** | 1548 /** |
| 1506 * Return `true` if the given [file] should be analyzed. | 1549 * Return `true` if the given [file] should be analyzed. |
| 1507 */ | 1550 */ |
| 1508 bool _shouldFileBeAnalyzed(File file) { | 1551 bool _shouldFileBeAnalyzed(File file) { |
| 1509 for (Glob glob in analyzedFilesGlobs) { | 1552 for (Glob glob in analyzedFilesGlobs) { |
| 1510 if (glob.matches(file.path)) { | 1553 if (glob.matches(file.path)) { |
| 1511 // Emacs creates dummy links to track the fact that a file is open for | 1554 // Emacs creates dummy links to track the fact that a file is open for |
| 1512 // editing and has unsaved changes (e.g. having unsaved changes to | 1555 // editing and has unsaved changes (e.g. having unsaved changes to |
| 1513 // 'foo.dart' causes a link '.#foo.dart' to be created, which points to | 1556 // 'foo.dart' causes a link '.#foo.dart' to be created, which points to |
| 1514 // the non-existent file 'username@hostname.pid'. To avoid these dummy | 1557 // the non-existent file 'username@hostname.pid'. To avoid these dummy |
| 1515 // links causing the analyzer to thrash, just ignore links to | 1558 // links causing the analyzer to thrash, just ignore links to |
| 1516 // non-existent files. | 1559 // non-existent files. |
| 1517 return file.exists; | 1560 return file.exists; |
| 1518 } | 1561 } |
| 1519 } | 1562 } |
| 1520 return false; | 1563 return false; |
| 1521 } | 1564 } |
| 1522 | 1565 |
| 1566 void _updateContextPackageUriResolver( |
| 1567 Folder contextFolder, FolderDisposition disposition) { |
| 1568 AnalysisContext context = folderMap[contextFolder]; |
| 1569 context.sourceFactory = _createSourceFactory( |
| 1570 context, context.analysisOptions, disposition, contextFolder); |
| 1571 callbacks.updateContextPackageUriResolver(context); |
| 1572 } |
| 1573 |
| 1523 /** | 1574 /** |
| 1524 * Create and return a source representing the given [file] within the given | 1575 * Create and return a source representing the given [file] within the given |
| 1525 * [context]. | 1576 * [context]. |
| 1526 */ | 1577 */ |
| 1527 static Source createSourceInContext(AnalysisContext context, File file) { | 1578 static Source createSourceInContext(AnalysisContext context, File file) { |
| 1528 // TODO(brianwilkerson) Optimize this, by allowing support for source | 1579 // TODO(brianwilkerson) Optimize this, by allowing support for source |
| 1529 // factories to restore URI's from a file path rather than a source. | 1580 // factories to restore URI's from a file path rather than a source. |
| 1530 Source source = file.createSource(); | 1581 Source source = file.createSource(); |
| 1531 if (context == null) { | 1582 if (context == null) { |
| 1532 return source; | 1583 return source; |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1708 ResourceProvider resourceProvider) { | 1759 ResourceProvider resourceProvider) { |
| 1709 if (packages != null) { | 1760 if (packages != null) { |
| 1710 // Construct package map for the SdkExtUriResolver. | 1761 // Construct package map for the SdkExtUriResolver. |
| 1711 Map<String, List<Folder>> packageMap = buildPackageMap(resourceProvider); | 1762 Map<String, List<Folder>> packageMap = buildPackageMap(resourceProvider); |
| 1712 return <UriResolver>[new SdkExtUriResolver(packageMap)]; | 1763 return <UriResolver>[new SdkExtUriResolver(packageMap)]; |
| 1713 } else { | 1764 } else { |
| 1714 return const <UriResolver>[]; | 1765 return const <UriResolver>[]; |
| 1715 } | 1766 } |
| 1716 } | 1767 } |
| 1717 } | 1768 } |
| OLD | NEW |