import 'package:file/file.dart';
import 'package:file/local.dart';
import 'package:file/memory.dart';
import 'package:file/record_replay.dart';
import 'package:meta/meta.dart';
import 'common.dart' show throwToolExit;
import 'context.dart';
import 'platform.dart';
import 'process.dart';
export 'package:file/file.dart';
export 'package:file/local.dart';
const String _kRecordingType = 'file';
const FileSystem _kLocalFs = LocalFileSystem();
FileSystem get fs => context.get<FileSystem>() ?? _kLocalFs;
RecordingFileSystem getRecordingFileSystem(String location) {
final Directory dir = getRecordingSink(location, _kRecordingType);
final RecordingFileSystem fileSystem = RecordingFileSystem(
delegate: _kLocalFs, destination: dir);
addShutdownHook(() async {
await fileSystem.recording.flush();
}, ShutdownStage.SERIALIZE_RECORDING);
return fileSystem;
}
ReplayFileSystem getReplayFileSystem(String location) {
final Directory dir = getReplaySource(location, _kRecordingType);
return ReplayFileSystem(recording: dir);
}
void ensureDirectoryExists(String filePath) {
final String dirPath = fs.path.dirname(filePath);
if (fs.isDirectorySync(dirPath))
return;
try {
fs.directory(dirPath).createSync(recursive: true);
} on FileSystemException catch (e) {
throwToolExit('Failed to create directory "$dirPath": ${e.osError.message}');
}
}
void copyDirectorySync(Directory srcDir, Directory destDir, [ void onFileCopied(File srcFile, File destFile) ]) {
if (!srcDir.existsSync())
throw Exception('Source directory "${srcDir.path}" does not exist, nothing to copy');
if (!destDir.existsSync())
destDir.createSync(recursive: true);
for (FileSystemEntity entity in srcDir.listSync()) {
final String newPath = destDir.fileSystem.path.join(destDir.path, entity.basename);
if (entity is File) {
final File newFile = destDir.fileSystem.file(newPath);
newFile.writeAsBytesSync(entity.readAsBytesSync());
onFileCopied?.call(entity, newFile);
} else if (entity is Directory) {
copyDirectorySync(
entity, destDir.fileSystem.directory(newPath));
} else {
throw Exception('${entity.path} is neither File nor Directory');
}
}
}
Directory getRecordingSink(String dirname, String basename) {
final String location = _kLocalFs.path.join(dirname, basename);
switch (_kLocalFs.typeSync(location, followLinks: false)) {
case FileSystemEntityType.file:
case FileSystemEntityType.link:
throwToolExit('Invalid record-to location: $dirname ("$basename" exists as non-directory)');
break;
case FileSystemEntityType.directory:
if (_kLocalFs.directory(location).listSync(followLinks: false).isNotEmpty)
throwToolExit('Invalid record-to location: $dirname ("$basename" is not empty)');
break;
case FileSystemEntityType.notFound:
_kLocalFs.directory(location).createSync(recursive: true);
}
return _kLocalFs.directory(location);
}
Directory getReplaySource(String dirname, String basename) {
final Directory dir = _kLocalFs.directory(_kLocalFs.path.join(dirname, basename));
if (!dir.existsSync())
throwToolExit('Invalid replay-from location: $dirname ("$basename" does not exist)');
return dir;
}
String canonicalizePath(String path) => fs.path.normalize(fs.path.absolute(path));
String escapePath(String path) => platform.isWindows ? path.replaceAll('\\', '\\\\') : path;
bool isOlderThanReference({ @required FileSystemEntity entity, @required File referenceFile }) {
if (!entity.existsSync())
return true;
return referenceFile.existsSync()
&& referenceFile.lastModifiedSync().isAfter(entity.statSync().modified);
}
class FileNotFoundException implements IOException {
const FileNotFoundException(this.path);
final String path;
@override
String toString() => 'File not found: $path';
}