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 | 9 |
| 10 import 'package:analysis_server/src/package_map_provider.dart'; | 10 import 'package:analysis_server/src/package_map_provider.dart'; |
| 11 import 'package:analyzer/file_system/file_system.dart'; | 11 import 'package:analyzer/file_system/file_system.dart'; |
| 12 import 'package:analyzer/src/generated/engine.dart'; | 12 import 'package:analyzer/src/generated/engine.dart'; |
| 13 import 'package:analyzer/src/generated/source.dart'; | 13 import 'package:analyzer/src/generated/source.dart'; |
| 14 import 'package:path/path.dart' as pathos; | |
| 14 import 'package:watcher/watcher.dart'; | 15 import 'package:watcher/watcher.dart'; |
| 15 | 16 |
| 17 | |
| 18 /** | |
| 19 * File name of pubspec files. | |
| 20 */ | |
| 21 const String PUBSPEC_NAME = 'pubspec.yaml'; | |
| 22 | |
| 23 | |
| 16 /** | 24 /** |
| 17 * Class that maintains a mapping from included/excluded paths to a set of | 25 * Class that maintains a mapping from included/excluded paths to a set of |
| 18 * folders that should correspond to analysis contexts. | 26 * folders that should correspond to analysis contexts. |
| 19 */ | 27 */ |
| 20 abstract class ContextManager { | 28 abstract class ContextManager { |
| 21 /** | 29 /** |
| 22 * File name of pubspec files. | |
| 23 */ | |
| 24 static const String PUBSPEC_NAME = 'pubspec.yaml'; | |
| 25 | |
| 26 /** | |
| 27 * [_ContextInfo] object for each included directory in the most | 30 * [_ContextInfo] object for each included directory in the most |
| 28 * recent successful call to [setRoots]. | 31 * recent successful call to [setRoots]. |
| 29 */ | 32 */ |
| 30 Map<Folder, _ContextInfo> _currentDirectoryInfo = | 33 Map<Folder, _ContextInfo> _contexts = new HashMap<Folder, _ContextInfo>(); |
| 31 new HashMap<Folder, _ContextInfo>(); | |
| 32 | 34 |
| 33 /** | 35 /** |
| 34 * The [ResourceProvider] using which paths are converted into [Resource]s. | 36 * The [ResourceProvider] using which paths are converted into [Resource]s. |
| 35 */ | 37 */ |
| 36 final ResourceProvider resourceProvider; | 38 final ResourceProvider resourceProvider; |
| 37 | 39 |
| 38 /** | 40 /** |
| 41 * The [path.Context] for this manager. | |
|
Brian Wilkerson
2014/08/08 14:00:02
I assume "path" was suppose to be "pathos".
As wo
scheglov
2014/08/08 15:54:33
Done.
| |
| 42 */ | |
| 43 pathos.Context pathContext; | |
| 44 | |
| 45 | |
| 46 /** | |
| 39 * Provider which is used to determine the mapping from package name to | 47 * Provider which is used to determine the mapping from package name to |
| 40 * package folder. | 48 * package folder. |
| 41 */ | 49 */ |
| 42 final PackageMapProvider packageMapProvider; | 50 final PackageMapProvider packageMapProvider; |
| 43 | 51 |
| 44 ContextManager(this.resourceProvider, this.packageMapProvider); | 52 ContextManager(this.resourceProvider, this.packageMapProvider) { |
| 53 pathContext = resourceProvider.pathContext; | |
| 54 } | |
| 45 | 55 |
| 46 /** | 56 /** |
| 47 * Called when a new context needs to be created. | 57 * Called when a new context needs to be created. |
| 48 */ | 58 */ |
| 49 void addContext(Folder folder, Map<String, List<Folder>> packageMap); | 59 void addContext(Folder folder, Map<String, List<Folder>> packageMap); |
| 50 | 60 |
| 51 /** | 61 /** |
| 52 * Called when the set of files associated with a context have changed (or | 62 * Called when the set of files associated with a context have changed (or |
| 53 * some of those files have been modified). [changeSet] is the set of | 63 * some of those files have been modified). [changeSet] is the set of |
| 54 * changes that need to be applied to the context. | 64 * changes that need to be applied to the context. |
| 55 */ | 65 */ |
| 56 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet); | 66 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet); |
| 57 | 67 |
| 58 /** | 68 /** |
| 59 * Returns `true` if the given absolute [path] is in one of the current | 69 * Returns `true` if the given absolute [path] is in one of the current |
| 60 * root folders and is not excluded. | 70 * root folders and is not excluded. |
| 61 */ | 71 */ |
| 62 bool isInAnalysisRoot(String path) { | 72 bool isInAnalysisRoot(String path) { |
| 63 // TODO(scheglov) check for excluded paths | 73 // TODO(scheglov) check for excluded paths |
| 64 for (Folder root in _currentDirectoryInfo.keys) { | 74 for (Folder root in _contexts.keys) { |
| 65 if (root.contains(path)) { | 75 if (root.contains(path)) { |
| 66 return true; | 76 return true; |
| 67 } | 77 } |
| 68 } | 78 } |
| 69 return false; | 79 return false; |
| 70 } | 80 } |
| 71 | 81 |
| 72 /** | 82 /** |
| 73 * Remove the context associated with the given [folder]. | 83 * Remove the context associated with the given [folder]. |
| 74 */ | 84 */ |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 93 'Only support for folder analysis is implemented currently.'); | 103 'Only support for folder analysis is implemented currently.'); |
| 94 } | 104 } |
| 95 } | 105 } |
| 96 // excluded | 106 // excluded |
| 97 // TODO(scheglov) remove when implemented | 107 // TODO(scheglov) remove when implemented |
| 98 if (excludedPaths.isNotEmpty) { | 108 if (excludedPaths.isNotEmpty) { |
| 99 throw new UnimplementedError('Excluded paths are not supported yet'); | 109 throw new UnimplementedError('Excluded paths are not supported yet'); |
| 100 } | 110 } |
| 101 Set<Folder> excludedFolders = new HashSet<Folder>(); | 111 Set<Folder> excludedFolders = new HashSet<Folder>(); |
| 102 // diff | 112 // diff |
| 103 Set<Folder> currentFolders = _currentDirectoryInfo.keys.toSet(); | 113 Set<Folder> currentFolders = _contexts.keys.toSet(); |
|
Brian Wilkerson
2014/08/08 14:00:02
Are we making a copy to avoid modifying the keys w
scheglov
2014/08/08 15:54:33
We use it twice in the code below.
Paul Berry
2014/08/08 16:07:10
Agreed, but if we go with my suggestions below, th
scheglov
2014/08/08 16:34:23
Done.
| |
| 104 Set<Folder> newFolders = includedFolders.difference(currentFolders); | 114 Set<Folder> newFolders = new HashSet<Folder>(); |
| 105 Set<Folder> oldFolders = currentFolders.difference(includedFolders); | 115 Set<Folder> oldFolders = new HashSet<Folder>(); |
| 116 for (Folder currentFolder in currentFolders) { | |
| 117 bool isIncluded = includedFolders.any((folder) { | |
| 118 return folder.contains(currentFolder.path); | |
| 119 }); | |
| 120 if (!isIncluded) { | |
| 121 oldFolders.add(currentFolder); | |
|
Paul Berry
2014/08/08 16:07:10
I think it would be clearer to just do:
_destro
scheglov
2014/08/08 16:34:23
Done.
| |
| 122 } | |
| 123 } | |
| 124 for (Folder includedFolder in includedFolders) { | |
| 125 bool wasIncluded = currentFolders.any((folder) { | |
| 126 return folder.contains(includedFolder.path); | |
| 127 }); | |
| 128 if (!wasIncluded) { | |
| 129 newFolders.add(includedFolder); | |
|
Paul Berry
2014/08/08 16:07:10
Similarly, I think it would be clearer to just to:
scheglov
2014/08/08 16:34:23
Done.
| |
| 130 } | |
| 131 } | |
| 106 // destroy old contexts | 132 // destroy old contexts |
| 107 for (Folder folder in oldFolders) { | 133 for (Folder folder in oldFolders) { |
| 108 _destroyContext(folder); | 134 _destroyContext(folder); |
| 109 } | 135 } |
| 110 // create new contexts | 136 // create new contexts |
| 111 for (Folder folder in newFolders) { | 137 for (Folder folder in newFolders) { |
| 112 _createContext(folder); | 138 _createContexts(folder, false); |
| 113 } | 139 } |
| 114 } | 140 } |
| 115 | 141 |
| 116 /** | 142 /** |
| 117 * Called when the package map for a context has changed. | 143 * Called when the package map for a context has changed. |
| 118 */ | 144 */ |
| 119 void updateContextPackageMap(Folder contextFolder, Map<String, | 145 void updateContextPackageMap(Folder contextFolder, Map<String, |
| 120 List<Folder>> packageMap); | 146 List<Folder>> packageMap); |
| 121 | 147 |
| 122 /** | 148 /** |
| 123 * Create a new context associated with the given folder. | 149 * Create a new empty context associated with [folder]. |
| 124 */ | 150 */ |
| 125 void _createContext(Folder folder) { | 151 _ContextInfo _createContext(Folder folder, List<_ContextInfo> children) { |
| 126 _ContextInfo info = new _ContextInfo(); | 152 _ContextInfo info = new _ContextInfo(folder, children); |
| 127 _currentDirectoryInfo[folder] = info; | 153 _contexts[folder] = info; |
| 128 info.changeSubscription = folder.changes.listen((WatchEvent event) { | 154 info.changeSubscription = folder.changes.listen((WatchEvent event) { |
| 129 _handleWatchEvent(folder, info, event); | 155 _handleWatchEvent(folder, info, event); |
| 130 }); | 156 }); |
| 131 File pubspecFile = folder.getChild(PUBSPEC_NAME); | |
| 132 PackageMapInfo packageMapInfo = | 157 PackageMapInfo packageMapInfo = |
| 133 packageMapProvider.computePackageMap(folder); | 158 packageMapProvider.computePackageMap(folder); |
| 134 info.packageMapDependencies = packageMapInfo.dependencies; | 159 info.packageMapDependencies = packageMapInfo.dependencies; |
| 135 // TODO(paulberry): if any of the dependencies is outside of [folder], | 160 // TODO(paulberry): if any of the dependencies is outside of [folder], |
| 136 // we'll need to watch their parent folders as well. | 161 // we'll need to watch their parent folders as well. |
| 137 addContext(folder, packageMapInfo.packageMap); | 162 addContext(folder, packageMapInfo.packageMap); |
| 163 return info; | |
| 164 } | |
| 165 | |
| 166 /** | |
| 167 * Create a new context associated with [folder] and fills its with sources. | |
| 168 */ | |
| 169 _ContextInfo _createContextWithSources(Folder folder, | |
| 170 List<_ContextInfo> children) { | |
| 171 _ContextInfo info = _createContext(folder, children); | |
| 138 ChangeSet changeSet = new ChangeSet(); | 172 ChangeSet changeSet = new ChangeSet(); |
| 139 _addSourceFiles(changeSet, folder, info); | 173 _addSourceFiles(changeSet, folder, info); |
| 140 applyChangesToContext(folder, changeSet); | 174 applyChangesToContext(folder, changeSet); |
| 175 return info; | |
| 176 } | |
| 177 | |
| 178 /** | |
| 179 * Creates a new context associated with [folder]. | |
| 180 * | |
| 181 * If there are subfolders with 'pubspec.yaml' files, separate contexts | |
| 182 * are created for them, and excluded from the context associated with | |
| 183 * [folder]. | |
| 184 * | |
| 185 * If [folder] itself contains a 'pubspec.yaml' file, subfolders are ignored. | |
| 186 * | |
| 187 * Returns create pubspec-based contexts. | |
| 188 */ | |
|
Paul Berry
2014/08/08 16:07:10
Can you document the meaning of "withPubspecOnly"
scheglov
2014/08/08 16:34:23
Done.
| |
| 189 List<_ContextInfo> _createContexts(Folder folder, bool withPubspecOnly) { | |
| 190 // check if there is a pubspec in the folder | |
| 191 { | |
| 192 File pubspecFile = folder.getChild(PUBSPEC_NAME); | |
| 193 if (pubspecFile.exists) { | |
| 194 _ContextInfo info = _createContextWithSources(folder, <_ContextInfo>[]); | |
| 195 return [info]; | |
| 196 } | |
| 197 } | |
| 198 // try to find subfolders with pubspec files | |
| 199 List<_ContextInfo> children = <_ContextInfo>[]; | |
| 200 for (Resource child in folder.getChildren()) { | |
| 201 if (child is Folder) { | |
| 202 List<_ContextInfo> childContexts = _createContexts(child, true); | |
| 203 children.addAll(childContexts); | |
| 204 } | |
| 205 } | |
| 206 // no pubspec, done | |
| 207 if (withPubspecOnly) { | |
| 208 return children; | |
| 209 } | |
| 210 // OK, create a context without a pubspec | |
| 211 _createContextWithSources(folder, children); | |
| 212 return children; | |
| 141 } | 213 } |
| 142 | 214 |
| 143 /** | 215 /** |
| 144 * Clean up and destroy the context associated with the given folder. | 216 * Clean up and destroy the context associated with the given folder. |
| 145 */ | 217 */ |
| 146 void _destroyContext(Folder folder) { | 218 void _destroyContext(Folder folder) { |
| 147 _currentDirectoryInfo[folder].changeSubscription.cancel(); | 219 _contexts[folder].changeSubscription.cancel(); |
| 148 _currentDirectoryInfo.remove(folder); | 220 _contexts.remove(folder); |
| 149 removeContext(folder); | 221 removeContext(folder); |
| 150 } | 222 } |
| 151 | 223 |
| 224 /** | |
| 225 * Extract a new [pubspecFile]-based context from [oldInfo]. | |
| 226 */ | |
| 227 void _extractContext(_ContextInfo oldInfo, File pubspecFile) { | |
| 228 Folder newFolder = pubspecFile.parent; | |
| 229 _ContextInfo newInfo = _createContext(newFolder, []); | |
| 230 newInfo.parent = oldInfo; | |
| 231 // prepare sources to extract | |
| 232 Map<String, Source> extractSources = new HashMap<String, Source>(); | |
|
Paul Berry
2014/08/08 16:07:10
Rename to "extractedSources"
scheglov
2014/08/08 16:34:23
Done.
| |
| 233 oldInfo.sources.forEach((path, source) { | |
| 234 if (newFolder.contains(path)) { | |
| 235 extractSources[path] = source; | |
| 236 } | |
| 237 }); | |
| 238 // update new context | |
| 239 { | |
| 240 ChangeSet changeSet = new ChangeSet(); | |
| 241 extractSources.forEach((path, source) { | |
| 242 newInfo.sources[path] = source; | |
| 243 changeSet.addedSource(source); | |
| 244 }); | |
| 245 applyChangesToContext(newFolder, changeSet); | |
| 246 } | |
| 247 // update old context | |
| 248 { | |
| 249 ChangeSet changeSet = new ChangeSet(); | |
| 250 extractSources.forEach((path, source) { | |
| 251 oldInfo.sources.remove(path); | |
| 252 changeSet.removedSource(source); | |
| 253 }); | |
| 254 applyChangesToContext(oldInfo.folder, changeSet); | |
| 255 } | |
| 256 } | |
| 257 | |
| 152 void _handleWatchEvent(Folder folder, _ContextInfo info, WatchEvent event) { | 258 void _handleWatchEvent(Folder folder, _ContextInfo info, WatchEvent event) { |
| 259 String path = event.path; | |
| 260 // maybe excluded, so other context will handle it | |
| 261 if (info.excludes(path)) { | |
| 262 return; | |
| 263 } | |
| 264 // handle the change | |
| 153 switch (event.type) { | 265 switch (event.type) { |
| 154 case ChangeType.ADD: | 266 case ChangeType.ADD: |
| 155 if (_isInPackagesDir(event.path, folder)) { | 267 if (_isInPackagesDir(path, folder)) { |
| 156 // TODO(paulberry): perhaps we should only skip packages dirs if | 268 // TODO(paulberry): perhaps we should only skip packages dirs if |
| 157 // there is a pubspec.yaml? | 269 // there is a pubspec.yaml? |
| 158 break; | 270 break; |
| 159 } | 271 } |
| 160 Resource resource = resourceProvider.getResource(event.path); | 272 Resource resource = resourceProvider.getResource(path); |
| 273 // pubspec was added, extract a new context | |
| 274 if (_isPubspec(path)) { | |
| 275 _extractContext(info, resource); | |
| 276 return; | |
| 277 } | |
| 161 // If the file went away and was replaced by a folder before we | 278 // If the file went away and was replaced by a folder before we |
| 162 // had a chance to process the event, resource might be a Folder. In | 279 // had a chance to process the event, resource might be a Folder. In |
| 163 // that case don't add it. | 280 // that case don't add it. |
| 164 if (resource is File) { | 281 if (resource is File) { |
| 165 File file = resource; | 282 File file = resource; |
| 166 if (_shouldFileBeAnalyzed(file)) { | 283 if (_shouldFileBeAnalyzed(file)) { |
| 167 ChangeSet changeSet = new ChangeSet(); | 284 ChangeSet changeSet = new ChangeSet(); |
| 168 Source source = file.createSource(); | 285 Source source = file.createSource(); |
| 169 changeSet.addedSource(source); | 286 changeSet.addedSource(source); |
| 170 applyChangesToContext(folder, changeSet); | 287 applyChangesToContext(folder, changeSet); |
| 171 info.sources[event.path] = source; | 288 info.sources[path] = source; |
| 172 } | 289 } |
| 173 } | 290 } |
| 174 break; | 291 break; |
| 175 case ChangeType.REMOVE: | 292 case ChangeType.REMOVE: |
| 176 Source source = info.sources[event.path]; | 293 // pubspec was removed, merge the context into its parent |
| 294 if (info.isPubspec(path)) { | |
| 295 _mergeContext(info); | |
| 296 return; | |
| 297 } | |
| 298 Source source = info.sources[path]; | |
| 177 if (source != null) { | 299 if (source != null) { |
| 178 ChangeSet changeSet = new ChangeSet(); | 300 ChangeSet changeSet = new ChangeSet(); |
| 179 changeSet.removedSource(source); | 301 changeSet.removedSource(source); |
| 180 applyChangesToContext(folder, changeSet); | 302 applyChangesToContext(folder, changeSet); |
| 181 info.sources.remove(event.path); | 303 info.sources.remove(path); |
| 182 } | 304 } |
| 183 break; | 305 break; |
| 184 case ChangeType.MODIFY: | 306 case ChangeType.MODIFY: |
| 185 Source source = info.sources[event.path]; | 307 Source source = info.sources[path]; |
| 186 if (source != null) { | 308 if (source != null) { |
| 187 ChangeSet changeSet = new ChangeSet(); | 309 ChangeSet changeSet = new ChangeSet(); |
| 188 changeSet.changedSource(source); | 310 changeSet.changedSource(source); |
| 189 applyChangesToContext(folder, changeSet); | 311 applyChangesToContext(folder, changeSet); |
| 190 } | 312 } |
| 191 break; | 313 break; |
| 192 } | 314 } |
| 193 | 315 |
| 194 if (info.packageMapDependencies.contains(event.path)) { | 316 if (info.packageMapDependencies.contains(path)) { |
| 195 // TODO(paulberry): when computePackageMap is changed into an | 317 // TODO(paulberry): when computePackageMap is changed into an |
| 196 // asynchronous API call, we'll want to suspend analysis for this context | 318 // asynchronous API call, we'll want to suspend analysis for this context |
| 197 // while we're rerunning "pub list", since any analysis we complete while | 319 // while we're rerunning "pub list", since any analysis we complete while |
| 198 // "pub list" is in progress is just going to get thrown away anyhow. | 320 // "pub list" is in progress is just going to get thrown away anyhow. |
| 199 PackageMapInfo packageMapInfo = | 321 PackageMapInfo packageMapInfo = |
| 200 packageMapProvider.computePackageMap(folder); | 322 packageMapProvider.computePackageMap(folder); |
| 201 info.packageMapDependencies = packageMapInfo.dependencies; | 323 info.packageMapDependencies = packageMapInfo.dependencies; |
| 202 updateContextPackageMap(folder, packageMapInfo.packageMap); | 324 updateContextPackageMap(folder, packageMapInfo.packageMap); |
| 203 } | 325 } |
| 204 } | 326 } |
| 205 | 327 |
| 206 /** | 328 /** |
| 207 * Determine if the path from [folder] to [path] contains a 'packages' | 329 * Determine if the path from [folder] to [path] contains a 'packages' |
| 208 * directory. | 330 * directory. |
| 209 */ | 331 */ |
| 210 bool _isInPackagesDir(String path, Folder folder) { | 332 bool _isInPackagesDir(String path, Folder folder) { |
| 211 String relativePath = | 333 String relativePath = pathContext.relative(path, from: folder.path); |
| 212 resourceProvider.pathContext.relative(path, from: folder.path); | 334 List<String> pathParts = pathContext.split(relativePath); |
| 213 List<String> pathParts = resourceProvider.pathContext.split(relativePath); | |
| 214 for (int i = 0; i < pathParts.length - 1; i++) { | 335 for (int i = 0; i < pathParts.length - 1; i++) { |
| 215 if (pathParts[i] == 'packages') { | 336 if (pathParts[i] == 'packages') { |
| 216 return true; | 337 return true; |
| 217 } | 338 } |
| 218 } | 339 } |
| 219 return false; | 340 return false; |
| 220 } | 341 } |
| 221 | 342 |
| 222 /** | 343 /** |
| 344 * Returns `true` if the given absolute [path] is a pubspec file. | |
| 345 */ | |
| 346 bool _isPubspec(String path) { | |
| 347 return pathContext.basename(path) == PUBSPEC_NAME; | |
| 348 } | |
| 349 | |
| 350 /** | |
| 351 * Merges [info] context into its parent. | |
| 352 */ | |
| 353 void _mergeContext(_ContextInfo info) { | |
| 354 // destroy the context | |
| 355 _destroyContext(info.folder); | |
| 356 // add files to the parent context | |
| 357 _ContextInfo parentInfo = info.parent; | |
| 358 if (parentInfo != null) { | |
| 359 parentInfo.children.remove(info); | |
| 360 ChangeSet changeSet = new ChangeSet(); | |
| 361 _addSourceFiles(changeSet, info.folder, parentInfo); | |
|
Paul Berry
2014/08/08 16:07:10
It looks like this will re-read the directory cont
scheglov
2014/08/08 16:34:23
Done.
| |
| 362 applyChangesToContext(parentInfo.folder, changeSet); | |
| 363 } | |
| 364 } | |
| 365 | |
| 366 /** | |
| 223 * Resursively adds all Dart and HTML files to the [changeSet]. | 367 * Resursively adds all Dart and HTML files to the [changeSet]. |
| 224 */ | 368 */ |
| 225 static void _addSourceFiles(ChangeSet changeSet, Folder folder, | 369 static void _addSourceFiles(ChangeSet changeSet, Folder folder, |
| 226 _ContextInfo info) { | 370 _ContextInfo info) { |
| 371 if (info.excludesResource(folder)) { | |
| 372 return; | |
| 373 } | |
| 227 List<Resource> children = folder.getChildren(); | 374 List<Resource> children = folder.getChildren(); |
| 228 for (Resource child in children) { | 375 for (Resource child in children) { |
| 229 if (child is File) { | 376 if (child is File) { |
| 230 if (_shouldFileBeAnalyzed(child)) { | 377 if (_shouldFileBeAnalyzed(child)) { |
| 231 Source source = child.createSource(); | 378 Source source = child.createSource(); |
| 232 changeSet.addedSource(source); | 379 changeSet.addedSource(source); |
| 233 info.sources[child.path] = source; | 380 info.sources[child.path] = source; |
| 234 } | 381 } |
| 235 } else if (child is Folder) { | 382 } else if (child is Folder) { |
| 236 if (child.shortName == 'packages') { | 383 if (child.shortName == 'packages') { |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 255 // causing the analyzer to thrash, just ignore links to non-existent files. | 402 // causing the analyzer to thrash, just ignore links to non-existent files. |
| 256 return file.exists; | 403 return file.exists; |
| 257 } | 404 } |
| 258 } | 405 } |
| 259 | 406 |
| 260 /** | 407 /** |
| 261 * Information tracked by the [ContextManager] for each context. | 408 * Information tracked by the [ContextManager] for each context. |
| 262 */ | 409 */ |
| 263 class _ContextInfo { | 410 class _ContextInfo { |
| 264 /** | 411 /** |
| 412 * The [Folder] for which this information object is created. | |
| 413 */ | |
| 414 final Folder folder; | |
| 415 | |
| 416 /** | |
| 417 * The enclosed pubspec-based contexts. | |
| 418 */ | |
| 419 final List<_ContextInfo> children; | |
| 420 | |
| 421 /** | |
| 422 * The [_ContextInfo] that encloses this one. | |
| 423 */ | |
| 424 _ContextInfo parent; | |
| 425 | |
| 426 /** | |
| 427 * The `pubspec.yaml` file path for this context. | |
| 428 */ | |
| 429 String pubspecPath; | |
| 430 | |
| 431 /** | |
| 265 * Stream subscription we are using to watch the context's directory for | 432 * Stream subscription we are using to watch the context's directory for |
| 266 * changes. | 433 * changes. |
| 267 */ | 434 */ |
| 268 StreamSubscription<WatchEvent> changeSubscription; | 435 StreamSubscription<WatchEvent> changeSubscription; |
| 269 | 436 |
| 270 /** | 437 /** |
| 271 * Map from full path to the [Source] object, for each source that has been | 438 * Map from full path to the [Source] object, for each source that has been |
| 272 * added to the context. | 439 * added to the context. |
| 273 */ | 440 */ |
| 274 Map<String, Source> sources = new HashMap<String, Source>(); | 441 Map<String, Source> sources = new HashMap<String, Source>(); |
| 275 | 442 |
| 276 /** | 443 /** |
| 277 * Dependencies of the context's package map. | 444 * Dependencies of the context's package map. |
| 278 * If any of these files changes, the package map needs to be recomputed. | 445 * If any of these files changes, the package map needs to be recomputed. |
| 279 */ | 446 */ |
| 280 Set<String> packageMapDependencies; | 447 Set<String> packageMapDependencies; |
| 448 | |
| 449 _ContextInfo(this.folder, this.children) { | |
| 450 pubspecPath = folder.getChild(PUBSPEC_NAME).path; | |
| 451 for (_ContextInfo child in children) { | |
| 452 child.parent = this; | |
| 453 } | |
| 454 } | |
| 455 | |
| 456 /** | |
| 457 * Returns `true` if [path] is excluded, as it is in one of the children. | |
| 458 */ | |
| 459 bool excludes(String path) { | |
| 460 return children.any((child) { | |
| 461 return child.folder.contains(path); | |
| 462 }); | |
| 463 } | |
| 464 | |
| 465 /** | |
| 466 * Returns `true` if [resource] is excldued, as it is in one of the children. | |
| 467 */ | |
| 468 bool excludesResource(Resource resource) { | |
| 469 return excludes(resource.path); | |
| 470 } | |
| 471 | |
| 472 /** | |
| 473 * Returns `true` if [path] is the pubspec file of this context. | |
| 474 */ | |
| 475 bool isPubspec(String path) { | |
| 476 return path == pubspecPath; | |
| 477 } | |
| 281 } | 478 } |
| OLD | NEW |