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 |