Update copyDirectory to allow links to not be followed (#144040)
In other words, copy links within a directory as links rather than copying them as files/directories. Fixes https://github.com/flutter/flutter/issues/144032.
This commit is contained in:
parent
d05eaf4a98
commit
45c8881eb2
@ -109,12 +109,19 @@ String getDisplayPath(String fullPath, FileSystem fileSystem) {
|
|||||||
///
|
///
|
||||||
/// Skips files if [shouldCopyFile] returns `false`.
|
/// Skips files if [shouldCopyFile] returns `false`.
|
||||||
/// Does not recurse over directories if [shouldCopyDirectory] returns `false`.
|
/// Does not recurse over directories if [shouldCopyDirectory] returns `false`.
|
||||||
|
///
|
||||||
|
/// If [followLinks] is false, then any symbolic links found are reported as
|
||||||
|
/// [Link] objects, rather than as directories or files, and are not recursed into.
|
||||||
|
///
|
||||||
|
/// If [followLinks] is true, then working links are reported as directories or
|
||||||
|
/// files, depending on what they point to.
|
||||||
void copyDirectory(
|
void copyDirectory(
|
||||||
Directory srcDir,
|
Directory srcDir,
|
||||||
Directory destDir, {
|
Directory destDir, {
|
||||||
bool Function(File srcFile, File destFile)? shouldCopyFile,
|
bool Function(File srcFile, File destFile)? shouldCopyFile,
|
||||||
bool Function(Directory)? shouldCopyDirectory,
|
bool Function(Directory)? shouldCopyDirectory,
|
||||||
void Function(File srcFile, File destFile)? onFileCopied,
|
void Function(File srcFile, File destFile)? onFileCopied,
|
||||||
|
bool followLinks = true,
|
||||||
}) {
|
}) {
|
||||||
if (!srcDir.existsSync()) {
|
if (!srcDir.existsSync()) {
|
||||||
throw Exception('Source directory "${srcDir.path}" does not exist, nothing to copy');
|
throw Exception('Source directory "${srcDir.path}" does not exist, nothing to copy');
|
||||||
@ -124,7 +131,7 @@ void copyDirectory(
|
|||||||
destDir.createSync(recursive: true);
|
destDir.createSync(recursive: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final FileSystemEntity entity in srcDir.listSync()) {
|
for (final FileSystemEntity entity in srcDir.listSync(followLinks: followLinks)) {
|
||||||
final String newPath = destDir.fileSystem.path.join(destDir.path, entity.basename);
|
final String newPath = destDir.fileSystem.path.join(destDir.path, entity.basename);
|
||||||
if (entity is Link) {
|
if (entity is Link) {
|
||||||
final Link newLink = destDir.fileSystem.link(newPath);
|
final Link newLink = destDir.fileSystem.link(newPath);
|
||||||
@ -145,6 +152,7 @@ void copyDirectory(
|
|||||||
destDir.fileSystem.directory(newPath),
|
destDir.fileSystem.directory(newPath),
|
||||||
shouldCopyFile: shouldCopyFile,
|
shouldCopyFile: shouldCopyFile,
|
||||||
onFileCopied: onFileCopied,
|
onFileCopied: onFileCopied,
|
||||||
|
followLinks: followLinks,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
throw Exception('${entity.path} is neither File nor Directory, was ${entity.runtimeType}');
|
throw Exception('${entity.path} is neither File nor Directory, was ${entity.runtimeType}');
|
||||||
|
@ -88,6 +88,106 @@ void main() {
|
|||||||
expect(sourceMemoryFs.directory(sourcePath).listSync().length, 3);
|
expect(sourceMemoryFs.directory(sourcePath).listSync().length, 3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWithoutContext('test directory copy with followLinks: true', () async {
|
||||||
|
final Signals signals = Signals.test();
|
||||||
|
final LocalFileSystem fileSystem = LocalFileSystem.test(
|
||||||
|
signals: signals,
|
||||||
|
);
|
||||||
|
final Directory tempDir = fileSystem.systemTempDirectory.createTempSync('flutter_copy_directory.');
|
||||||
|
try {
|
||||||
|
final String sourcePath = io.Platform.isWindows ? r'some\origin' : 'some/origin';
|
||||||
|
final Directory sourceDirectory = tempDir.childDirectory(sourcePath)..createSync(recursive: true);
|
||||||
|
final File sourceFile1 = sourceDirectory.childFile('some_file.txt')..writeAsStringSync('file 1');
|
||||||
|
sourceDirectory.childLink('absolute_linked.txt').createSync(sourceFile1.absolute.path);
|
||||||
|
final DateTime writeTime = sourceFile1.lastModifiedSync();
|
||||||
|
final Directory sourceSubDirectory = sourceDirectory.childDirectory('dir1').childDirectory('dir2')..createSync(recursive: true);
|
||||||
|
sourceSubDirectory.childFile('another_file.txt').writeAsStringSync('file 2');
|
||||||
|
final String subdirectorySourcePath = io.Platform.isWindows ? r'dir1\dir2' : 'dir1/dir2';
|
||||||
|
sourceDirectory.childLink('relative_linked_sub_dir').createSync(subdirectorySourcePath);
|
||||||
|
sourceDirectory.childDirectory('empty_directory').createSync(recursive: true);
|
||||||
|
|
||||||
|
final String targetPath = io.Platform.isWindows ? r'some\non-existent\target' : 'some/non-existent/target';
|
||||||
|
final Directory targetDirectory = tempDir.childDirectory(targetPath);
|
||||||
|
|
||||||
|
copyDirectory(sourceDirectory, targetDirectory);
|
||||||
|
|
||||||
|
expect(targetDirectory.existsSync(), true);
|
||||||
|
expect(targetDirectory.childFile('some_file.txt').existsSync(), true);
|
||||||
|
expect(targetDirectory.childFile('some_file.txt').readAsStringSync(), 'file 1');
|
||||||
|
expect(targetDirectory.childFile('absolute_linked.txt').readAsStringSync(), 'file 1');
|
||||||
|
expect(targetDirectory.childLink('absolute_linked.txt').existsSync(), false);
|
||||||
|
expect(targetDirectory.childDirectory('dir1').childDirectory('dir2').existsSync(), true);
|
||||||
|
expect(targetDirectory.childDirectory('dir1').childDirectory('dir2').childFile('another_file.txt').existsSync(), true);
|
||||||
|
expect(targetDirectory.childDirectory('dir1').childDirectory('dir2').childFile('another_file.txt').readAsStringSync(), 'file 2');
|
||||||
|
expect(targetDirectory.childDirectory('relative_linked_sub_dir').existsSync(), true);
|
||||||
|
expect(targetDirectory.childLink('relative_linked_sub_dir').existsSync(), false);
|
||||||
|
expect(targetDirectory.childDirectory('relative_linked_sub_dir').childFile('another_file.txt').existsSync(), true);
|
||||||
|
expect(targetDirectory.childDirectory('relative_linked_sub_dir').childFile('another_file.txt').readAsStringSync(), 'file 2');
|
||||||
|
expect(targetDirectory.childDirectory('empty_directory').existsSync(), true);
|
||||||
|
|
||||||
|
// Assert that the copy operation hasn't modified the original file in some way.
|
||||||
|
expect(sourceDirectory.childFile('some_file.txt').lastModifiedSync(), writeTime);
|
||||||
|
// There's still 5 things in the original directory as there were initially.
|
||||||
|
expect(sourceDirectory.listSync().length, 5);
|
||||||
|
} finally {
|
||||||
|
tryToDelete(tempDir);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('test directory copy with followLinks: false', () async {
|
||||||
|
final Signals signals = Signals.test();
|
||||||
|
final LocalFileSystem fileSystem = LocalFileSystem.test(
|
||||||
|
signals: signals,
|
||||||
|
);
|
||||||
|
final Directory tempDir = fileSystem.systemTempDirectory.createTempSync('flutter_copy_directory.');
|
||||||
|
try {
|
||||||
|
final String sourcePath = io.Platform.isWindows ? r'some\origin' : 'some/origin';
|
||||||
|
final Directory sourceDirectory = tempDir.childDirectory(sourcePath)..createSync(recursive: true);
|
||||||
|
final File sourceFile1 = sourceDirectory.childFile('some_file.txt')..writeAsStringSync('file 1');
|
||||||
|
sourceDirectory.childLink('absolute_linked.txt').createSync(sourceFile1.absolute.path);
|
||||||
|
final DateTime writeTime = sourceFile1.lastModifiedSync();
|
||||||
|
final Directory sourceSubDirectory = sourceDirectory.childDirectory('dir1').childDirectory('dir2')..createSync(recursive: true);
|
||||||
|
sourceSubDirectory.childFile('another_file.txt').writeAsStringSync('file 2');
|
||||||
|
final String subdirectorySourcePath = io.Platform.isWindows ? r'dir1\dir2' : 'dir1/dir2';
|
||||||
|
sourceDirectory.childLink('relative_linked_sub_dir').createSync(subdirectorySourcePath);
|
||||||
|
sourceDirectory.childDirectory('empty_directory').createSync(recursive: true);
|
||||||
|
|
||||||
|
final String targetPath = io.Platform.isWindows ? r'some\non-existent\target' : 'some/non-existent/target';
|
||||||
|
final Directory targetDirectory = tempDir.childDirectory(targetPath);
|
||||||
|
|
||||||
|
copyDirectory(sourceDirectory, targetDirectory, followLinks: false);
|
||||||
|
|
||||||
|
expect(targetDirectory.existsSync(), true);
|
||||||
|
expect(targetDirectory.childFile('some_file.txt').existsSync(), true);
|
||||||
|
expect(targetDirectory.childFile('some_file.txt').readAsStringSync(), 'file 1');
|
||||||
|
expect(targetDirectory.childFile('absolute_linked.txt').readAsStringSync(), 'file 1');
|
||||||
|
expect(targetDirectory.childLink('absolute_linked.txt').existsSync(), true);
|
||||||
|
expect(
|
||||||
|
targetDirectory.childLink('absolute_linked.txt').targetSync(),
|
||||||
|
sourceFile1.absolute.path,
|
||||||
|
);
|
||||||
|
expect(targetDirectory.childDirectory('dir1').childDirectory('dir2').existsSync(), true);
|
||||||
|
expect(targetDirectory.childDirectory('dir1').childDirectory('dir2').childFile('another_file.txt').existsSync(), true);
|
||||||
|
expect(targetDirectory.childDirectory('dir1').childDirectory('dir2').childFile('another_file.txt').readAsStringSync(), 'file 2');
|
||||||
|
expect(targetDirectory.childDirectory('relative_linked_sub_dir').existsSync(), true);
|
||||||
|
expect(targetDirectory.childLink('relative_linked_sub_dir').existsSync(), true);
|
||||||
|
expect(
|
||||||
|
targetDirectory.childLink('relative_linked_sub_dir').targetSync(),
|
||||||
|
subdirectorySourcePath,
|
||||||
|
);
|
||||||
|
expect(targetDirectory.childDirectory('relative_linked_sub_dir').childFile('another_file.txt').existsSync(), true);
|
||||||
|
expect(targetDirectory.childDirectory('relative_linked_sub_dir').childFile('another_file.txt').readAsStringSync(), 'file 2');
|
||||||
|
expect(targetDirectory.childDirectory('empty_directory').existsSync(), true);
|
||||||
|
|
||||||
|
// Assert that the copy operation hasn't modified the original file in some way.
|
||||||
|
expect(sourceDirectory.childFile('some_file.txt').lastModifiedSync(), writeTime);
|
||||||
|
// There's still 5 things in the original directory as there were initially.
|
||||||
|
expect(sourceDirectory.listSync().length, 5);
|
||||||
|
} finally {
|
||||||
|
tryToDelete(tempDir);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
testWithoutContext('Skip files if shouldCopyFile returns false', () {
|
testWithoutContext('Skip files if shouldCopyFile returns false', () {
|
||||||
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
||||||
final Directory origin = fileSystem.directory('/origin');
|
final Directory origin = fileSystem.directory('/origin');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user