Chromium Code Reviews| 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:analyzer/src/context/context.dart' as context; | |
| 12 import 'package:analysis_server/plugin/analysis/resolver_provider.dart'; | 13 import 'package:analysis_server/plugin/analysis/resolver_provider.dart'; |
| 13 import 'package:analysis_server/src/analysis_server.dart'; | 14 import 'package:analysis_server/src/analysis_server.dart'; |
| 14 import 'package:analysis_server/src/server_options.dart'; | 15 import 'package:analysis_server/src/server_options.dart'; |
| 15 import 'package:analyzer/file_system/file_system.dart'; | 16 import 'package:analyzer/file_system/file_system.dart'; |
| 16 import 'package:analyzer/instrumentation/instrumentation.dart'; | 17 import 'package:analyzer/instrumentation/instrumentation.dart'; |
| 17 import 'package:analyzer/plugin/options.dart'; | 18 import 'package:analyzer/plugin/options.dart'; |
| 18 import 'package:analyzer/source/analysis_options_provider.dart'; | 19 import 'package:analyzer/source/analysis_options_provider.dart'; |
| 19 import 'package:analyzer/source/package_map_provider.dart'; | 20 import 'package:analyzer/source/package_map_provider.dart'; |
| 20 import 'package:analyzer/source/package_map_resolver.dart'; | 21 import 'package:analyzer/source/package_map_resolver.dart'; |
| 21 import 'package:analyzer/source/path_filter.dart'; | 22 import 'package:analyzer/source/path_filter.dart'; |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 304 void updateContextPackageUriResolver( | 305 void updateContextPackageUriResolver( |
| 305 Folder contextFolder, FolderDisposition disposition); | 306 Folder contextFolder, FolderDisposition disposition); |
| 306 } | 307 } |
| 307 | 308 |
| 308 /** | 309 /** |
| 309 * Class that maintains a mapping from included/excluded paths to a set of | 310 * Class that maintains a mapping from included/excluded paths to a set of |
| 310 * folders that should correspond to analysis contexts. | 311 * folders that should correspond to analysis contexts. |
| 311 */ | 312 */ |
| 312 class ContextManagerImpl implements ContextManager { | 313 class ContextManagerImpl implements ContextManager { |
| 313 /** | 314 /** |
| 315 * File name of analysis options files. | |
| 316 */ | |
| 317 static const String ANALYSIS_OPTIONS_FILE = '.analysis_options'; | |
|
Brian Wilkerson
2015/10/15 00:20:36
Do we have other definitions of this constant (or
pquitslund
2015/10/15 03:39:06
Agreed. The only other ones are in tests and in a
Brian Wilkerson
2015/10/15 13:15:31
Not really, no.
| |
| 318 | |
| 319 /** | |
| 314 * Temporary flag to hide WIP .packages support (DEP 5). | 320 * Temporary flag to hide WIP .packages support (DEP 5). |
| 315 */ | 321 */ |
| 316 static bool ENABLE_PACKAGESPEC_SUPPORT = serverOptions.isSet( | 322 static bool ENABLE_PACKAGESPEC_SUPPORT = serverOptions.isSet( |
| 317 'ContextManagerImpl.ENABLE_PACKAGESPEC_SUPPORT', | 323 'ContextManagerImpl.ENABLE_PACKAGESPEC_SUPPORT', |
| 318 defaultValue: true); | 324 defaultValue: true); |
| 319 | 325 |
| 320 /** | 326 /** |
| 321 * The name of the `lib` directory. | 327 * The name of the `lib` directory. |
| 322 */ | 328 */ |
| 323 static const String LIB_DIR_NAME = 'lib'; | 329 static const String LIB_DIR_NAME = 'lib'; |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 459 return true; | 465 return true; |
| 460 } | 466 } |
| 461 } | 467 } |
| 462 // no | 468 // no |
| 463 return false; | 469 return false; |
| 464 } | 470 } |
| 465 | 471 |
| 466 /** | 472 /** |
| 467 * Process [options] for the given context [info]. | 473 * Process [options] for the given context [info]. |
| 468 */ | 474 */ |
| 469 void processOptionsForContext( | 475 void processOptionsForContext(ContextInfo info, Folder folder, |
| 470 ContextInfo info, Map<String, YamlNode> options) { | 476 {bool optionsRemoved: false}) { |
| 471 if (options == null) { | 477 Map<String, YamlNode> options; |
| 478 try { | |
| 479 options = analysisOptionsProvider.getOptions(folder); | |
| 480 } catch (e, stacktrace) { | |
| 481 AnalysisEngine.instance.logger.logError( | |
| 482 'Error processing .analysis_options', | |
| 483 new CaughtException(e, stacktrace)); | |
| 484 // TODO(pquitslund): contribute plugin that sends error notification on | |
| 485 // options file. | |
| 486 // Related test: | |
| 487 // context_manager_test.test_analysis_options_parse_failure() | |
| 488 // AnalysisEngine.instance.optionsPlugin.optionsProcessors | |
| 489 // .forEach((OptionsProcessor p) => p.onError(e)); | |
| 490 } | |
| 491 | |
| 492 if (options == null && !optionsRemoved) { | |
| 472 return; | 493 return; |
| 473 } | 494 } |
| 474 | 495 |
| 475 // Notify options processors. | 496 // Notify options processors. |
| 476 AnalysisEngine.instance.optionsPlugin.optionsProcessors.forEach( | 497 AnalysisEngine.instance.optionsPlugin.optionsProcessors |
| 477 (OptionsProcessor p) => p.optionsProcessed(info.context, options)); | 498 .forEach((OptionsProcessor p) { |
| 499 try { | |
| 500 p.optionsProcessed(info.context, options); | |
| 501 } catch (e, stacktrace) { | |
| 502 AnalysisEngine.instance.logger.logError( | |
| 503 'Error processing .analysis_options', | |
| 504 new CaughtException(e, stacktrace)); | |
| 505 } | |
| 506 }); | |
| 507 | |
| 508 // In case options files are removed, revert to default options. | |
| 509 if (optionsRemoved) { | |
| 510 info.context.analysisOptions = new AnalysisOptionsImpl(); | |
| 511 return; | |
| 512 } | |
| 478 | 513 |
| 479 // Analysis options are processed 'in-line'. | 514 // Analysis options are processed 'in-line'. |
| 480 // TODO(pq): consider pushing exclude handling into a plugin. | |
| 481 YamlMap analyzer = options['analyzer']; | 515 YamlMap analyzer = options['analyzer']; |
| 482 if (analyzer == null) { | 516 if (analyzer == null) { |
| 483 // No options for analyzer. | 517 // No options for analyzer. |
| 484 return; | 518 return; |
| 485 } | 519 } |
| 486 | 520 |
| 487 // Set strong mode. | 521 // Set strong mode. |
| 488 var strongMode = analyzer['strong-mode']; | 522 var strongMode = analyzer['strong-mode']; |
| 489 if (strongMode == true) { | 523 if (strongMode is bool) { |
|
Brian Wilkerson
2015/10/15 00:20:36
If the key isn't there I think we want to treat it
pquitslund
2015/10/15 03:39:06
Ah. Good catch! I took this approach:
bool
| |
| 490 AnalysisContext context = info.context; | 524 AnalysisContext context = info.context; |
| 491 AnalysisOptionsImpl options = | 525 if (context.analysisOptions.strongMode != strongMode) { |
| 492 new AnalysisOptionsImpl.from(context.analysisOptions); | 526 AnalysisOptionsImpl options = |
| 493 options.strongMode = true; | 527 new AnalysisOptionsImpl.from(context.analysisOptions); |
| 494 context.analysisOptions = options; | 528 options.strongMode = strongMode; |
| 529 context.analysisOptions = options; | |
| 530 } | |
| 495 } | 531 } |
| 496 | 532 |
| 497 // Set ignore patterns. | 533 // Set ignore patterns. |
| 498 YamlList exclude = analyzer['exclude']; | 534 YamlList exclude = analyzer['exclude']; |
| 499 if (exclude != null) { | 535 if (exclude != null) { |
| 500 setIgnorePatternsForContext(info, exclude); | 536 setIgnorePatternsForContext(info, exclude); |
| 501 } | 537 } |
| 502 } | 538 } |
| 503 | 539 |
| 504 @override | 540 @override |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 837 // Next resort to a package uri resolver. | 873 // Next resort to a package uri resolver. |
| 838 if (disposition == null) { | 874 if (disposition == null) { |
| 839 disposition = | 875 disposition = |
| 840 _computeFolderDisposition(folder, dependencies.add, packagespecFile); | 876 _computeFolderDisposition(folder, dependencies.add, packagespecFile); |
| 841 } | 877 } |
| 842 | 878 |
| 843 info.setDependencies(dependencies); | 879 info.setDependencies(dependencies); |
| 844 info.context = callbacks.addContext(folder, disposition); | 880 info.context = callbacks.addContext(folder, disposition); |
| 845 info.context.name = folder.path; | 881 info.context.name = folder.path; |
| 846 | 882 |
| 847 try { | 883 processOptionsForContext(info, folder); |
| 848 Map<String, YamlNode> options = | |
| 849 analysisOptionsProvider.getOptions(folder); | |
| 850 processOptionsForContext(info, options); | |
| 851 } catch (e, stacktrace) { | |
| 852 AnalysisEngine.instance.logger.logError( | |
| 853 'Error processing .analysis_options', | |
| 854 new CaughtException(e, stacktrace)); | |
| 855 // TODO(pquitslund): contribute plugin that sends error notification on | |
| 856 // options file. | |
| 857 // Related test: | |
| 858 // context_manager_test.test_analysis_options_parse_failure() | |
| 859 // AnalysisEngine.instance.optionsPlugin.optionsProcessors | |
| 860 // .forEach((OptionsProcessor p) => p.onError(e)); | |
| 861 } | |
| 862 | 884 |
| 863 return info; | 885 return info; |
| 864 } | 886 } |
| 865 | 887 |
| 866 /** | 888 /** |
| 867 * Potentially create a new context associated with the given [folder]. | 889 * Potentially create a new context associated with the given [folder]. |
| 868 * | 890 * |
| 869 * If there are subfolders with 'pubspec.yaml' files, separate contexts are | 891 * If there are subfolders with 'pubspec.yaml' files, separate contexts are |
| 870 * created for them and excluded from the context associated with the | 892 * created for them and excluded from the context associated with the |
| 871 * [folder]. | 893 * [folder]. |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1154 List<Source> sources = info.context.getSourcesWithFullName(path); | 1176 List<Source> sources = info.context.getSourcesWithFullName(path); |
| 1155 if (!sources.isEmpty) { | 1177 if (!sources.isEmpty) { |
| 1156 ChangeSet changeSet = new ChangeSet(); | 1178 ChangeSet changeSet = new ChangeSet(); |
| 1157 sources.forEach((Source source) { | 1179 sources.forEach((Source source) { |
| 1158 changeSet.changedSource(source); | 1180 changeSet.changedSource(source); |
| 1159 }); | 1181 }); |
| 1160 callbacks.applyChangesToContext(info.folder, changeSet); | 1182 callbacks.applyChangesToContext(info.folder, changeSet); |
| 1161 } | 1183 } |
| 1162 break; | 1184 break; |
| 1163 } | 1185 } |
| 1186 _checkForPackagespecUpdate(path, info, info.folder); | |
| 1187 _checkForAnalysisOptionsUpdate(path, info, event.type); | |
| 1188 } | |
| 1164 | 1189 |
| 1165 //TODO(pquitslund): find the right place for this | 1190 void _checkForAnalysisOptionsUpdate( |
| 1166 _checkForPackagespecUpdate(path, info, info.folder); | 1191 String path, ContextInfo info, ChangeType changeType) { |
| 1192 if (pathContext.basename(path) == ANALYSIS_OPTIONS_FILE) { | |
| 1193 var analysisContext = info.context; | |
| 1194 if (analysisContext is context.AnalysisContextImpl) { | |
| 1195 processOptionsForContext(info, info.folder, | |
| 1196 optionsRemoved: changeType == ChangeType.REMOVE); | |
| 1197 analysisContext.invalidateCachedResults(); | |
| 1198 callbacks.applyChangesToContext(info.folder, new ChangeSet()); | |
| 1199 } | |
| 1200 } | |
| 1167 } | 1201 } |
| 1168 | 1202 |
| 1169 /** | 1203 /** |
| 1170 * Determine whether the given [path], when interpreted relative to the | 1204 * Determine whether the given [path], when interpreted relative to the |
| 1171 * context root [root], contains a folder whose name starts with '.'. | 1205 * context root [root], contains a folder whose name starts with '.'. |
| 1172 */ | 1206 */ |
| 1173 bool _isContainedInDotFolder(String root, String path) { | 1207 bool _isContainedInDotFolder(String root, String path) { |
| 1174 String relativePath = | 1208 String relativePath = |
| 1175 pathContext.relative(pathContext.dirname(path), from: root); | 1209 pathContext.relative(pathContext.dirname(path), from: root); |
| 1176 for (String pathComponent in pathContext.split(relativePath)) { | 1210 for (String pathComponent in pathContext.split(relativePath)) { |
| (...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1442 var path = resourceProvider.pathContext.fromUri(uri); | 1476 var path = resourceProvider.pathContext.fromUri(uri); |
| 1443 packageMap[name] = <Folder>[resourceProvider.getFolder(path)]; | 1477 packageMap[name] = <Folder>[resourceProvider.getFolder(path)]; |
| 1444 } | 1478 } |
| 1445 }); | 1479 }); |
| 1446 return <UriResolver>[new SdkExtUriResolver(packageMap)]; | 1480 return <UriResolver>[new SdkExtUriResolver(packageMap)]; |
| 1447 } else { | 1481 } else { |
| 1448 return const <UriResolver>[]; | 1482 return const <UriResolver>[]; |
| 1449 } | 1483 } |
| 1450 } | 1484 } |
| 1451 } | 1485 } |
| OLD | NEW |