mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 02:57:35 +00:00
Store data objects for File/Folder in MemoryResourceProvider.
And by storing the list of child names in a folder we can implement Folder.getChildren() more efficiently. Bug: https://github.com/dart-lang/sdk/issues/47220 Change-Id: I893dffd6ada4095b8580ec5d469142478f57f284 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/213682 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
b1d878fc8f
commit
28738dfad0
|
@ -1,3 +1,8 @@
|
|||
## 2.4.0-dev
|
||||
* Deprecated `ResourceProvider.getModificationTimes()`.
|
||||
* Deprecated `MemoryResourceProvider.newDummyLink()`.
|
||||
* Deprecated `MemoryResourceProvider.updateFile()`.
|
||||
|
||||
## 2.3.0
|
||||
* Enable `constructor-tearoffs` feature by default in `2.15`.
|
||||
* Improvements in constructors tear-off implementation.
|
||||
|
|
|
@ -198,6 +198,7 @@ abstract class ResourceProvider {
|
|||
///
|
||||
/// If the file of a source is not managed by this provider, return `null`.
|
||||
/// If the file a source does not exist, return `-1`.
|
||||
@Deprecated('Not used by clients')
|
||||
Future<List<int?>> getModificationTimes(List<Source> sources);
|
||||
|
||||
/// Return the [Resource] that corresponds to the given [path].
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
|
@ -16,13 +15,9 @@ import 'package:watcher/watcher.dart';
|
|||
/// An in-memory implementation of [ResourceProvider].
|
||||
/// Use `/` as a path separator.
|
||||
class MemoryResourceProvider implements ResourceProvider {
|
||||
final Map<String, _MemoryResource> _pathToResource =
|
||||
HashMap<String, _MemoryResource>();
|
||||
final Map<String, Uint8List> _pathToBytes = HashMap<String, Uint8List>();
|
||||
final Map<String, int> _pathToTimestamp = HashMap<String, int>();
|
||||
final Map<String, _ResourceData> _pathToData = {};
|
||||
final Map<String, String> _pathToLinkedPath = {};
|
||||
final Map<String, List<StreamController<WatchEvent>>> _pathToWatchers =
|
||||
HashMap<String, List<StreamController<WatchEvent>>>();
|
||||
final Map<String, List<StreamController<WatchEvent>>> _pathToWatchers = {};
|
||||
int nextStamp = 0;
|
||||
|
||||
final pathos.Context _pathContext;
|
||||
|
@ -55,19 +50,28 @@ class MemoryResourceProvider implements ResourceProvider {
|
|||
|
||||
/// Delete the file with the given path.
|
||||
void deleteFile(String path) {
|
||||
_checkFileAtPath(path);
|
||||
_pathToResource.remove(path);
|
||||
_pathToBytes.remove(path);
|
||||
_pathToTimestamp.remove(path);
|
||||
var data = _pathToData[path];
|
||||
if (data is! _FileData) {
|
||||
throw FileSystemException(path, 'Not a file.');
|
||||
}
|
||||
|
||||
_pathToData.remove(path);
|
||||
_removeFromParentFolderData(path);
|
||||
|
||||
_notifyWatchers(path, ChangeType.REMOVE);
|
||||
}
|
||||
|
||||
/// Delete the folder with the given path
|
||||
/// and recursively delete nested files and folders.
|
||||
void deleteFolder(String path) {
|
||||
_checkFolderAtPath(path);
|
||||
var folder = _pathToResource[path] as _MemoryFolder;
|
||||
for (Resource child in folder.getChildren()) {
|
||||
var data = _pathToData[path];
|
||||
if (data is! _FolderData) {
|
||||
throw FileSystemException(path, 'Not a folder.');
|
||||
}
|
||||
|
||||
for (var childName in data.childNames.toList()) {
|
||||
var childPath = pathContext.join(path, childName);
|
||||
var child = getResource(childPath);
|
||||
if (child is File) {
|
||||
deleteFile(child.path);
|
||||
} else if (child is Folder) {
|
||||
|
@ -76,9 +80,17 @@ class MemoryResourceProvider implements ResourceProvider {
|
|||
throw 'failed to delete resource: $child';
|
||||
}
|
||||
}
|
||||
_pathToResource.remove(path);
|
||||
_pathToBytes.remove(path);
|
||||
_pathToTimestamp.remove(path);
|
||||
|
||||
if (_pathToData[path] != data) {
|
||||
throw StateError('Unexpected concurrent modification: $path');
|
||||
}
|
||||
if (data.childNames.isNotEmpty) {
|
||||
throw StateError('Must be empty.');
|
||||
}
|
||||
|
||||
_pathToData.remove(path);
|
||||
_removeFromParentFolderData(path);
|
||||
|
||||
_notifyWatchers(path, ChangeType.REMOVE);
|
||||
}
|
||||
|
||||
|
@ -94,18 +106,27 @@ class MemoryResourceProvider implements ResourceProvider {
|
|||
return _MemoryFolder(this, path);
|
||||
}
|
||||
|
||||
@Deprecated('Not used by clients')
|
||||
@override
|
||||
Future<List<int>> getModificationTimes(List<Source> sources) async {
|
||||
return sources.map((source) {
|
||||
String path = source.fullName;
|
||||
return _pathToTimestamp[path] ?? -1;
|
||||
var file = getFile(path);
|
||||
try {
|
||||
return file.modificationStamp;
|
||||
} on FileSystemException {
|
||||
return -1;
|
||||
}
|
||||
}).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Resource getResource(String path) {
|
||||
_ensureAbsoluteAndNormalized(path);
|
||||
return _pathToResource[path] ?? _MemoryFile(this, path);
|
||||
var data = _pathToData[path];
|
||||
return data is _FolderData
|
||||
? _MemoryFolder(this, path)
|
||||
: _MemoryFile(this, path);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -115,66 +136,53 @@ class MemoryResourceProvider implements ResourceProvider {
|
|||
}
|
||||
|
||||
void modifyFile(String path, String content) {
|
||||
_checkFileAtPath(path);
|
||||
_pathToBytes[path] = utf8.encode(content) as Uint8List;
|
||||
_pathToTimestamp[path] = nextStamp++;
|
||||
var data = _pathToData[path];
|
||||
if (data is! _FileData) {
|
||||
throw FileSystemException(path, 'Not a file.');
|
||||
}
|
||||
|
||||
_pathToData[path] = _FileData(
|
||||
bytes: utf8.encode(content) as Uint8List,
|
||||
timeStamp: nextStamp++,
|
||||
);
|
||||
_notifyWatchers(path, ChangeType.MODIFY);
|
||||
}
|
||||
|
||||
/// Create a resource representing a dummy link (that is, a File object which
|
||||
/// appears in its parent directory, but whose `exists` property is false)
|
||||
@Deprecated('Not used by clients')
|
||||
File newDummyLink(String path) {
|
||||
_ensureAbsoluteAndNormalized(path);
|
||||
newFolder(pathContext.dirname(path));
|
||||
_MemoryDummyLink link = _MemoryDummyLink(this, path);
|
||||
_pathToResource[path] = link;
|
||||
_pathToTimestamp[path] = nextStamp++;
|
||||
_notifyWatchers(path, ChangeType.ADD);
|
||||
return link;
|
||||
}
|
||||
|
||||
File newFile(String path, String content, [int? stamp]) {
|
||||
_ensureAbsoluteAndNormalized(path);
|
||||
_MemoryFile file = _newFile(path);
|
||||
_pathToBytes[path] = utf8.encode(content) as Uint8List;
|
||||
_pathToTimestamp[path] = stamp ?? nextStamp++;
|
||||
_notifyWatchers(path, ChangeType.ADD);
|
||||
return file;
|
||||
var bytes = utf8.encode(content);
|
||||
return newFileWithBytes(path, bytes, stamp);
|
||||
}
|
||||
|
||||
File newFileWithBytes(String path, List<int> bytes, [int? stamp]) {
|
||||
_ensureAbsoluteAndNormalized(path);
|
||||
_MemoryFile file = _newFile(path);
|
||||
_pathToBytes[path] = Uint8List.fromList(bytes);
|
||||
_pathToTimestamp[path] = stamp ?? nextStamp++;
|
||||
|
||||
var parentPath = pathContext.dirname(path);
|
||||
var parentData = _newFolder(parentPath);
|
||||
_addToParentFolderData(parentData, path);
|
||||
|
||||
_pathToData[path] = _FileData(
|
||||
bytes: Uint8List.fromList(bytes),
|
||||
timeStamp: stamp ?? nextStamp++,
|
||||
);
|
||||
_notifyWatchers(path, ChangeType.ADD);
|
||||
return file;
|
||||
|
||||
return _MemoryFile(this, path);
|
||||
}
|
||||
|
||||
Folder newFolder(String path) {
|
||||
_ensureAbsoluteAndNormalized(path);
|
||||
if (!pathContext.isAbsolute(path)) {
|
||||
throw ArgumentError("Path must be absolute : $path");
|
||||
}
|
||||
var resource = _pathToResource[path];
|
||||
if (resource == null) {
|
||||
String parentPath = pathContext.dirname(path);
|
||||
if (parentPath != path) {
|
||||
newFolder(parentPath);
|
||||
}
|
||||
_MemoryFolder folder = _MemoryFolder(this, path);
|
||||
_pathToResource[path] = folder;
|
||||
_pathToTimestamp[path] = nextStamp++;
|
||||
_notifyWatchers(path, ChangeType.ADD);
|
||||
return folder;
|
||||
} else if (resource is _MemoryFolder) {
|
||||
_notifyWatchers(path, ChangeType.ADD);
|
||||
return resource;
|
||||
} else {
|
||||
String message =
|
||||
'Folder expected at ' "'$path'" 'but ${resource.runtimeType} found';
|
||||
throw ArgumentError(message);
|
||||
}
|
||||
_newFolder(path);
|
||||
return _MemoryFolder(this, path);
|
||||
}
|
||||
|
||||
/// Create a link from the [path] to the [target].
|
||||
|
@ -184,44 +192,29 @@ class MemoryResourceProvider implements ResourceProvider {
|
|||
_pathToLinkedPath[path] = target;
|
||||
}
|
||||
|
||||
@Deprecated('Not used by clients')
|
||||
File updateFile(String path, String content, [int? stamp]) {
|
||||
_ensureAbsoluteAndNormalized(path);
|
||||
newFolder(pathContext.dirname(path));
|
||||
_MemoryFile file = _MemoryFile(this, path);
|
||||
_pathToResource[path] = file;
|
||||
_pathToBytes[path] = utf8.encode(content) as Uint8List;
|
||||
_pathToTimestamp[path] = stamp ?? nextStamp++;
|
||||
_pathToData[path] = _FileData(
|
||||
bytes: utf8.encode(content) as Uint8List,
|
||||
timeStamp: stamp ?? nextStamp++,
|
||||
);
|
||||
_notifyWatchers(path, ChangeType.MODIFY);
|
||||
return file;
|
||||
return _MemoryFile(this, path);
|
||||
}
|
||||
|
||||
/// Write a representation of the file system on the given [sink].
|
||||
void writeOn(StringSink sink) {
|
||||
List<String> paths = _pathToResource.keys.toList();
|
||||
List<String> paths = _pathToData.keys.toList();
|
||||
paths.sort();
|
||||
paths.forEach(sink.writeln);
|
||||
}
|
||||
|
||||
void _checkFileAtPath(String path) {
|
||||
// TODO(brianwilkerson) Consider throwing a FileSystemException rather than
|
||||
// an ArgumentError.
|
||||
var resource = _pathToResource[path];
|
||||
if (resource is! _MemoryFile) {
|
||||
if (resource == null) {
|
||||
throw ArgumentError('File expected at "$path" but does not exist');
|
||||
}
|
||||
throw ArgumentError(
|
||||
'File expected at "$path" but ${resource.runtimeType} found');
|
||||
}
|
||||
}
|
||||
|
||||
void _checkFolderAtPath(String path) {
|
||||
// TODO(brianwilkerson) Consider throwing a FileSystemException rather than
|
||||
// an ArgumentError.
|
||||
var resource = _pathToResource[path];
|
||||
if (resource is! _MemoryFolder) {
|
||||
throw ArgumentError(
|
||||
'Folder expected at "$path" but ${resource.runtimeType} found');
|
||||
void _addToParentFolderData(_FolderData parentData, String path) {
|
||||
var childName = pathContext.basename(path);
|
||||
if (!parentData.childNames.contains(childName)) {
|
||||
parentData.childNames.add(childName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,18 +229,25 @@ class MemoryResourceProvider implements ResourceProvider {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create a new [_MemoryFile] without any content.
|
||||
_MemoryFile _newFile(String path) {
|
||||
String folderPath = pathContext.dirname(path);
|
||||
var folder = _pathToResource[folderPath];
|
||||
if (folder == null) {
|
||||
newFolder(folderPath);
|
||||
} else if (folder is! Folder) {
|
||||
throw ArgumentError('Cannot create file ($path) as child of file');
|
||||
_FolderData _newFolder(String path) {
|
||||
_ensureAbsoluteAndNormalized(path);
|
||||
|
||||
var data = _pathToData[path];
|
||||
if (data is _FolderData) {
|
||||
return data;
|
||||
} else if (data == null) {
|
||||
var parentPath = pathContext.dirname(path);
|
||||
if (parentPath != path) {
|
||||
var parentData = _newFolder(parentPath);
|
||||
_addToParentFolderData(parentData, path);
|
||||
}
|
||||
var data = _FolderData();
|
||||
_pathToData[path] = data;
|
||||
_notifyWatchers(path, ChangeType.ADD);
|
||||
return data;
|
||||
} else {
|
||||
throw FileSystemException(path, 'Folder expected.');
|
||||
}
|
||||
_MemoryFile file = _MemoryFile(this, path);
|
||||
_pathToResource[path] = file;
|
||||
return file;
|
||||
}
|
||||
|
||||
void _notifyWatchers(String path, ChangeType changeType) {
|
||||
|
@ -262,36 +262,41 @@ class MemoryResourceProvider implements ResourceProvider {
|
|||
});
|
||||
}
|
||||
|
||||
_MemoryFile _renameFileSync(_MemoryFile file, String newPath) {
|
||||
String path = file.path;
|
||||
void _removeFromParentFolderData(String path) {
|
||||
var parentPath = pathContext.dirname(path);
|
||||
var parentData = _pathToData[parentPath] as _FolderData;
|
||||
var childName = pathContext.basename(path);
|
||||
parentData.childNames.remove(childName);
|
||||
}
|
||||
|
||||
void _renameFileSync(String path, String newPath) {
|
||||
var data = _pathToData[path];
|
||||
if (data is! _FileData) {
|
||||
throw FileSystemException(path, 'Not a file.');
|
||||
}
|
||||
|
||||
if (newPath == path) {
|
||||
return file;
|
||||
}
|
||||
var existingNewResource = _pathToResource[newPath];
|
||||
if (existingNewResource is _MemoryFolder) {
|
||||
throw FileSystemException(
|
||||
path, 'Could not be renamed: $newPath is a folder.');
|
||||
return;
|
||||
}
|
||||
|
||||
_MemoryFile newFile = _newFile(newPath);
|
||||
_pathToResource.remove(path);
|
||||
|
||||
var oldBytes = _pathToBytes.remove(path);
|
||||
if (oldBytes != null) {
|
||||
_pathToBytes[newPath] = oldBytes;
|
||||
var existingNewData = _pathToData[newPath];
|
||||
if (existingNewData == null) {
|
||||
// Nothing to do.
|
||||
} else if (existingNewData is _FileData) {
|
||||
deleteFile(newPath);
|
||||
} else {
|
||||
throw FileSystemException(newPath, 'Not a file.');
|
||||
}
|
||||
|
||||
var oldTimestamp = _pathToTimestamp.remove(path);
|
||||
if (oldTimestamp != null) {
|
||||
_pathToTimestamp[newPath] = oldTimestamp;
|
||||
}
|
||||
var parentPath = pathContext.dirname(path);
|
||||
var parentData = _newFolder(parentPath);
|
||||
_addToParentFolderData(parentData, path);
|
||||
|
||||
_pathToData.remove(path);
|
||||
_pathToData[newPath] = data;
|
||||
|
||||
if (existingNewResource != null) {
|
||||
_notifyWatchers(newPath, ChangeType.REMOVE);
|
||||
}
|
||||
_notifyWatchers(path, ChangeType.REMOVE);
|
||||
_notifyWatchers(newPath, ChangeType.ADD);
|
||||
return newFile;
|
||||
}
|
||||
|
||||
String _resolveLinks(String path) {
|
||||
|
@ -317,15 +322,34 @@ class MemoryResourceProvider implements ResourceProvider {
|
|||
return result;
|
||||
}
|
||||
|
||||
void _setFileContent(_MemoryFile file, List<int> bytes) {
|
||||
String path = file.path;
|
||||
_pathToResource[path] = file;
|
||||
_pathToBytes[path] = Uint8List.fromList(bytes);
|
||||
_pathToTimestamp[path] = nextStamp++;
|
||||
void _setFileContent(String path, List<int> bytes) {
|
||||
var parentPath = pathContext.dirname(path);
|
||||
var parentData = _newFolder(parentPath);
|
||||
_addToParentFolderData(parentData, path);
|
||||
|
||||
_pathToData[path] = _FileData(
|
||||
bytes: Uint8List.fromList(bytes),
|
||||
timeStamp: nextStamp++,
|
||||
);
|
||||
_notifyWatchers(path, ChangeType.MODIFY);
|
||||
}
|
||||
}
|
||||
|
||||
class _FileData extends _ResourceData {
|
||||
final Uint8List bytes;
|
||||
final int timeStamp;
|
||||
|
||||
_FileData({
|
||||
required this.bytes,
|
||||
required this.timeStamp,
|
||||
});
|
||||
}
|
||||
|
||||
class _FolderData extends _ResourceData {
|
||||
/// Names (not paths) of direct children.
|
||||
final List<String> childNames = [];
|
||||
}
|
||||
|
||||
/// An in-memory implementation of [File] which acts like a symbolic link to a
|
||||
/// non-existent file.
|
||||
class _MemoryDummyLink extends _MemoryResource implements File {
|
||||
|
@ -347,11 +371,7 @@ class _MemoryDummyLink extends _MemoryResource implements File {
|
|||
|
||||
@override
|
||||
int get modificationStamp {
|
||||
var stamp = provider._pathToTimestamp[path];
|
||||
if (stamp == null) {
|
||||
throw FileSystemException(path, "File does not exist");
|
||||
}
|
||||
return stamp;
|
||||
throw FileSystemException(path, "File does not exist");
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -413,7 +433,7 @@ class _MemoryFile extends _MemoryResource implements File {
|
|||
@override
|
||||
bool get exists {
|
||||
var canonicalPath = provider._resolveLinks(path);
|
||||
return provider._pathToResource[canonicalPath] is _MemoryFile;
|
||||
return provider._pathToData[canonicalPath] is _FileData;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -424,11 +444,11 @@ class _MemoryFile extends _MemoryResource implements File {
|
|||
@override
|
||||
int get modificationStamp {
|
||||
var canonicalPath = provider._resolveLinks(path);
|
||||
var stamp = provider._pathToTimestamp[canonicalPath];
|
||||
if (stamp == null) {
|
||||
throw FileSystemException(path, 'File "$path" does not exist.');
|
||||
var data = provider._pathToData[canonicalPath];
|
||||
if (data is! _FileData) {
|
||||
throw FileSystemException(path, 'File does not exist.');
|
||||
}
|
||||
return stamp;
|
||||
return data.timeStamp;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -458,26 +478,23 @@ class _MemoryFile extends _MemoryResource implements File {
|
|||
@override
|
||||
Uint8List readAsBytesSync() {
|
||||
var canonicalPath = provider._resolveLinks(path);
|
||||
var content = provider._pathToBytes[canonicalPath];
|
||||
if (content == null) {
|
||||
throw FileSystemException(path, 'File "$path" does not exist.');
|
||||
var data = provider._pathToData[canonicalPath];
|
||||
if (data is! _FileData) {
|
||||
throw FileSystemException(path, 'File does not exist.');
|
||||
}
|
||||
return content;
|
||||
return data.bytes;
|
||||
}
|
||||
|
||||
@override
|
||||
String readAsStringSync() {
|
||||
var canonicalPath = provider._resolveLinks(path);
|
||||
var content = provider._pathToBytes[canonicalPath];
|
||||
if (content == null) {
|
||||
throw FileSystemException(path, 'File "$path" does not exist.');
|
||||
}
|
||||
return utf8.decode(content);
|
||||
var bytes = readAsBytesSync();
|
||||
return utf8.decode(bytes);
|
||||
}
|
||||
|
||||
@override
|
||||
File renameSync(String newPath) {
|
||||
return provider._renameFileSync(this, newPath);
|
||||
provider._renameFileSync(path, newPath);
|
||||
return provider.getFile(newPath);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -486,7 +503,7 @@ class _MemoryFile extends _MemoryResource implements File {
|
|||
var result = provider.getFile(canonicalPath);
|
||||
|
||||
if (!result.exists) {
|
||||
throw FileSystemException(path, 'File "$path" does not exist.');
|
||||
throw FileSystemException(path, 'File does not exist.');
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -494,12 +511,13 @@ class _MemoryFile extends _MemoryResource implements File {
|
|||
|
||||
@override
|
||||
void writeAsBytesSync(List<int> bytes) {
|
||||
provider._setFileContent(this, bytes);
|
||||
provider._setFileContent(path, bytes);
|
||||
}
|
||||
|
||||
@override
|
||||
void writeAsStringSync(String content) {
|
||||
provider._setFileContent(this, utf8.encode(content));
|
||||
var bytes = utf8.encode(content);
|
||||
writeAsBytesSync(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -511,7 +529,7 @@ class _MemoryFolder extends _MemoryResource implements Folder {
|
|||
@override
|
||||
bool get exists {
|
||||
var canonicalPath = provider._resolveLinks(path);
|
||||
return provider._pathToResource[canonicalPath] is _MemoryFolder;
|
||||
return provider._pathToData[canonicalPath] is _FolderData;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -555,29 +573,20 @@ class _MemoryFolder extends _MemoryResource implements Folder {
|
|||
|
||||
@override
|
||||
Resource getChild(String relPath) {
|
||||
String childPath = canonicalizePath(relPath);
|
||||
return provider._pathToResource[childPath] ??
|
||||
_MemoryFile(provider, childPath);
|
||||
var path = canonicalizePath(relPath);
|
||||
return provider.getResource(path);
|
||||
}
|
||||
|
||||
@override
|
||||
_MemoryFile getChildAssumingFile(String relPath) {
|
||||
String childPath = canonicalizePath(relPath);
|
||||
var resource = provider._pathToResource[childPath];
|
||||
if (resource is _MemoryFile) {
|
||||
return resource;
|
||||
}
|
||||
return _MemoryFile(provider, childPath);
|
||||
var path = canonicalizePath(relPath);
|
||||
return _MemoryFile(provider, path);
|
||||
}
|
||||
|
||||
@override
|
||||
_MemoryFolder getChildAssumingFolder(String relPath) {
|
||||
String childPath = canonicalizePath(relPath);
|
||||
var resource = provider._pathToResource[childPath];
|
||||
if (resource is _MemoryFolder) {
|
||||
return resource;
|
||||
}
|
||||
return _MemoryFolder(provider, childPath);
|
||||
var path = canonicalizePath(relPath);
|
||||
return _MemoryFolder(provider, path);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -596,17 +605,17 @@ class _MemoryFolder extends _MemoryResource implements Folder {
|
|||
}).toList();
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
var data = provider._pathToData[path];
|
||||
if (data is! _FolderData) {
|
||||
throw FileSystemException(path, 'Folder does not exist.');
|
||||
}
|
||||
|
||||
var children = <Resource>[];
|
||||
|
||||
provider._pathToResource.forEach((resourcePath, resource) {
|
||||
if (provider.pathContext.dirname(resourcePath) == path) {
|
||||
children.add(resource);
|
||||
}
|
||||
});
|
||||
for (var childName in data.childNames) {
|
||||
var childPath = provider.pathContext.join(path, childName);
|
||||
var child = provider.getResource(childPath);
|
||||
children.add(child);
|
||||
}
|
||||
|
||||
provider._pathToLinkedPath.forEach((resourcePath, targetPath) {
|
||||
if (provider.pathContext.dirname(resourcePath) == path) {
|
||||
|
@ -640,7 +649,7 @@ class _MemoryFolder extends _MemoryResource implements Folder {
|
|||
var result = provider.getFolder(canonicalPath);
|
||||
|
||||
if (!result.exists) {
|
||||
throw FileSystemException(path, 'Folder "$path" does not exist.');
|
||||
throw FileSystemException(path, 'Folder does not exist.');
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -712,3 +721,5 @@ abstract class _MemoryResource implements Resource {
|
|||
@override
|
||||
Uri toUri() => provider.pathContext.toUri(path);
|
||||
}
|
||||
|
||||
class _ResourceData {}
|
||||
|
|
|
@ -40,6 +40,7 @@ class OverlayResourceProvider implements ResourceProvider {
|
|||
Folder getFolder(String path) =>
|
||||
_OverlayFolder(this, baseProvider.getFolder(path));
|
||||
|
||||
@Deprecated('Not used by clients')
|
||||
@override
|
||||
Future<List<int>> getModificationTimes(List<Source> sources) async {
|
||||
return sources.map((source) {
|
||||
|
|
|
@ -78,6 +78,7 @@ class PhysicalResourceProvider implements ResourceProvider {
|
|||
return _PhysicalFolder(io.Directory(path));
|
||||
}
|
||||
|
||||
@Deprecated('Not used by clients')
|
||||
@override
|
||||
Future<List<int?>> getModificationTimes(List<Source> sources) async {
|
||||
List<String> paths = sources.map((source) => source.fullName).toList();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: analyzer
|
||||
version: 2.3.0
|
||||
version: 2.4.0-dev
|
||||
description: This package provides a library that performs static analysis of Dart code.
|
||||
homepage: https://github.com/dart-lang/sdk/tree/main/pkg/analyzer
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@ final isFile = TypeMatcher<File>();
|
|||
final isFileSystemException = TypeMatcher<FileSystemException>();
|
||||
final isFolder = TypeMatcher<Folder>();
|
||||
|
||||
final throwsFileSystemException = throwsA(isFileSystemException);
|
||||
|
||||
abstract class FileSystemTestSupport {
|
||||
/// The content used for the file at the [defaultFilePath] if it is created
|
||||
/// and no other content is provided.
|
||||
|
@ -108,9 +110,11 @@ mixin FileTestMixin implements FileSystemTestSupport {
|
|||
test_delete_existing() {
|
||||
File file = getFile(exists: true);
|
||||
expect(file.exists, isTrue);
|
||||
expect(file.parent2.getChildren(), contains(file));
|
||||
|
||||
file.delete();
|
||||
expect(file.exists, isFalse);
|
||||
expect(file.parent2.getChildren(), isNot(contains(file)));
|
||||
}
|
||||
|
||||
test_delete_notExisting();
|
||||
|
@ -919,6 +923,7 @@ mixin ResourceProviderTestMixin implements FileSystemTestSupport {
|
|||
expect(folder.exists, isFalse);
|
||||
}
|
||||
|
||||
@Deprecated('Not used by clients')
|
||||
test_getModificationTimes_existing() async {
|
||||
Source source = getFile(exists: true).createSource();
|
||||
|
||||
|
@ -926,6 +931,7 @@ mixin ResourceProviderTestMixin implements FileSystemTestSupport {
|
|||
expect(times, [source.modificationStamp]);
|
||||
}
|
||||
|
||||
@Deprecated('Not used by clients')
|
||||
test_getModificationTimes_notExisting() async {
|
||||
Source source = getFile(exists: false).createSource();
|
||||
|
||||
|
|
|
@ -241,7 +241,10 @@ class MemoryFileTest extends BaseTest with FileTestMixin {
|
|||
File file = getFile(exists: false);
|
||||
expect(file.exists, isFalse);
|
||||
|
||||
expect(() => file.delete(), throwsA(const TypeMatcher<ArgumentError>()));
|
||||
expect(
|
||||
() => file.delete(),
|
||||
throwsFileSystemException,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -304,14 +307,20 @@ class MemoryResourceProviderTest extends BaseTest
|
|||
test_deleteFile_folder() {
|
||||
Folder folder = getFolder(exists: true);
|
||||
|
||||
expect(() => provider.deleteFile(defaultFolderPath), throwsArgumentError);
|
||||
expect(
|
||||
() => provider.deleteFile(defaultFolderPath),
|
||||
throwsFileSystemException,
|
||||
);
|
||||
expect(folder.exists, isTrue);
|
||||
}
|
||||
|
||||
test_deleteFile_notExisting() {
|
||||
File file = getFile(exists: false);
|
||||
|
||||
expect(() => provider.deleteFile(defaultFilePath), throwsArgumentError);
|
||||
expect(
|
||||
() => provider.deleteFile(defaultFilePath),
|
||||
throwsFileSystemException,
|
||||
);
|
||||
expect(file.exists, isFalse);
|
||||
}
|
||||
|
||||
|
@ -325,16 +334,20 @@ class MemoryResourceProviderTest extends BaseTest
|
|||
test_modifyFile_existing_folder() {
|
||||
getFolder(exists: true);
|
||||
|
||||
expect(() => provider.modifyFile(defaultFolderPath, 'contents'),
|
||||
throwsArgumentError);
|
||||
expect(
|
||||
() => provider.modifyFile(defaultFolderPath, 'contents'),
|
||||
throwsFileSystemException,
|
||||
);
|
||||
expect(provider.getResource(defaultFolderPath), isFolder);
|
||||
}
|
||||
|
||||
test_modifyFile_notExisting() {
|
||||
getFile(exists: false);
|
||||
|
||||
expect(() => provider.modifyFile(defaultFilePath, 'contents'),
|
||||
throwsArgumentError);
|
||||
expect(
|
||||
() => provider.modifyFile(defaultFilePath, 'contents'),
|
||||
throwsFileSystemException,
|
||||
);
|
||||
Resource file = provider.getResource(defaultFilePath);
|
||||
expect(file, isFile);
|
||||
expect(file.exists, isFalse);
|
||||
|
@ -357,7 +370,10 @@ class MemoryResourceProviderTest extends BaseTest
|
|||
test_newFolder_existing_file() {
|
||||
getFile(exists: true);
|
||||
|
||||
expect(() => provider.newFolder(defaultFilePath), throwsArgumentError);
|
||||
expect(
|
||||
() => provider.newFolder(defaultFilePath),
|
||||
throwsFileSystemException,
|
||||
);
|
||||
}
|
||||
|
||||
test_newFolder_existing_folder() {
|
||||
|
|
|
@ -272,25 +272,21 @@ class FileTest extends OverlayTestSupport {
|
|||
test_renameSync_notExisting_withoutOverlay() {
|
||||
String oldPath = '/foo/bar/file.txt';
|
||||
String newPath = baseProvider.convertPath('/foo/bar/new-file.txt');
|
||||
File oldFile = _file(exists: true, path: oldPath);
|
||||
File newFile = oldFile.renameSync(newPath);
|
||||
expect(oldFile.path, baseProvider.convertPath(oldPath));
|
||||
expect(oldFile.exists, isFalse);
|
||||
expect(newFile.path, newPath);
|
||||
expect(newFile.exists, isTrue);
|
||||
expect(newFile.readAsStringSync(), 'a');
|
||||
File oldFile = _file(exists: false, path: oldPath);
|
||||
expect(
|
||||
() => oldFile.renameSync(newPath),
|
||||
throwsFileSystemException,
|
||||
);
|
||||
}
|
||||
|
||||
test_renameSync_notExisting_withOverlay() {
|
||||
String oldPath = '/foo/bar/file.txt';
|
||||
String newPath = baseProvider.convertPath('/foo/bar/new-file.txt');
|
||||
File oldFile = _file(exists: false, path: oldPath, withOverlay: true);
|
||||
File newFile = oldFile.renameSync(newPath);
|
||||
expect(oldFile.path, baseProvider.convertPath(oldPath));
|
||||
expect(oldFile.exists, isFalse);
|
||||
expect(newFile.path, newPath);
|
||||
expect(newFile.exists, isTrue);
|
||||
expect(newFile.readAsStringSync(), 'bbb');
|
||||
expect(
|
||||
() => oldFile.renameSync(newPath),
|
||||
throwsFileSystemException,
|
||||
);
|
||||
}
|
||||
|
||||
@failingTest
|
||||
|
@ -480,7 +476,7 @@ class FolderTest extends OverlayTestSupport {
|
|||
test_delete_notExisting() {
|
||||
Folder folder = _folder(exists: false);
|
||||
expect(folder.exists, isFalse);
|
||||
expect(() => folder.delete(), throwsA(TypeMatcher<ArgumentError>()));
|
||||
expect(() => folder.delete(), throwsFileSystemException);
|
||||
}
|
||||
|
||||
void test_exists_links_existing() {
|
||||
|
@ -810,12 +806,14 @@ class OverlayResourceProviderTest extends OverlayTestSupport {
|
|||
expect(folder.exists, isTrue);
|
||||
}
|
||||
|
||||
@Deprecated('Not used by clients')
|
||||
test_getModificationTimes_withoutOverlay() async {
|
||||
Source source = _file(exists: true).createSource();
|
||||
List<int> times = await provider.getModificationTimes([source]);
|
||||
expect(times, [source.modificationStamp]);
|
||||
}
|
||||
|
||||
@Deprecated('Not used by clients')
|
||||
test_getModificationTimes_withOverlay() async {
|
||||
Source source = _file(exists: true, withOverlay: true).createSource();
|
||||
List<int> times = await provider.getModificationTimes([source]);
|
||||
|
|
Loading…
Reference in a new issue