| 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:core' hide Resource; |    10 import 'dart:core' hide Resource; | 
|    10  |    11  | 
|    11 import 'package:analysis_server/src/analysis_server.dart'; |    12 import 'package:analysis_server/src/analysis_server.dart'; | 
|    12 import 'package:analysis_server/src/source/optimizing_pub_package_map_provider.d
      art'; |    13 import 'package:analysis_server/src/source/optimizing_pub_package_map_provider.d
      art'; | 
|    13 import 'package:analysis_server/uri/resolver_provider.dart'; |    14 import 'package:analysis_server/uri/resolver_provider.dart'; | 
|    14 import 'package:analyzer/file_system/file_system.dart'; |    15 import 'package:analyzer/file_system/file_system.dart'; | 
|    15 import 'package:analyzer/instrumentation/instrumentation.dart'; |    16 import 'package:analyzer/instrumentation/instrumentation.dart'; | 
|    16 import 'package:analyzer/source/analysis_options_provider.dart'; |    17 import 'package:analyzer/source/analysis_options_provider.dart'; | 
|    17 import 'package:analyzer/source/package_map_resolver.dart'; |    18 import 'package:analyzer/source/package_map_resolver.dart'; | 
|    18 import 'package:analyzer/source/path_filter.dart'; |    19 import 'package:analyzer/source/path_filter.dart'; | 
|    19 import 'package:analyzer/src/generated/engine.dart'; |    20 import 'package:analyzer/src/generated/engine.dart'; | 
|    20 import 'package:analyzer/src/generated/java_io.dart'; |    21 import 'package:analyzer/src/generated/java_io.dart'; | 
|    21 import 'package:analyzer/src/generated/source.dart'; |    22 import 'package:analyzer/src/generated/source.dart'; | 
|    22 import 'package:analyzer/src/generated/source_io.dart'; |    23 import 'package:analyzer/src/generated/source_io.dart'; | 
 |    24 import 'package:package_config/packages.dart'; | 
 |    25 import 'package:package_config/packages_file.dart' as pkgfile show parse; | 
 |    26 import 'package:package_config/src/packages_impl.dart' show MapPackages; | 
