| 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 analyzer.file_system.memory_file_system; | 5 library analyzer.file_system.memory_file_system; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 import 'dart:core' hide Resource; | 9 import 'dart:core' hide Resource; |
| 10 | 10 |
| 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' show TimestampedData; | 12 import 'package:analyzer/src/generated/engine.dart' show TimestampedData; |
| 13 import 'package:analyzer/src/generated/source_io.dart'; | 13 import 'package:analyzer/src/generated/source_io.dart'; |
| 14 import 'package:analyzer/src/util/absolute_path.dart'; | 14 import 'package:analyzer/src/util/absolute_path.dart'; |
| 15 import 'package:path/path.dart'; | 15 import 'package:path/path.dart'; |
| 16 import 'package:watcher/watcher.dart'; | 16 import 'package:watcher/watcher.dart'; |
| 17 | 17 |
| 18 /** | 18 /** |
| 19 * An in-memory implementation of [ResourceProvider]. | 19 * An in-memory implementation of [ResourceProvider]. |
| 20 * Use `/` as a path separator. | 20 * Use `/` as a path separator. |
| 21 */ | 21 */ |
| 22 class MemoryResourceProvider implements ResourceProvider { | 22 class MemoryResourceProvider implements ResourceProvider { |
| 23 final Map<String, _MemoryResource> _pathToResource = | 23 final Map<String, _MemoryResource> _pathToResource = |
| 24 new HashMap<String, _MemoryResource>(); | 24 new HashMap<String, _MemoryResource>(); |
| 25 final Map<String, String> _pathToContent = new HashMap<String, String>(); | 25 final Map<String, String> _pathToContent = new HashMap<String, String>(); |
| 26 final Map<String, List<int>> _pathToBytes = new HashMap<String, List<int>>(); |
| 26 final Map<String, int> _pathToTimestamp = new HashMap<String, int>(); | 27 final Map<String, int> _pathToTimestamp = new HashMap<String, int>(); |
| 27 final Map<String, List<StreamController<WatchEvent>>> _pathToWatchers = | 28 final Map<String, List<StreamController<WatchEvent>>> _pathToWatchers = |
| 28 new HashMap<String, List<StreamController<WatchEvent>>>(); | 29 new HashMap<String, List<StreamController<WatchEvent>>>(); |
| 29 int nextStamp = 0; | 30 int nextStamp = 0; |
| 30 | 31 |
| 31 final Context _pathContext; | 32 final Context _pathContext; |
| 32 @override | 33 @override |
| 33 final AbsolutePathContext absolutePathContext; | 34 final AbsolutePathContext absolutePathContext; |
| 34 | 35 |
| 35 MemoryResourceProvider({bool isWindows: false}) | 36 MemoryResourceProvider({bool isWindows: false}) |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 newFolder(pathContext.dirname(path)); | 110 newFolder(pathContext.dirname(path)); |
| 110 _MemoryDummyLink link = new _MemoryDummyLink(this, path); | 111 _MemoryDummyLink link = new _MemoryDummyLink(this, path); |
| 111 _pathToResource[path] = link; | 112 _pathToResource[path] = link; |
| 112 _pathToTimestamp[path] = nextStamp++; | 113 _pathToTimestamp[path] = nextStamp++; |
| 113 _notifyWatchers(path, ChangeType.ADD); | 114 _notifyWatchers(path, ChangeType.ADD); |
| 114 return link; | 115 return link; |
| 115 } | 116 } |
| 116 | 117 |
| 117 File newFile(String path, String content, [int stamp]) { | 118 File newFile(String path, String content, [int stamp]) { |
| 118 path = pathContext.normalize(path); | 119 path = pathContext.normalize(path); |
| 119 _MemoryResource folder = _pathToResource[pathContext.dirname(path)]; | 120 _MemoryFile file = _newFile(path); |
| 120 if (folder == null) { | |
| 121 newFolder(pathContext.dirname(path)); | |
| 122 } else if (folder is! Folder) { | |
| 123 throw new ArgumentError('Cannot create file ($path) as child of file'); | |
| 124 } | |
| 125 _MemoryFile file = new _MemoryFile(this, path); | |
| 126 _pathToResource[path] = file; | |
| 127 _pathToContent[path] = content; | 121 _pathToContent[path] = content; |
| 128 _pathToTimestamp[path] = stamp != null ? stamp : nextStamp++; | 122 _pathToTimestamp[path] = stamp ?? nextStamp++; |
| 129 _notifyWatchers(path, ChangeType.ADD); | 123 _notifyWatchers(path, ChangeType.ADD); |
| 130 return file; | 124 return file; |
| 131 } | 125 } |
| 126 |
| 127 File newFileWithBytes(String path, List<int> bytes, [int stamp]) { |
| 128 path = pathContext.normalize(path); |
| 129 _MemoryFile file = _newFile(path); |
| 130 _pathToBytes[path] = bytes; |
| 131 _pathToTimestamp[path] = stamp ?? nextStamp++; |
| 132 _notifyWatchers(path, ChangeType.ADD); |
| 133 return file; |
| 134 } |
| 132 | 135 |
| 133 Folder newFolder(String path) { | 136 Folder newFolder(String path) { |
| 134 path = pathContext.normalize(path); | 137 path = pathContext.normalize(path); |
| 135 if (!pathContext.isAbsolute(path)) { | 138 if (!pathContext.isAbsolute(path)) { |
| 136 throw new ArgumentError("Path must be absolute : $path"); | 139 throw new ArgumentError("Path must be absolute : $path"); |
| 137 } | 140 } |
| 138 _MemoryResource resource = _pathToResource[path]; | 141 _MemoryResource resource = _pathToResource[path]; |
| 139 if (resource == null) { | 142 if (resource == null) { |
| 140 String parentPath = pathContext.dirname(path); | 143 String parentPath = pathContext.dirname(path); |
| 141 if (parentPath != path) { | 144 if (parentPath != path) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 176 } | 179 } |
| 177 | 180 |
| 178 void _checkFolderAtPath(String path) { | 181 void _checkFolderAtPath(String path) { |
| 179 _MemoryResource resource = _pathToResource[path]; | 182 _MemoryResource resource = _pathToResource[path]; |
| 180 if (resource is! _MemoryFolder) { | 183 if (resource is! _MemoryFolder) { |
| 181 throw new ArgumentError( | 184 throw new ArgumentError( |
| 182 'Folder expected at "$path" but ${resource.runtimeType} found'); | 185 'Folder expected at "$path" but ${resource.runtimeType} found'); |
| 183 } | 186 } |
| 184 } | 187 } |
| 185 | 188 |
| 189 /** |
| 190 * Create a new [_MemoryFile] without any content. |
| 191 */ |
| 192 _MemoryFile _newFile(String path) { |
| 193 String folderPath = pathContext.dirname(path); |
| 194 _MemoryResource folder = _pathToResource[folderPath]; |
| 195 if (folder == null) { |
| 196 newFolder(folderPath); |
| 197 } else if (folder is! Folder) { |
| 198 throw new ArgumentError('Cannot create file ($path) as child of file'); |
| 199 } |
| 200 _MemoryFile file = new _MemoryFile(this, path); |
| 201 _pathToResource[path] = file; |
| 202 return file; |
| 203 } |
| 204 |
| 186 void _notifyWatchers(String path, ChangeType changeType) { | 205 void _notifyWatchers(String path, ChangeType changeType) { |
| 187 _pathToWatchers.forEach((String watcherPath, | 206 _pathToWatchers.forEach((String watcherPath, |
| 188 List<StreamController<WatchEvent>> streamControllers) { | 207 List<StreamController<WatchEvent>> streamControllers) { |
| 189 if (watcherPath == path || pathContext.isWithin(watcherPath, path)) { | 208 if (watcherPath == path || pathContext.isWithin(watcherPath, path)) { |
| 190 for (StreamController<WatchEvent> streamController | 209 for (StreamController<WatchEvent> streamController |
| 191 in streamControllers) { | 210 in streamControllers) { |
| 192 streamController.add(new WatchEvent(changeType, path)); | 211 streamController.add(new WatchEvent(changeType, path)); |
| 193 } | 212 } |
| 194 } | 213 } |
| 195 }); | 214 }); |
| 196 } | 215 } |
| 216 |
| 217 void _setFileBytes(String path, List<int> bytes) { |
| 218 _pathToBytes[path] = bytes; |
| 219 _pathToTimestamp[path] = nextStamp++; |
| 220 _notifyWatchers(path, ChangeType.MODIFY); |
| 221 } |
| 197 } | 222 } |
| 198 | 223 |
| 199 /** | 224 /** |
| 200 * An in-memory implementation of [File] which acts like a symbolic link to a | 225 * An in-memory implementation of [File] which acts like a symbolic link to a |
| 201 * non-existent file. | 226 * non-existent file. |
| 202 */ | 227 */ |
| 203 class _MemoryDummyLink extends _MemoryResource implements File { | 228 class _MemoryDummyLink extends _MemoryResource implements File { |
| 204 _MemoryDummyLink(MemoryResourceProvider provider, String path) | 229 _MemoryDummyLink(MemoryResourceProvider provider, String path) |
| 205 : super(provider, path); | 230 : super(provider, path); |
| 206 | 231 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 229 Source createSource([Uri uri]) { | 254 Source createSource([Uri uri]) { |
| 230 throw new FileSystemException(path, 'File could not be read'); | 255 throw new FileSystemException(path, 'File could not be read'); |
| 231 } | 256 } |
| 232 | 257 |
| 233 @override | 258 @override |
| 234 bool isOrContains(String path) { | 259 bool isOrContains(String path) { |
| 235 return path == this.path; | 260 return path == this.path; |
| 236 } | 261 } |
| 237 | 262 |
| 238 @override | 263 @override |
| 264 List<int> readAsBytesSync() { |
| 265 throw new FileSystemException(path, 'File could not be read'); |
| 266 } |
| 267 |
| 268 @override |
| 239 String readAsStringSync() { | 269 String readAsStringSync() { |
| 240 throw new FileSystemException(path, 'File could not be read'); | 270 throw new FileSystemException(path, 'File could not be read'); |
| 241 } | 271 } |
| 272 |
| 273 @override |
| 274 void writeAsBytesSync(List<int> bytes) { |
| 275 throw new FileSystemException(path, 'File could not be written'); |
| 276 } |
| 242 } | 277 } |
| 243 | 278 |
| 244 /** | 279 /** |
| 245 * An in-memory implementation of [File]. | 280 * An in-memory implementation of [File]. |
| 246 */ | 281 */ |
| 247 class _MemoryFile extends _MemoryResource implements File { | 282 class _MemoryFile extends _MemoryResource implements File { |
| 248 _MemoryFile(MemoryResourceProvider provider, String path) | 283 _MemoryFile(MemoryResourceProvider provider, String path) |
| 249 : super(provider, path); | 284 : super(provider, path); |
| 250 | 285 |
| 251 @override | 286 @override |
| (...skipping 23 matching lines...) Expand all Loading... |
| 275 } | 310 } |
| 276 return new _MemoryFileSource(this, uri); | 311 return new _MemoryFileSource(this, uri); |
| 277 } | 312 } |
| 278 | 313 |
| 279 @override | 314 @override |
| 280 bool isOrContains(String path) { | 315 bool isOrContains(String path) { |
| 281 return path == this.path; | 316 return path == this.path; |
| 282 } | 317 } |
| 283 | 318 |
| 284 @override | 319 @override |
| 320 List<int> readAsBytesSync() { |
| 321 List<int> bytes = _provider._pathToBytes[path]; |
| 322 if (bytes == null) { |
| 323 throw new FileSystemException(path, 'File "$path" is not binary.'); |
| 324 } |
| 325 return bytes; |
| 326 } |
| 327 |
| 328 @override |
| 285 String readAsStringSync() { | 329 String readAsStringSync() { |
| 286 String content = _provider._pathToContent[path]; | 330 String content = _provider._pathToContent[path]; |
| 287 if (content == null) { | 331 if (content == null) { |
| 288 throw new FileSystemException(path, 'File "$path" does not exist.'); | 332 throw new FileSystemException(path, 'File "$path" does not exist.'); |
| 289 } | 333 } |
| 290 return content; | 334 return content; |
| 291 } | 335 } |
| 336 |
| 337 @override |
| 338 void writeAsBytesSync(List<int> bytes) { |
| 339 _provider._setFileBytes(path, bytes); |
| 340 } |
| 292 } | 341 } |
| 293 | 342 |
| 294 /** | 343 /** |
| 295 * An in-memory implementation of [Source]. | 344 * An in-memory implementation of [Source]. |
| 296 */ | 345 */ |
| 297 class _MemoryFileSource extends Source { | 346 class _MemoryFileSource extends Source { |
| 298 /** | 347 /** |
| 299 * Map from encoded URI/filepath pair to a unique integer identifier. This | 348 * Map from encoded URI/filepath pair to a unique integer identifier. This |
| 300 * identifier is used for equality tests and hash codes. | 349 * identifier is used for equality tests and hash codes. |
| 301 * | 350 * |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 497 bool operator ==(other) { | 546 bool operator ==(other) { |
| 498 if (runtimeType != other.runtimeType) { | 547 if (runtimeType != other.runtimeType) { |
| 499 return false; | 548 return false; |
| 500 } | 549 } |
| 501 return path == other.path; | 550 return path == other.path; |
| 502 } | 551 } |
| 503 | 552 |
| 504 @override | 553 @override |
| 505 String toString() => path; | 554 String toString() => path; |
| 506 } | 555 } |
| OLD | NEW |