blob: da41c9653eee40cc484977932353ef0b1e75d382 [file] [log] [blame]
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of file.src.backends.memory;
class _MemoryDirectory extends _MemoryFileSystemEntity
with common.DirectoryAddOnsMixin
implements Directory {
static int _tempCounter = 0;
_MemoryDirectory(MemoryFileSystem fileSystem, String path)
: super(fileSystem, path);
@override
io.FileSystemEntityType get expectedType => io.FileSystemEntityType.DIRECTORY;
@override
Uri get uri => new Uri.directory(path);
@override
bool existsSync() => _backingOrNull?.stat?.type == expectedType;
@override
Future<Directory> create({bool recursive: false}) async {
createSync(recursive: recursive);
return this;
}
@override
void createSync({bool recursive: false}) {
_Node node = _createSync(
followTailLink: true,
visitLinks: true,
createChild: (_DirectoryNode parent, bool isFinalSegment) {
if (recursive || isFinalSegment) {
return new _DirectoryNode(parent);
}
return null;
},
);
if (node.type != expectedType) {
// There was an existing non-directory node at this object's path
throw common.notADirectory(path);
}
}
@override
Future<Directory> createTemp([String prefix]) async => createTempSync(prefix);
@override
Directory createTempSync([String prefix]) {
prefix = (prefix ?? '') + 'rand';
String fullPath = fileSystem.path.join(path, prefix);
String dirname = fileSystem.path.dirname(fullPath);
String basename = fileSystem.path.basename(fullPath);
_DirectoryNode node = fileSystem._findNode(dirname);
_checkExists(node, () => dirname);
_checkIsDir(node, () => dirname);
String name() => '$basename$_tempCounter';
while (node.children.containsKey(name())) {
_tempCounter++;
}
_DirectoryNode tempDir = new _DirectoryNode(node);
node.children[name()] = tempDir;
return new _MemoryDirectory(
fileSystem, fileSystem.path.join(dirname, name()));
}
@override
Future<Directory> rename(String newPath) async => renameSync(newPath);
@override
Directory renameSync(String newPath) => _renameSync(
newPath,
validateOverwriteExistingEntity: (_DirectoryNode existingNode) {
if (existingNode.children.isNotEmpty) {
throw common.directoryNotEmpty(newPath);
}
},
);
@override
Directory get parent =>
(_backingOrNull?.isRoot ?? false) ? this : super.parent;
@override
Directory get absolute => super.absolute;
@override
Stream<FileSystemEntity> list({
bool recursive: false,
bool followLinks: true,
}) =>
new Stream<FileSystemEntity>.fromIterable(listSync(
recursive: recursive,
followLinks: followLinks,
));
@override
List<FileSystemEntity> listSync({
bool recursive: false,
bool followLinks: true,
}) {
_DirectoryNode node = _backing;
List<FileSystemEntity> listing = <FileSystemEntity>[];
List<_PendingListTask> tasks = <_PendingListTask>[
new _PendingListTask(
node,
path.endsWith(_separator) ? path.substring(0, path.length - 1) : path,
new Set<_LinkNode>(),
),
];
while (tasks.isNotEmpty) {
_PendingListTask task = tasks.removeLast();
task.dir.children.forEach((String name, _Node child) {
Set<_LinkNode> breadcrumbs = new Set<_LinkNode>.from(task.breadcrumbs);
String childPath = fileSystem.path.join(task.path, name);
while (followLinks && _isLink(child) && breadcrumbs.add(child)) {
_Node referent = (child as _LinkNode).referentOrNull;
if (referent != null) {
child = referent;
}
}
if (_isDirectory(child)) {
listing.add(new _MemoryDirectory(fileSystem, childPath));
if (recursive) {
tasks.add(new _PendingListTask(child, childPath, breadcrumbs));
}
} else if (_isLink(child)) {
listing.add(new _MemoryLink(fileSystem, childPath));
} else if (_isFile(child)) {
listing.add(new _MemoryFile(fileSystem, childPath));
}
});
}
return listing;
}
@override
Directory _clone(String path) => new _MemoryDirectory(fileSystem, path);
@override
String toString() => "MemoryDirectory: '$path'";
}
class _PendingListTask {
final _DirectoryNode dir;
final String path;
final Set<_LinkNode> breadcrumbs;
_PendingListTask(this.dir, this.path, this.breadcrumbs);
}