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/resource.dart'; | 10 import 'package:analysis_server/src/resource.dart'; |
| 11 import 'package:analyzer/src/generated/engine.dart'; | 11 import 'package:analyzer/src/generated/engine.dart'; |
| 12 import 'package:analyzer/src/generated/source.dart'; | 12 import 'package:analyzer/src/generated/source.dart'; |
| 13 import 'package:watcher/watcher.dart'; | 13 import 'package:watcher/watcher.dart'; |
| 14 | 14 |
| 15 /** | 15 /** |
| 16 * Information tracked by the [ContextDirectoryManager] for each context. | 16 * Information tracked by the [ContextDirectoryManager] for each context. |
| 17 */ | 17 */ |
| 18 class _ContextDirectoryInfo { | 18 class _ContextDirectoryInfo { |
| 19 /** | 19 /** |
| 20 * Stream subscription we are using to watch the context's directory for | 20 * Stream subscription we are using to watch the context's directory for |
| 21 * changes. | 21 * changes. |
| 22 */ | 22 */ |
| 23 StreamSubscription<WatchEvent> changeSubscription; | 23 StreamSubscription<WatchEvent> changeSubscription; |
| 24 | 24 |
| 25 /** | 25 /** |
| 26 * Map from full path to the [Source] object, for each source that has been | 26 * Map from full path to the [Source] object, for each source that has been |
| 27 * added to the context. | 27 * added to the context. |
| 28 */ | 28 */ |
| 29 Map<String, Source> sources = new HashMap<String, Source>(); | 29 Map<String, Source> sources = new HashMap<String, Source>(); |
| 30 | |
| 31 /** | |
| 32 * Pubspec file for this context, if there is one. Otherwise null. | |
| 33 */ | |
| 34 File pubspecFile = null; | |
|
scheglov
2014/06/18 18:32:04
Do we need "= null"?
Paul Berry
2014/06/19 14:55:15
Technically, it's redundant, since uninitialized v
| |
| 35 | |
| 36 /** | |
| 37 * Path to that the pubspec file for this context would have, if it has one. | |
| 38 * Otherwise path that the pubspec file would have. | |
| 39 */ | |
| 40 String pubspecPath; | |
| 30 } | 41 } |
| 31 | 42 |
| 32 /** | 43 /** |
| 33 * Class that maintains a mapping from included/excluded paths to a set of | 44 * Class that maintains a mapping from included/excluded paths to a set of |
| 34 * folders that should correspond to analysis contexts. | 45 * folders that should correspond to analysis contexts. |
| 35 */ | 46 */ |
| 36 abstract class ContextDirectoryManager { | 47 abstract class ContextDirectoryManager { |
| 37 /** | 48 /** |
| 49 * File name of pubspec files. | |
| 50 */ | |
| 51 static String PUBSPEC_NAME = 'pubspec.yaml'; | |
|
scheglov
2014/06/18 18:32:04
static const?
Paul Berry
2014/06/19 14:55:15
Done.
| |
| 52 | |
| 53 /** | |
| 38 * [_ContextDirectoryInfo] object for each included directory in the most | 54 * [_ContextDirectoryInfo] object for each included directory in the most |
| 39 * recent successful call to [setRoots]. | 55 * recent successful call to [setRoots]. |
| 40 */ | 56 */ |
| 41 Map<Folder, _ContextDirectoryInfo> _currentDirectoryInfo = | 57 Map<Folder, _ContextDirectoryInfo> _currentDirectoryInfo = |
| 42 new HashMap<Folder, _ContextDirectoryInfo>(); | 58 new HashMap<Folder, _ContextDirectoryInfo>(); |
| 43 | 59 |
| 44 /** | 60 /** |
| 45 * The [ResourceProvider] using which paths are converted into [Resource]s. | 61 * The [ResourceProvider] using which paths are converted into [Resource]s. |
| 46 */ | 62 */ |
| 47 final ResourceProvider resourceProvider; | 63 final ResourceProvider resourceProvider; |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 72 // TODO(scheglov) remove when implemented | 88 // TODO(scheglov) remove when implemented |
| 73 if (excludedPaths.isNotEmpty) { | 89 if (excludedPaths.isNotEmpty) { |
| 74 throw new UnimplementedError( | 90 throw new UnimplementedError( |
| 75 'Excluded paths are not supported yet'); | 91 'Excluded paths are not supported yet'); |
| 76 } | 92 } |
| 77 Set<Folder> excludedFolders = new HashSet<Folder>(); | 93 Set<Folder> excludedFolders = new HashSet<Folder>(); |
| 78 // diff | 94 // diff |
| 79 Set<Folder> currentFolders = _currentDirectoryInfo.keys.toSet(); | 95 Set<Folder> currentFolders = _currentDirectoryInfo.keys.toSet(); |
| 80 Set<Folder> newFolders = includedFolders.difference(currentFolders); | 96 Set<Folder> newFolders = includedFolders.difference(currentFolders); |
| 81 Set<Folder> oldFolders = currentFolders.difference(includedFolders); | 97 Set<Folder> oldFolders = currentFolders.difference(includedFolders); |
| 82 // remove old contexts | 98 // remove old contexts |
|
scheglov
2014/06/18 18:32:04
"destroy old contexts" ?
Paul Berry
2014/06/19 14:55:15
Done.
| |
| 83 for (Folder folder in oldFolders) { | 99 for (Folder folder in oldFolders) { |
| 84 _currentDirectoryInfo.remove(folder); | 100 _destroyContext(folder); |
| 85 removeContext(folder); | |
| 86 } | 101 } |
| 87 // add new contexts | 102 // add new contexts |
|
scheglov
2014/06/18 18:32:04
"create new contexts"?
Paul Berry
2014/06/19 14:55:15
Done.
| |
| 88 for (Folder folder in newFolders) { | 103 for (Folder folder in newFolders) { |
| 89 _ContextDirectoryInfo info = new _ContextDirectoryInfo(); | 104 _createContext(folder); |
| 90 _currentDirectoryInfo[folder] = info; | |
| 91 info.changeSubscription = folder.changes.listen((WatchEvent event) { | |
| 92 _handleWatchEvent(folder, info, event); | |
| 93 }); | |
| 94 File pubspecFile = folder.getChild('pubspec.yaml'); | |
| 95 addContext(folder, pubspecFile.exists ? pubspecFile : null); | |
| 96 ChangeSet changeSet = new ChangeSet(); | |
| 97 _addSourceFiles(changeSet, folder, info); | |
| 98 applyChangesToContext(folder, changeSet); | |
| 99 } | 105 } |
| 100 } | 106 } |
| 101 | 107 |
| 108 /** | |
| 109 * Create a new context associated with the given folder. | |
| 110 */ | |
| 111 void _createContext(Folder folder) { | |
| 112 _ContextDirectoryInfo info = new _ContextDirectoryInfo(); | |
| 113 _currentDirectoryInfo[folder] = info; | |
| 114 info.changeSubscription = folder.changes.listen((WatchEvent event) { | |
| 115 _handleWatchEvent(folder, info, event); | |
| 116 }); | |
| 117 File pubspecFile = folder.getChild(PUBSPEC_NAME); | |
| 118 info.pubspecPath = pubspecFile.path; | |
| 119 if (pubspecFile.exists) { | |
| 120 info.pubspecFile = pubspecFile; | |
| 121 } | |
| 122 addContext(folder, info.pubspecFile); | |
| 123 ChangeSet changeSet = new ChangeSet(); | |
| 124 _addSourceFiles(changeSet, folder, info); | |
| 125 applyChangesToContext(folder, changeSet); | |
| 126 } | |
| 127 | |
| 128 /** | |
| 129 * Clean up and destroy the context associated with the given folder. | |
| 130 */ | |
| 131 void _destroyContext(Folder folder) { | |
| 132 _currentDirectoryInfo[folder].changeSubscription.cancel(); | |
| 133 _currentDirectoryInfo.remove(folder); | |
| 134 removeContext(folder); | |
| 135 } | |
| 136 | |
| 102 void _handleWatchEvent(Folder folder, _ContextDirectoryInfo info, WatchEvent e vent) { | 137 void _handleWatchEvent(Folder folder, _ContextDirectoryInfo info, WatchEvent e vent) { |
| 103 switch (event.type) { | 138 switch (event.type) { |
| 104 case ChangeType.ADD: | 139 case ChangeType.ADD: |
| 105 if (_isInPackagesDir(event.path, folder)) { | 140 if (_isInPackagesDir(event.path, folder)) { |
| 106 // TODO(paulberry): perhaps we should only skip packages dirs if | 141 // TODO(paulberry): perhaps we should only skip packages dirs if |
| 107 // there is a pubspec.yaml? | 142 // there is a pubspec.yaml? |
| 108 break; | 143 break; |
| 109 } | 144 } |
| 110 // TODO(paulberry): handle adding pubspec.yaml | 145 if (info.pubspecFile == null && event.path == info.pubspecPath) { |
| 146 // Pubspec file added. This is likely to be such a rare event that | |
| 147 // there's no need to try to be clever. Just destroy the old context | |
| 148 // and create a new one. | |
| 149 _destroyContext(folder); | |
| 150 _createContext(folder); | |
| 151 return; | |
| 152 } | |
| 111 if (_shouldFileBeAnalyzed(event.path)) { | 153 if (_shouldFileBeAnalyzed(event.path)) { |
| 112 ChangeSet changeSet = new ChangeSet(); | 154 ChangeSet changeSet = new ChangeSet(); |
| 113 Resource resource = resourceProvider.getResource(event.path); | 155 Resource resource = resourceProvider.getResource(event.path); |
| 114 // If the file went away and was replaced by a folder before we | 156 // If the file went away and was replaced by a folder before we |
| 115 // had a chance to process the event, resource might be a Folder. In | 157 // had a chance to process the event, resource might be a Folder. In |
| 116 // that case don't add it. | 158 // that case don't add it. |
| 117 if (resource is File) { | 159 if (resource is File) { |
| 118 File file = resource; | 160 File file = resource; |
| 119 Source source = file.createSource(UriKind.FILE_URI); | 161 Source source = file.createSource(UriKind.FILE_URI); |
| 120 changeSet.addedSource(source); | 162 changeSet.addedSource(source); |
| 121 applyChangesToContext(folder, changeSet); | 163 applyChangesToContext(folder, changeSet); |
| 122 info.sources[event.path]= source; | 164 info.sources[event.path]= source; |
| 123 } | 165 } |
| 124 } | 166 } |
| 125 break; | 167 break; |
| 126 case ChangeType.REMOVE: | 168 case ChangeType.REMOVE: |
| 169 if (info.pubspecFile != null && event.path == info.pubspecPath) { | |
| 170 // Pubspec file removed. This is likely to be such a rare event that | |
| 171 // there's no need to try to be clever. Just destroy the old context | |
| 172 // and create a new one. | |
| 173 _destroyContext(folder); | |
| 174 _createContext(folder); | |
| 175 return; | |
| 176 } | |
| 127 // TODO(paulberry): handle removing pubspec.yaml | 177 // TODO(paulberry): handle removing pubspec.yaml |
| 128 Source source = info.sources[event.path]; | 178 Source source = info.sources[event.path]; |
| 129 if (source != null) { | 179 if (source != null) { |
| 130 ChangeSet changeSet = new ChangeSet(); | 180 ChangeSet changeSet = new ChangeSet(); |
| 131 changeSet.removedSource(source); | 181 changeSet.removedSource(source); |
| 132 applyChangesToContext(folder, changeSet); | 182 applyChangesToContext(folder, changeSet); |
| 133 info.sources.remove(event.path); | 183 info.sources.remove(event.path); |
| 134 } | 184 } |
| 135 break; | 185 break; |
| 136 case ChangeType.MODIFY: | 186 case ChangeType.MODIFY: |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 199 * some of those files have been modified). [changeSet] is the set of | 249 * some of those files have been modified). [changeSet] is the set of |
| 200 * changes that need to be applied to the context. | 250 * changes that need to be applied to the context. |
| 201 */ | 251 */ |
| 202 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet); | 252 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet); |
| 203 | 253 |
| 204 /** | 254 /** |
| 205 * Remove the context associated with the given [folder]. | 255 * Remove the context associated with the given [folder]. |
| 206 */ | 256 */ |
| 207 void removeContext(Folder folder); | 257 void removeContext(Folder folder); |
| 208 } | 258 } |
| OLD | NEW |