|    23 import 'package:path/path.dart' as pathos; |    27 import 'package:path/path.dart' as pathos; | 
|    24 import 'package:watcher/watcher.dart'; |    28 import 'package:watcher/watcher.dart'; | 
|    25 import 'package:yaml/yaml.dart'; |    29 import 'package:yaml/yaml.dart'; | 
|    26  |    30  | 
|    27 /** |    31 /** | 
|    28  * Class that maintains a mapping from included/excluded paths to a set of |    32  * Class that maintains a mapping from included/excluded paths to a set of | 
|    29  * folders that should correspond to analysis contexts. |    33  * folders that should correspond to analysis contexts. | 
|    30  */ |    34  */ | 
|    31 abstract class AbstractContextManager implements ContextManager { |    35 abstract class AbstractContextManager implements ContextManager { | 
 |    36  | 
 |    37   /** | 
 |    38    * Temporary flag to hide WIP .packages support (DEP 5). | 
 |    39    */ | 
 |    40   static bool ENABLE_PACKAGESPEC_SUPPORT = false; | 
 |    41  | 
|    32   /** |    42   /** | 
|    33    * The name of the `lib` directory. |    43    * The name of the `lib` directory. | 
|    34    */ |    44    */ | 
|    35   static const String LIB_DIR_NAME = 'lib'; |    45   static const String LIB_DIR_NAME = 'lib'; | 
|    36  |    46  | 
|    37   /** |    47   /** | 
|    38    * The name of `packages` folders. |    48    * The name of `packages` folders. | 
|    39    */ |    49    */ | 
|    40   static const String PACKAGES_NAME = 'packages'; |    50   static const String PACKAGES_NAME = 'packages'; | 
|    41  |    51  | 
|    42   /** |    52   /** | 
|    43    * File name of pubspec files. |    53    * File name of pubspec files. | 
|    44    */ |    54    */ | 
|    45   static const String PUBSPEC_NAME = 'pubspec.yaml'; |    55   static const String PUBSPEC_NAME = 'pubspec.yaml'; | 
|    46  |    56  | 
|    47   /** |    57   /** | 
 |    58    * File name of package spec files. | 
 |    59    */ | 
 |    60   static const String PACKAGE_SPEC_NAME = '.packages'; | 
 |    61  | 
 |    62   /** | 
|    48    * [_ContextInfo] object for each included directory in the most |    63    * [_ContextInfo] object for each included directory in the most | 
|    49    * recent successful call to [setRoots]. |    64    * recent successful call to [setRoots]. | 
|    50    */ |    65    */ | 
|    51   Map<Folder, _ContextInfo> _contexts = new HashMap<Folder, _ContextInfo>(); |    66   Map<Folder, _ContextInfo> _contexts = new HashMap<Folder, _ContextInfo>(); | 
|    52  |    67  | 
|    53   /** |    68   /** | 
|    54    * The [ResourceProvider] using which paths are converted into [Resource]s. |    69    * The [ResourceProvider] using which paths are converted into [Resource]s. | 
|    55    */ |    70    */ | 
|    56   final ResourceProvider resourceProvider; |    71   final ResourceProvider resourceProvider; | 
|    57  |    72  | 
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   106   final InstrumentationService _instrumentationService; |   121   final InstrumentationService _instrumentationService; | 
|   107  |   122  | 
|   108   AbstractContextManager(this.resourceProvider, this.packageResolverProvider, |   123   AbstractContextManager(this.resourceProvider, this.packageResolverProvider, | 
|   109       this._packageMapProvider, this._instrumentationService) { |   124       this._packageMapProvider, this._instrumentationService) { | 
|   110     pathContext = resourceProvider.pathContext; |   125     pathContext = resourceProvider.pathContext; | 
|   111   } |   126   } | 
|   112  |   127  | 
|   113   /** |   128   /** | 
|   114    * Create and return a new analysis context. |   129    * Create and return a new analysis context. | 
|   115    */ |   130    */ | 
|   116   AnalysisContext addContext(Folder folder, UriResolver packageUriResolver); |   131   AnalysisContext addContext( | 
 |   132       Folder folder, UriResolver packageUriResolver, Packages packages); | 
|   117  |   133  | 
|   118   /** |   134   /** | 
|   119    * Called when the set of files associated with a context have changed (or |   135    * Called when the set of files associated with a context have changed (or | 
|   120    * some of those files have been modified).  [changeSet] is the set of |   136    * some of those files have been modified).  [changeSet] is the set of | 
|   121    * changes that need to be applied to the context. |   137    * changes that need to be applied to the context. | 
|   122    */ |   138    */ | 
|   123   void applyChangesToContext(Folder contextFolder, ChangeSet changeSet); |   139   void applyChangesToContext(Folder contextFolder, ChangeSet changeSet); | 
|   124  |   140  | 
|   125   /** |   141   /** | 
|   126    * We are about to start computing the package map. |   142    * We are about to start computing the package map. | 
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   163     return contexts; |   179     return contexts; | 
|   164   } |   180   } | 
|   165  |   181  | 
|   166   /** |   182   /** | 
|   167    * We have finished computing the package map. |   183    * We have finished computing the package map. | 
|   168    */ |   184    */ | 
|   169   void endComputePackageMap() { |   185   void endComputePackageMap() { | 
|   170     // Do nothing. |   186     // Do nothing. | 
|   171   } |   187   } | 
|   172  |   188  | 
|   173   /// Sets the [ignorePatterns] for the context [folder]. |   189   @override | 
|   174   void setIgnorePatternsForContext(Folder folder, List<String> ignorePatterns) { |   190   bool isInAnalysisRoot(String path) { | 
|   175     _ContextInfo info = _contexts[folder]; |   191     // check if excluded | 
|   176     if (info == null) { |   192     if (_isExcluded(path)) { | 
|   177       return; |   193       return false; | 
|   178     } |   194     } | 
|   179     var pathFilter = info.pathFilter; |   195     // check if in of the roots | 
|   180     pathFilter.setIgnorePatterns(ignorePatterns); |   196     for (Folder root in _contexts.keys) { | 
 |   197       if (root.contains(path)) { | 
 |   198         return true; | 
 |   199       } | 
 |   200     } | 
 |   201     // no | 
 |   202     return false; | 
|   181   } |   203   } | 
|   182  |   204  | 
|   183   /// Process [options] for the context [folder]. |   205   /// Process [options] for the context [folder]. | 
|   184   void processOptionsForContext(Folder folder, Map<String, YamlNode> options) { |   206   void processOptionsForContext(Folder folder, Map<String, YamlNode> options) { | 
|   185     _ContextInfo info = _contexts[folder]; |   207     _ContextInfo info = _contexts[folder]; | 
|   186     if (info == null) { |   208     if (info == null) { | 
|   187       return; |   209       return; | 
|   188     } |   210     } | 
|   189     YamlMap analyzer = options['analyzer']; |   211     YamlMap analyzer = options['analyzer']; | 
|   190     if (analyzer == null) { |   212     if (analyzer == null) { | 
|   191       // No options for analyzer. |   213       // No options for analyzer. | 
|   192       return; |   214       return; | 
|   193     } |   215     } | 
|   194  |   216  | 
|   195     // Set ignore patterns. |   217     // Set ignore patterns. | 
|   196     YamlList exclude = analyzer['exclude']; |   218     YamlList exclude = analyzer['exclude']; | 
|   197     if (exclude != null) { |   219     if (exclude != null) { | 
|   198       setIgnorePatternsForContext(folder, exclude); |   220       setIgnorePatternsForContext(folder, exclude); | 
|   199     } |   221     } | 
|   200   } |   222   } | 
|   201  |   223  | 
|   202   @override |   224   @override | 
|   203   bool isInAnalysisRoot(String path) { |  | 
|   204     // check if excluded |  | 
|   205     if (_isExcluded(path)) { |  | 
|   206       return false; |  | 
|   207     } |  | 
|   208     // check if in of the roots |  | 
|   209     for (Folder root in _contexts.keys) { |  | 
|   210       if (root.contains(path)) { |  | 
|   211         return true; |  | 
|   212       } |  | 
|   213     } |  | 
|   214     // no |  | 
|   215     return false; |  | 
|   216   } |  | 
|   217  |  | 
|   218   @override |  | 
|   219   void refresh(List<Resource> roots) { |   225   void refresh(List<Resource> roots) { | 
|   220     // Destroy old contexts |   226     // Destroy old contexts | 
|   221     List<Folder> contextFolders = _contexts.keys.toList(); |   227     List<Folder> contextFolders = _contexts.keys.toList(); | 
|   222     if (roots == null) { |   228     if (roots == null) { | 
|   223       contextFolders.forEach(_destroyContext); |   229       contextFolders.forEach(_destroyContext); | 
|   224     } else { |   230     } else { | 
|   225       roots.forEach((Resource resource) { |   231       roots.forEach((Resource resource) { | 
|   226         contextFolders.forEach((Folder contextFolder) { |   232         contextFolders.forEach((Folder contextFolder) { | 
|   227           if (resource is Folder && resource.isOrContains(contextFolder.path)) { |   233           if (resource is Folder && resource.isOrContains(contextFolder.path)) { | 
|   228             _destroyContext(contextFolder); |   234             _destroyContext(contextFolder); | 
|   229           } |   235           } | 
|   230         }); |   236         }); | 
|   231       }); |   237       }); | 
|   232     } |   238     } | 
|   233  |   239  | 
|   234     // Rebuild contexts based on the data last sent to setRoots(). |   240     // Rebuild contexts based on the data last sent to setRoots(). | 
|   235     setRoots(includedPaths, excludedPaths, packageRoots); |   241     setRoots(includedPaths, excludedPaths, packageRoots); | 
|   236   } |   242   } | 
|   237  |   243  | 
|   238   /** |   244   /** | 
|   239    * Remove the context associated with the given [folder]. |   245    * Remove the context associated with the given [folder]. | 
|   240    */ |   246    */ | 
|   241   void removeContext(Folder folder); |   247   void removeContext(Folder folder); | 
|   242  |   248  | 
 |   249   /// Sets the [ignorePatterns] for the context [folder]. | 
 |   250   void setIgnorePatternsForContext(Folder folder, List<String> ignorePatterns) { | 
 |   251     _ContextInfo info = _contexts[folder]; | 
 |   252     if (info == null) { | 
 |   253       return; | 
 |   254     } | 
 |   255     var pathFilter = info.pathFilter; | 
 |   256     pathFilter.setIgnorePatterns(ignorePatterns); | 
 |   257   } | 
 |   258  | 
|   243   @override |   259   @override | 
|   244   void setRoots(List<String> includedPaths, List<String> excludedPaths, |   260   void setRoots(List<String> includedPaths, List<String> excludedPaths, | 
|   245       Map<String, String> packageRoots) { |   261       Map<String, String> packageRoots) { | 
|   246     this.packageRoots = packageRoots; |   262     this.packageRoots = packageRoots; | 
|   247  |   263  | 
|   248     // Normalize all package root sources by mapping them to folders on the |   264     // Normalize all package root sources by mapping them to folders on the | 
|   249     // filesystem.  Ignore any package root sources that aren't folders. |   265     // filesystem.  Ignore any package root sources that aren't folders. | 
|   250     normalizedPackageRoots = <String, String>{}; |   266     normalizedPackageRoots = <String, String>{}; | 
|   251     packageRoots.forEach((String sourcePath, String targetPath) { |   267     packageRoots.forEach((String sourcePath, String targetPath) { | 
|   252       Resource resource = resourceProvider.getResource(sourcePath); |   268       Resource resource = resourceProvider.getResource(sourcePath); | 
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   327  |   343  | 
|   328   /** |   344   /** | 
|   329    * Return `true` if the given [file] should be analyzed. |   345    * Return `true` if the given [file] should be analyzed. | 
|   330    */ |   346    */ | 
|   331   bool shouldFileBeAnalyzed(File file); |   347   bool shouldFileBeAnalyzed(File file); | 
|   332  |   348  | 
|   333   /** |   349   /** | 
|   334    * Called when the package map for a context has changed. |   350    * Called when the package map for a context has changed. | 
|   335    */ |   351    */ | 
|   336   void updateContextPackageUriResolver( |   352   void updateContextPackageUriResolver( | 
|   337       Folder contextFolder, UriResolver packageUriResolver); |   353       Folder contextFolder, UriResolver packageUriResolver, Packages packages); | 
|   338  |   354  | 
|   339   /** |   355   /** | 
|   340    * Resursively adds all Dart and HTML files to the [changeSet]. |   356    * Resursively adds all Dart and HTML files to the [changeSet]. | 
|   341    */ |   357    */ | 
|   342   void _addPreviouslyExcludedSources(_ContextInfo info, ChangeSet changeSet, |   358   void _addPreviouslyExcludedSources(_ContextInfo info, ChangeSet changeSet, | 
|   343       Folder folder, List<String> oldExcludedPaths) { |   359       Folder folder, List<String> oldExcludedPaths) { | 
|   344     if (info.excludesResource(folder)) { |   360     if (info.excludesResource(folder)) { | 
|   345       return; |   361       return; | 
|   346     } |   362     } | 
|   347     List<Resource> children; |   363     List<Resource> children; | 
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   424   /** |   440   /** | 
|   425    * Cancel all dependency subscriptions for the given context. |   441    * Cancel all dependency subscriptions for the given context. | 
|   426    */ |   442    */ | 
|   427   void _cancelDependencySubscriptions(_ContextInfo info) { |   443   void _cancelDependencySubscriptions(_ContextInfo info) { | 
|   428     for (StreamSubscription<WatchEvent> s in info.dependencySubscriptions) { |   444     for (StreamSubscription<WatchEvent> s in info.dependencySubscriptions) { | 
|   429       s.cancel(); |   445       s.cancel(); | 
|   430     } |   446     } | 
|   431     info.dependencySubscriptions.clear(); |   447     info.dependencySubscriptions.clear(); | 
|   432   } |   448   } | 
|   433  |   449  | 
 |   450   void _checkForPackagespecUpdate( | 
 |   451       String path, _ContextInfo info, Folder folder) { | 
 |   452     // Check to see if this is the .packages file for this context and if so, | 
 |   453     // update the context's source factory. | 
 |   454     if (pathContext.basename(path) == PACKAGE_SPEC_NAME && | 
 |   455         info.isPathToPackageDescription(path)) { | 
 |   456       File packagespec = resourceProvider.getFile(path); | 
 |   457       if (packagespec.exists) { | 
 |   458         Packages packages = _readPackagespec(packagespec); | 
 |   459         if (packages != null) { | 
 |   460           updateContextPackageUriResolver(folder, null, packages); | 
 |   461         } | 
 |   462       } | 
 |   463     } | 
 |   464   } | 
 |   465  | 
|   434   /** |   466   /** | 
|   435    * Compute the appropriate package URI resolver for [folder], and store |   467    * Compute the appropriate package URI resolver for [folder], and store | 
|   436    * dependency information in [info]. Return `null` if no package map can |   468    * dependency information in [info]. Return `null` if no package map can | 
|   437    * be computed. |   469    * be computed. | 
|   438    */ |   470    */ | 
|   439   UriResolver _computePackageUriResolver(Folder folder, _ContextInfo info) { |   471   UriResolver _computePackageUriResolver(Folder folder, _ContextInfo info) { | 
|   440     _cancelDependencySubscriptions(info); |   472     _cancelDependencySubscriptions(info); | 
|   441     if (info.packageRoot != null) { |   473     if (info.packageRoot != null) { | 
|   442       info.packageMapInfo = null; |   474       info.packageMapInfo = null; | 
|   443       JavaFile packagesDir = new JavaFile(info.packageRoot); |   475       JavaFile packagesDir = new JavaFile(info.packageRoot); | 
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   504           resourceProvider, packageMapInfo.packageMap); |   536           resourceProvider, packageMapInfo.packageMap); | 
|   505       // TODO(paulberry): if any of the dependencies is outside of [folder], |   537       // TODO(paulberry): if any of the dependencies is outside of [folder], | 
|   506       // we'll need to watch their parent folders as well. |   538       // we'll need to watch their parent folders as well. | 
|   507     } |   539     } | 
|   508   } |   540   } | 
|   509  |   541  | 
|   510   /** |   542   /** | 
|   511    * Create a new empty context associated with [folder]. |   543    * Create a new empty context associated with [folder]. | 
|   512    */ |   544    */ | 
|   513   _ContextInfo _createContext( |   545   _ContextInfo _createContext( | 
|   514       Folder folder, File pubspecFile, List<_ContextInfo> children) { |   546       Folder folder, File packagespecFile, List<_ContextInfo> children) { | 
|   515     _ContextInfo info = new _ContextInfo( |   547     _ContextInfo info = new _ContextInfo( | 
|   516         folder, pubspecFile, children, normalizedPackageRoots[folder.path]); |   548         folder, packagespecFile, children, normalizedPackageRoots[folder.path]); | 
|   517     _contexts[folder] = info; |   549     _contexts[folder] = info; | 
|   518     var options = analysisOptionsProvider.getOptions(folder); |   550     var options = analysisOptionsProvider.getOptions(folder); | 
|   519     processOptionsForContext(folder, options); |   551     processOptionsForContext(folder, options); | 
|   520     info.changeSubscription = folder.changes.listen((WatchEvent event) { |   552     info.changeSubscription = folder.changes.listen((WatchEvent event) { | 
|   521       _handleWatchEvent(folder, info, event); |   553       _handleWatchEvent(folder, info, event); | 
|   522     }); |   554     }); | 
|   523     try { |   555     try { | 
|   524       UriResolver packageUriResolver = _computePackageUriResolver(folder, info); |   556       Packages packages; | 
|   525       info.context = addContext(folder, packageUriResolver); |   557       UriResolver packageUriResolver; | 
 |   558  | 
 |   559       if (ENABLE_PACKAGESPEC_SUPPORT) { | 
 |   560         // Try .packages first. | 
 |   561         if (pathos.basename(packagespecFile.path) == PACKAGE_SPEC_NAME) { | 
 |   562           packages = _readPackagespec(packagespecFile); | 
 |   563         } | 
 |   564       } | 
 |   565  | 
 |   566       // Next resort to a package uri resolver. | 
 |   567       if (packages == null) { | 
 |   568         packageUriResolver = _computePackageUriResolver(folder, info); | 
 |   569       } | 
 |   570  | 
 |   571       info.context = addContext(folder, packageUriResolver, packages); | 
|   526       info.context.name = folder.path; |   572       info.context.name = folder.path; | 
|   527     } catch (_) { |   573     } catch (_) { | 
|   528       info.changeSubscription.cancel(); |   574       info.changeSubscription.cancel(); | 
|   529       rethrow; |   575       rethrow; | 
|   530     } |   576     } | 
|   531     return info; |   577     return info; | 
|   532   } |   578   } | 
|   533  |   579  | 
|   534   /** |   580   /** | 
|   535    * Potentially create a new context associated with the given [folder]. |   581    * Potentially create a new context associated with the given [folder]. | 
|   536    * |   582    * | 
|   537    * If there are subfolders with 'pubspec.yaml' files, separate contexts are |   583    * If there are subfolders with 'pubspec.yaml' files, separate contexts are | 
|   538    * created for them and excluded from the context associated with the |   584    * created for them and excluded from the context associated with the | 
|   539    * [folder]. |   585    * [folder]. | 
|   540    * |   586    * | 
|   541    * If [withPubspecOnly] is `true`, a context will be created only if there |   587    * If [withPackageSpecOnly] is `true`, a context will be created only if there | 
|   542    * is a 'pubspec.yaml' file in the [folder]. |   588    * is a 'pubspec.yaml' or '.packages' file in the [folder]. | 
|   543    * |   589    * | 
|   544    * Returns create pubspec-based contexts. |   590    * Returns created contexts. | 
|   545    */ |   591    */ | 
|   546   List<_ContextInfo> _createContexts(Folder folder, bool withPubspecOnly) { |   592   List<_ContextInfo> _createContexts(Folder folder, bool withPackageSpecOnly) { | 
|   547     // try to find subfolders with pubspec files |   593     // Try to find subfolders with pubspecs or .packages files. | 
|   548     List<_ContextInfo> children = <_ContextInfo>[]; |   594     List<_ContextInfo> children = <_ContextInfo>[]; | 
|   549     try { |   595     try { | 
|   550       for (Resource child in folder.getChildren()) { |   596       for (Resource child in folder.getChildren()) { | 
|   551         if (child is Folder) { |   597         if (child is Folder) { | 
|   552           children.addAll(_createContexts(child, true)); |   598           children.addAll(_createContexts(child, true)); | 
|   553         } |   599         } | 
|   554       } |   600       } | 
|   555     } on FileSystemException { |   601     } on FileSystemException { | 
|   556       // The directory either doesn't exist or cannot be read. Either way, there |   602       // The directory either doesn't exist or cannot be read. Either way, there | 
|   557       // are no subfolders that need to be added. |   603       // are no subfolders that need to be added. | 
|   558     } |   604     } | 
|   559     // check whether there is a pubspec in the folder |   605  | 
|   560     File pubspecFile = folder.getChild(PUBSPEC_NAME); |   606     File packageSpec; | 
|   561     if (pubspecFile.exists) { |   607  | 
 |   608     if (ENABLE_PACKAGESPEC_SUPPORT) { | 
 |   609       // Start by looking for .packages. | 
 |   610       packageSpec = folder.getChild(PACKAGE_SPEC_NAME); | 
 |   611     } | 
 |   612  | 
 |   613     // Fall back to looking for a pubspec. | 
 |   614     if (packageSpec == null || !packageSpec.exists) { | 
 |   615       packageSpec = folder.getChild(PUBSPEC_NAME); | 
 |   616     } | 
 |   617  | 
 |   618     if (packageSpec.exists) { | 
|   562       return <_ContextInfo>[ |   619       return <_ContextInfo>[ | 
|   563         _createContextWithSources(folder, pubspecFile, children) |   620         _createContextWithSources(folder, packageSpec, children) | 
|   564       ]; |   621       ]; | 
|   565     } |   622     } | 
|   566     // no pubspec, done |   623     // No packagespec? Done. | 
|   567     if (withPubspecOnly) { |   624     if (withPackageSpecOnly) { | 
|   568       return children; |   625       return children; | 
|   569     } |   626     } | 
|   570     // OK, create a context without a pubspec |   627     // OK, create a context without a packagespec. | 
|   571     return <_ContextInfo>[ |   628     return <_ContextInfo>[ | 
|   572       _createContextWithSources(folder, pubspecFile, children) |   629       _createContextWithSources(folder, packageSpec, children) | 
|   573     ]; |   630     ]; | 
|   574   } |   631   } | 
|   575  |   632  | 
|   576   /** |   633   /** | 
|   577    * Create a new context associated with the given [folder]. The [pubspecFile] |   634    * Create a new context associated with the given [folder]. The [pubspecFile] | 
|   578    * is the `pubspec.yaml` file contained in the folder. Add any sources that |   635    * is the `pubspec.yaml` file contained in the folder. Add any sources that | 
|   579    * are not included in one of the [children] to the context. |   636    * are not included in one of the [children] to the context. | 
|   580    */ |   637    */ | 
|   581   _ContextInfo _createContextWithSources( |   638   _ContextInfo _createContextWithSources( | 
|   582       Folder folder, File pubspecFile, List<_ContextInfo> children) { |   639       Folder folder, File pubspecFile, List<_ContextInfo> children) { | 
|   583     _ContextInfo info = _createContext(folder, pubspecFile, children); |   640     _ContextInfo info = _createContext(folder, pubspecFile, children); | 
|   584     ChangeSet changeSet = new ChangeSet(); |   641     ChangeSet changeSet = new ChangeSet(); | 
|   585     _addSourceFiles(changeSet, folder, info); |   642     _addSourceFiles(changeSet, folder, info); | 
|   586     applyChangesToContext(folder, changeSet); |   643     applyChangesToContext(folder, changeSet); | 
|   587     return info; |   644     return info; | 
|   588   } |   645   } | 
|   589  |   646  | 
|   590   /** |   647   /** | 
|   591    * Clean up and destroy the context associated with the given folder. |   648    * Clean up and destroy the context associated with the given folder. | 
|   592    */ |   649    */ | 
|   593   void _destroyContext(Folder folder) { |   650   void _destroyContext(Folder folder) { | 
|   594     _ContextInfo info = _contexts[folder]; |   651     _ContextInfo info = _contexts[folder]; | 
|   595     info.changeSubscription.cancel(); |   652     info.changeSubscription.cancel(); | 
|   596     _cancelDependencySubscriptions(info); |   653     _cancelDependencySubscriptions(info); | 
|   597     removeContext(folder); |   654     removeContext(folder); | 
|   598     _contexts.remove(folder); |   655     _contexts.remove(folder); | 
|   599   } |   656   } | 
|   600  |   657  | 
|   601   /** |   658   /** | 
|   602    * Extract a new [pubspecFile]-based context from [oldInfo]. |   659    * Extract a new [packagespecFile]-based context from [oldInfo]. | 
|   603    */ |   660    */ | 
|   604   void _extractContext(_ContextInfo oldInfo, File pubspecFile) { |   661   void _extractContext(_ContextInfo oldInfo, File packagespecFile) { | 
|   605     Folder newFolder = pubspecFile.parent; |   662     Folder newFolder = packagespecFile.parent; | 
|   606     _ContextInfo newInfo = _createContext(newFolder, pubspecFile, []); |   663     _ContextInfo newInfo = _createContext(newFolder, packagespecFile, []); | 
|   607     newInfo.parent = oldInfo; |   664     newInfo.parent = oldInfo; | 
|   608     // prepare sources to extract |   665     // prepare sources to extract | 
|   609     Map<String, Source> extractedSources = new HashMap<String, Source>(); |   666     Map<String, Source> extractedSources = new HashMap<String, Source>(); | 
|   610     oldInfo.sources.forEach((path, source) { |   667     oldInfo.sources.forEach((path, source) { | 
|   611       if (newFolder.contains(path)) { |   668       if (newFolder.contains(path)) { | 
|   612         extractedSources[path] = source; |   669         extractedSources[path] = source; | 
|   613       } |   670       } | 
|   614     }); |   671     }); | 
|   615     // update new context |   672     // update new context | 
|   616     { |   673     { | 
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   650     } |   707     } | 
|   651     if (info.ignored(path)) { |   708     if (info.ignored(path)) { | 
|   652       return; |   709       return; | 
|   653     } |   710     } | 
|   654     // handle the change |   711     // handle the change | 
|   655     switch (event.type) { |   712     switch (event.type) { | 
|   656       case ChangeType.ADD: |   713       case ChangeType.ADD: | 
|   657         if (_isInPackagesDir(path, folder)) { |   714         if (_isInPackagesDir(path, folder)) { | 
|   658           return; |   715           return; | 
|   659         } |   716         } | 
 |   717  | 
|   660         Resource resource = resourceProvider.getResource(path); |   718         Resource resource = resourceProvider.getResource(path); | 
|   661         // pubspec was added in a sub-folder, extract a new context |   719  | 
|   662         if (_isPubspec(path) && info.isRoot && !info.isPubspec(path)) { |   720         if (ENABLE_PACKAGESPEC_SUPPORT) { | 
|   663           _extractContext(info, resource); |   721           String directoryPath = pathContext.dirname(path); | 
|   664           return; |   722  | 
 |   723           // Check to see if we need to create a new context. | 
 |   724           if (info.isRoot) { | 
 |   725  | 
 |   726             // Only create a new context if this is not the same directory | 
 |   727             // described by our info object. | 
 |   728             if (info.folder.path != directoryPath) { | 
 |   729               if (_isPubspec(path)) { | 
 |   730                 // Check for a sibling .packages file. | 
 |   731                 if (!resourceProvider.getFile( | 
 |   732                     pathos.join(directoryPath, PACKAGE_SPEC_NAME)).exists) { | 
 |   733                   _extractContext(info, resource); | 
 |   734                   return; | 
 |   735                 } | 
 |   736               } | 
 |   737               if (_isPackagespec(path)) { | 
 |   738                 // Check for a sibling pubspec.yaml file. | 
 |   739                 if (!resourceProvider | 
 |   740                     .getFile(pathos.join(directoryPath, PUBSPEC_NAME)).exists) { | 
 |   741                   _extractContext(info, resource); | 
 |   742                   return; | 
 |   743                 } | 
 |   744               } | 
 |   745             } | 
 |   746           } | 
 |   747         } else { | 
 |   748           // pubspec was added in a sub-folder, extract a new context | 
 |   749           if (_isPubspec(path) && | 
 |   750               info.isRoot && | 
 |   751               !info.isPathToPackageDescription(path)) { | 
 |   752             _extractContext(info, resource); | 
 |   753             return; | 
 |   754           } | 
|   665         } |   755         } | 
 |   756  | 
|   666         // If the file went away and was replaced by a folder before we |   757         // If the file went away and was replaced by a folder before we | 
|   667         // had a chance to process the event, resource might be a Folder.  In |   758         // had a chance to process the event, resource might be a Folder.  In | 
|   668         // that case don't add it. |   759         // that case don't add it. | 
|   669         if (resource is File) { |   760         if (resource is File) { | 
|   670           File file = resource; |   761           File file = resource; | 
|   671           if (shouldFileBeAnalyzed(file)) { |   762           if (shouldFileBeAnalyzed(file)) { | 
|   672             ChangeSet changeSet = new ChangeSet(); |   763             ChangeSet changeSet = new ChangeSet(); | 
|   673             Source source = createSourceInContext(info.context, file); |   764             Source source = createSourceInContext(info.context, file); | 
|   674             changeSet.addedSource(source); |   765             changeSet.addedSource(source); | 
|   675             applyChangesToContext(folder, changeSet); |   766             applyChangesToContext(folder, changeSet); | 
|   676             info.sources[path] = source; |   767             info.sources[path] = source; | 
|   677           } |   768           } | 
|   678         } |   769         } | 
|   679         break; |   770         break; | 
|   680       case ChangeType.REMOVE: |   771       case ChangeType.REMOVE: | 
|   681         // pubspec was removed, merge the context into its parent |   772  | 
|   682         if (info.isPubspec(path) && !info.isRoot) { |   773         // If package spec info is removed, check to see if we can merge context
      s. | 
|   683           _mergeContext(info); |   774         // Note that it's important to verify that there is NEITHER a .packages 
      nor a | 
|   684           return; |   775         // lingering pubspec.yaml before merging. | 
 |   776         if (!info.isRoot) { | 
 |   777           if (ENABLE_PACKAGESPEC_SUPPORT) { | 
 |   778             String directoryPath = pathContext.dirname(path); | 
 |   779  | 
 |   780             // Only merge if this is the same directory described by our info ob
      ject. | 
 |   781             if (info.folder.path == directoryPath) { | 
 |   782               if (_isPubspec(path)) { | 
 |   783                 // Check for a sibling .packages file. | 
 |   784                 if (!resourceProvider.getFile( | 
 |   785                     pathos.join(directoryPath, PACKAGE_SPEC_NAME)).exists) { | 
 |   786                   _mergeContext(info); | 
 |   787                   return; | 
 |   788                 } | 
 |   789               } | 
 |   790               if (_isPackagespec(path)) { | 
 |   791                 // Check for a sibling pubspec.yaml file. | 
 |   792                 if (!resourceProvider | 
 |   793                     .getFile(pathos.join(directoryPath, PUBSPEC_NAME)).exists) { | 
 |   794                   _mergeContext(info); | 
 |   795                   return; | 
 |   796                 } | 
 |   797               } | 
 |   798             } | 
 |   799           } else { | 
 |   800             if (info.isPathToPackageDescription(path)) { | 
 |   801               _mergeContext(info); | 
 |   802               return; | 
 |   803             } | 
 |   804           } | 
|   685         } |   805         } | 
 |   806  | 
|   686         List<Source> sources = info.context.getSourcesWithFullName(path); |   807         List<Source> sources = info.context.getSourcesWithFullName(path); | 
|   687         if (!sources.isEmpty) { |   808         if (!sources.isEmpty) { | 
|   688           ChangeSet changeSet = new ChangeSet(); |   809           ChangeSet changeSet = new ChangeSet(); | 
|   689           sources.forEach((Source source) { |   810           sources.forEach((Source source) { | 
|   690             changeSet.removedSource(source); |   811             changeSet.removedSource(source); | 
|   691           }); |   812           }); | 
|   692           applyChangesToContext(folder, changeSet); |   813           applyChangesToContext(folder, changeSet); | 
|   693           info.sources.remove(path); |   814           info.sources.remove(path); | 
|   694         } |   815         } | 
|   695         break; |   816         break; | 
|   696       case ChangeType.MODIFY: |   817       case ChangeType.MODIFY: | 
|   697         List<Source> sources = info.context.getSourcesWithFullName(path); |   818         List<Source> sources = info.context.getSourcesWithFullName(path); | 
|   698         if (!sources.isEmpty) { |   819         if (!sources.isEmpty) { | 
|   699           ChangeSet changeSet = new ChangeSet(); |   820           ChangeSet changeSet = new ChangeSet(); | 
|   700           sources.forEach((Source source) { |   821           sources.forEach((Source source) { | 
|   701             changeSet.changedSource(source); |   822             changeSet.changedSource(source); | 
|   702           }); |   823           }); | 
|   703           applyChangesToContext(folder, changeSet); |   824           applyChangesToContext(folder, changeSet); | 
|   704         } |   825         } | 
|   705         break; |   826         break; | 
|   706     } |   827     } | 
|   707  |   828  | 
 |   829     //TODO(pquitslund): find the right place for this | 
 |   830     _checkForPackagespecUpdate(path, info, folder); | 
 |   831  | 
|   708     if (info.packageMapInfo != null && |   832     if (info.packageMapInfo != null && | 
|   709         info.packageMapInfo.isChangedDependency(path, resourceProvider)) { |   833         info.packageMapInfo.isChangedDependency(path, resourceProvider)) { | 
|   710       _recomputePackageUriResolver(info); |   834       _recomputePackageUriResolver(info); | 
|   711     } |   835     } | 
|   712   } |   836   } | 
|   713  |   837  | 
|   714   /** |   838   /** | 
|   715    * Returns `true` if the given [path] is excluded by [excludedPaths]. |   839    * Returns `true` if the given [path] is excluded by [excludedPaths]. | 
|   716    */ |   840    */ | 
|   717   bool _isExcluded(String path) { |   841   bool _isExcluded(String path) => _isExcludedBy(excludedPaths, path); | 
|   718     return _isExcludedBy(excludedPaths, path); |  | 
|   719   } |  | 
|   720  |   842  | 
|   721   /** |   843   /** | 
|   722    * Returns `true` if the given [path] is excluded by [excludedPaths]. |   844    * Returns `true` if the given [path] is excluded by [excludedPaths]. | 
|   723    */ |   845    */ | 
|   724   bool _isExcludedBy(List<String> excludedPaths, String path) { |   846   bool _isExcludedBy(List<String> excludedPaths, String path) { | 
|   725     return excludedPaths.any((excludedPath) { |   847     return excludedPaths.any((excludedPath) { | 
|   726       if (pathContext.isWithin(excludedPath, path)) { |   848       if (pathContext.isWithin(excludedPath, path)) { | 
|   727         return true; |   849         return true; | 
|   728       } |   850       } | 
|   729       return path == excludedPath; |   851       return path == excludedPath; | 
|   730     }); |   852     }); | 
|   731   } |   853   } | 
|   732  |   854  | 
|   733   /** |   855   /** | 
|   734    * Determine if the path from [folder] to [path] contains a 'packages' |   856    * Determine if the path from [folder] to [path] contains a 'packages' | 
|   735    * directory. |   857    * directory. | 
|   736    */ |   858    */ | 
|   737   bool _isInPackagesDir(String path, Folder folder) { |   859   bool _isInPackagesDir(String path, Folder folder) { | 
|   738     String relativePath = pathContext.relative(path, from: folder.path); |   860     String relativePath = pathContext.relative(path, from: folder.path); | 
|   739     List<String> pathParts = pathContext.split(relativePath); |   861     List<String> pathParts = pathContext.split(relativePath); | 
|   740     return pathParts.contains(PACKAGES_NAME); |   862     return pathParts.contains(PACKAGES_NAME); | 
|   741   } |   863   } | 
|   742  |   864  | 
|   743   /** |   865   bool _isPackagespec(String path) => | 
|   744    * Returns `true` if the given absolute [path] is a pubspec file. |   866       pathContext.basename(path) == PACKAGE_SPEC_NAME; | 
|   745    */ |   867  | 
|   746   bool _isPubspec(String path) { |   868   bool _isPubspec(String path) => pathContext.basename(path) == PUBSPEC_NAME; | 
|   747     return pathContext.basename(path) == PUBSPEC_NAME; |  | 
|   748   } |  | 
|   749  |   869  | 
|   750   /** |   870   /** | 
|   751    * Merges [info] context into its parent. |   871    * Merges [info] context into its parent. | 
|   752    */ |   872    */ | 
|   753   void _mergeContext(_ContextInfo info) { |   873   void _mergeContext(_ContextInfo info) { | 
|   754     // destroy the context |   874     // destroy the context | 
|   755     _destroyContext(info.folder); |   875     _destroyContext(info.folder); | 
|   756     // add files to the parent context |   876     // add files to the parent context | 
|   757     _ContextInfo parentInfo = info.parent; |   877     _ContextInfo parentInfo = info.parent; | 
|   758     if (parentInfo != null) { |   878     if (parentInfo != null) { | 
|   759       parentInfo.children.remove(info); |   879       parentInfo.children.remove(info); | 
|   760       ChangeSet changeSet = new ChangeSet(); |   880       ChangeSet changeSet = new ChangeSet(); | 
|   761       info.sources.forEach((path, source) { |   881       info.sources.forEach((path, source) { | 
|   762         parentInfo.sources[path] = source; |   882         parentInfo.sources[path] = source; | 
|   763         changeSet.addedSource(source); |   883         changeSet.addedSource(source); | 
|   764       }); |   884       }); | 
|   765       applyChangesToContext(parentInfo.folder, changeSet); |   885       applyChangesToContext(parentInfo.folder, changeSet); | 
|   766     } |   886     } | 
|   767   } |   887   } | 
|   768  |   888  | 
 |   889   Packages _readPackagespec(File specFile) { | 
 |   890     try { | 
 |   891       String contents = specFile.readAsStringSync(); | 
 |   892       Map<String, Uri> map = | 
 |   893           pkgfile.parse(UTF8.encode(contents), new Uri.file(specFile.path)); | 
 |   894       return new MapPackages(map); | 
 |   895     } catch (_) { | 
 |   896       //TODO(pquitslund): consider creating an error for the spec file. | 
 |   897       return null; | 
 |   898     } | 
 |   899   } | 
 |   900  | 
|   769   /** |   901   /** | 
|   770    * Recompute the package URI resolver for the context described by [info], |   902    * Recompute the package URI resolver for the context described by [info], | 
|   771    * and update the client appropriately. |   903    * and update the client appropriately. | 
|   772    */ |   904    */ | 
|   773   void _recomputePackageUriResolver(_ContextInfo info) { |   905   void _recomputePackageUriResolver(_ContextInfo info) { | 
|   774     // TODO(paulberry): when computePackageMap is changed into an |   906     // TODO(paulberry): when computePackageMap is changed into an | 
|   775     // asynchronous API call, we'll want to suspend analysis for this context |   907     // asynchronous API call, we'll want to suspend analysis for this context | 
|   776     // while we're rerunning "pub list", since any analysis we complete while |   908     // while we're rerunning "pub list", since any analysis we complete while | 
|   777     // "pub list" is in progress is just going to get thrown away anyhow. |   909     // "pub list" is in progress is just going to get thrown away anyhow. | 
|   778     UriResolver packageUriResolver = |   910     UriResolver packageUriResolver = | 
|   779         _computePackageUriResolver(info.folder, info); |   911         _computePackageUriResolver(info.folder, info); | 
|   780     updateContextPackageUriResolver(info.folder, packageUriResolver); |   912     updateContextPackageUriResolver(info.folder, packageUriResolver, null); | 
|   781   } |   913   } | 
|   782  |   914  | 
|   783   /** |   915   /** | 
|   784    * Create and return a source representing the given [file] within the given |   916    * Create and return a source representing the given [file] within the given | 
|   785    * [context]. |   917    * [context]. | 
|   786    */ |   918    */ | 
|   787   static Source createSourceInContext(AnalysisContext context, File file) { |   919   static Source createSourceInContext(AnalysisContext context, File file) { | 
|   788     // TODO(brianwilkerson) Optimize this, by allowing support for source |   920     // TODO(brianwilkerson) Optimize this, by allowing support for source | 
|   789     // factories to restore URI's from a file path rather than a source. |   921     // factories to restore URI's from a file path rather than a source. | 
|   790     Source source = file.createSource(); |   922     Source source = file.createSource(); | 
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   916    * The package root for this context, or null if there is no package root. |  1048    * The package root for this context, or null if there is no package root. | 
|   917    */ |  1049    */ | 
|   918   String packageRoot; |  1050   String packageRoot; | 
|   919  |  1051  | 
|   920   /** |  1052   /** | 
|   921    * The [_ContextInfo] that encloses this one. |  1053    * The [_ContextInfo] that encloses this one. | 
|   922    */ |  1054    */ | 
|   923   _ContextInfo parent; |  1055   _ContextInfo parent; | 
|   924  |  1056  | 
|   925   /** |  1057   /** | 
|   926    * The `pubspec.yaml` file path for this context. |  1058    * The package description file path for this context. | 
|   927    */ |  1059    */ | 
|   928   String pubspecPath; |  1060   String packageDescriptionPath; | 
|   929  |  1061  | 
|   930   /** |  1062   /** | 
|   931    * Stream subscription we are using to watch the context's directory for |  1063    * Stream subscription we are using to watch the context's directory for | 
|   932    * changes. |  1064    * changes. | 
|   933    */ |  1065    */ | 
|   934   StreamSubscription<WatchEvent> changeSubscription; |  1066   StreamSubscription<WatchEvent> changeSubscription; | 
|   935  |  1067  | 
|   936   /** |  1068   /** | 
|   937    * Stream subscriptions we are using to watch the files |  1069    * Stream subscriptions we are using to watch the files | 
|   938    * used to determine the package map. |  1070    * used to determine the package map. | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
|   951    */ |  1083    */ | 
|   952   Map<String, Source> sources = new HashMap<String, Source>(); |  1084   Map<String, Source> sources = new HashMap<String, Source>(); | 
|   953  |  1085  | 
|   954   /** |  1086   /** | 
|   955    * Info returned by the last call to |  1087    * Info returned by the last call to | 
|   956    * [OptimizingPubPackageMapProvider.computePackageMap], or `null` if the |  1088    * [OptimizingPubPackageMapProvider.computePackageMap], or `null` if the | 
|   957    * package map hasn't been computed for this context yet. |  1089    * package map hasn't been computed for this context yet. | 
|   958    */ |  1090    */ | 
|   959   OptimizingPubPackageMapInfo packageMapInfo; |  1091   OptimizingPubPackageMapInfo packageMapInfo; | 
|   960  |  1092  | 
|   961   _ContextInfo(Folder folder, File pubspecFile, this.children, this.packageRoot) |  1093   _ContextInfo( | 
 |  1094       Folder folder, File packagespecFile, this.children, this.packageRoot) | 
|   962       : folder = folder, |  1095       : folder = folder, | 
|   963         pathFilter = new PathFilter(folder.path, null) { |  1096         pathFilter = new PathFilter(folder.path, null) { | 
|   964     pubspecPath = pubspecFile.path; |  1097     packageDescriptionPath = packagespecFile.path; | 
|   965     for (_ContextInfo child in children) { |  1098     for (_ContextInfo child in children) { | 
|   966       child.parent = this; |  1099       child.parent = this; | 
|   967     } |  1100     } | 
|   968   } |  1101   } | 
|   969  |  1102  | 
|   970   /** |  1103   /** | 
|   971    * Returns `true` if this context is root folder based. |  1104    * Returns `true` if this context is root folder based. | 
|   972    */ |  1105    */ | 
|   973   bool get isRoot => parent == null; |  1106   bool get isRoot => parent == null; | 
|   974  |  1107  | 
|   975   /** |  1108   /** | 
|   976    * Returns `true` if [path] is excluded, as it is in one of the children. |  1109    * Returns `true` if [path] is excluded, as it is in one of the children. | 
|   977    */ |  1110    */ | 
|   978   bool excludes(String path) { |  1111   bool excludes(String path) { | 
|   979     return children.any((child) { |  1112     return children.any((child) { | 
|   980       return child.folder.contains(path); |  1113       return child.folder.contains(path); | 
|   981     }); |  1114     }); | 
|   982   } |  1115   } | 
|   983  |  1116  | 
 |  1117   /** | 
 |  1118    * Returns `true` if [resource] is excluded, as it is in one of the children. | 
 |  1119    */ | 
 |  1120   bool excludesResource(Resource resource) => excludes(resource.path); | 
 |  1121  | 
|   984   /// Returns `true` if  [path] should be ignored. |  1122   /// Returns `true` if  [path] should be ignored. | 
|   985   bool ignored(String path) => pathFilter.ignored(path); |  1123   bool ignored(String path) => pathFilter.ignored(path); | 
|   986  |  1124  | 
|   987   /** |  1125   /** | 
|   988    * Returns `true` if [resource] is excluded, as it is in one of the children. |  1126    * Returns `true` if [path] is the package description file for this context  | 
 |  1127    * (pubspec.yaml or .packages). | 
|   989    */ |  1128    */ | 
|   990   bool excludesResource(Resource resource) { |  1129   bool isPathToPackageDescription(String path) => | 
|   991     return excludes(resource.path); |  1130       path == packageDescriptionPath; | 
|   992   } |  | 
|   993  |  | 
|   994   /** |  | 
|   995    * Returns `true` if [path] is the pubspec file of this context. |  | 
|   996    */ |  | 
|   997   bool isPubspec(String path) { |  | 
|   998     return path == pubspecPath; |  | 
|   999   } |  | 
|  1000 } |  1131 } | 
| OLD | NEW |