Introduce overwrite parameter to File.copyRecursively.
#KT-8924 Fixed
This commit is contained in:
@@ -218,7 +218,7 @@ public enum class OnErrorAction {
|
|||||||
private class TerminateException(file: File) : FileSystemException(file) {}
|
private class TerminateException(file: File) : FileSystemException(file) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies this file with all its children to the specified destination [dst] path.
|
* Copies this file with all its children to the specified destination [target] path.
|
||||||
* If some directories on the way to the destination are missing, then they will be created.
|
* If some directories on the way to the destination are missing, then they will be created.
|
||||||
*
|
*
|
||||||
* If any errors occur during the copying, then further actions will depend on the result of the call
|
* If any errors occur during the copying, then further actions will depend on the result of the call
|
||||||
@@ -231,11 +231,13 @@ private class TerminateException(file: File) : FileSystemException(file) {}
|
|||||||
* AccessDeniedException - if there was an attempt to open a directory that didn't succeed.
|
* AccessDeniedException - if there was an attempt to open a directory that didn't succeed.
|
||||||
* IOException - if some problems occur when copying.
|
* IOException - if some problems occur when copying.
|
||||||
*
|
*
|
||||||
|
* @param overwrite `true` if it is allowed to overwrite existing destination files and directories.
|
||||||
* @return `false` if the copying was terminated, `true` otherwise.
|
* @return `false` if the copying was terminated, `true` otherwise.
|
||||||
*
|
*
|
||||||
* Note that if this function fails, then partial copying may have taken place.
|
* Note that if this function fails, then partial copying may have taken place.
|
||||||
*/
|
*/
|
||||||
public fun File.copyRecursively(dst: File,
|
public fun File.copyRecursively(target: File,
|
||||||
|
overwrite: Boolean = false,
|
||||||
onError: (File, IOException) -> OnErrorAction =
|
onError: (File, IOException) -> OnErrorAction =
|
||||||
{ file, exception -> throw exception }
|
{ file, exception -> throw exception }
|
||||||
): Boolean {
|
): Boolean {
|
||||||
@@ -252,16 +254,29 @@ public fun File.copyRecursively(dst: File,
|
|||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
val relPath = src.toRelativeString(this)
|
val relPath = src.toRelativeString(this)
|
||||||
val dstFile = File(dst, relPath)
|
val dstFile = File(target, relPath)
|
||||||
if (dstFile.exists() && !(src.isDirectory && dstFile.isDirectory)) {
|
if (dstFile.exists() && !(src.isDirectory && dstFile.isDirectory)) {
|
||||||
if (onError(dstFile, FileAlreadyExistsException(file = src,
|
val stillExists = if (!overwrite) true else {
|
||||||
other = dstFile,
|
if (dstFile.isDirectory)
|
||||||
reason = "The destination file already exists")) == OnErrorAction.TERMINATE)
|
!dstFile.deleteRecursively()
|
||||||
return false
|
else
|
||||||
} else if (src.isDirectory) {
|
!dstFile.delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stillExists) {
|
||||||
|
if (onError(dstFile, FileAlreadyExistsException(file = src,
|
||||||
|
other = dstFile,
|
||||||
|
reason = "The destination file already exists")) == OnErrorAction.TERMINATE)
|
||||||
|
return false
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src.isDirectory) {
|
||||||
dstFile.mkdirs()
|
dstFile.mkdirs()
|
||||||
} else {
|
} else {
|
||||||
if (src.copyTo(dstFile, true) != src.length()) {
|
if (src.copyTo(dstFile, overwrite) != src.length()) {
|
||||||
if (onError(src, IOException("src.length() != dst.length()")) == OnErrorAction.TERMINATE)
|
if (onError(src, IOException("src.length() != dst.length()")) == OnErrorAction.TERMINATE)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -451,20 +451,22 @@ class FilesTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun compareDirectories(src: File, dst: File) {
|
||||||
|
for (file in src.walkTopDown()) {
|
||||||
|
val dstFile = dst.resolve(file.relativeTo(src))
|
||||||
|
assertTrue(dstFile.exists())
|
||||||
|
assertEquals(file.isFile, dstFile.isFile)
|
||||||
|
if (dstFile.isFile) {
|
||||||
|
assertEquals(file.readText(), dstFile.readText())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@test fun copyRecursively() {
|
@test fun copyRecursively() {
|
||||||
val src = createTempDir()
|
val src = createTempDir()
|
||||||
val dst = createTempDir()
|
val dst = createTempDir()
|
||||||
dst.delete()
|
dst.delete()
|
||||||
fun check() {
|
fun check() = compareDirectories(src, dst)
|
||||||
for (file in src.walkTopDown()) {
|
|
||||||
val dstFile = dst.resolve(file.relativeTo(src))
|
|
||||||
assertTrue(dstFile.exists())
|
|
||||||
if (dstFile.isFile) {
|
|
||||||
assertEquals(file.readText(), dstFile.readText())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val subDir1 = createTempDir(prefix = "d1_", directory = src)
|
val subDir1 = createTempDir(prefix = "d1_", directory = src)
|
||||||
@@ -531,6 +533,40 @@ class FilesTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test fun copyRecursivelyWithOverwrite() {
|
||||||
|
val src = createTempDir()
|
||||||
|
val dst = createTempDir()
|
||||||
|
fun check() = compareDirectories(src, dst)
|
||||||
|
|
||||||
|
try {
|
||||||
|
val srcFile = src.resolve("test")
|
||||||
|
val dstFile = dst.resolve("test")
|
||||||
|
srcFile.writeText("text1")
|
||||||
|
|
||||||
|
src.copyRecursively(dst)
|
||||||
|
|
||||||
|
srcFile.writeText("text1 modified")
|
||||||
|
src.copyRecursively(dst, overwrite = true)
|
||||||
|
check()
|
||||||
|
|
||||||
|
dstFile.delete()
|
||||||
|
dstFile.mkdir()
|
||||||
|
dstFile.resolve("subFile").writeText("subfile")
|
||||||
|
src.copyRecursively(dst, overwrite = true)
|
||||||
|
check()
|
||||||
|
|
||||||
|
srcFile.delete()
|
||||||
|
srcFile.mkdir()
|
||||||
|
srcFile.resolve("subFile").writeText("text2")
|
||||||
|
src.copyRecursively(dst, overwrite = true)
|
||||||
|
check()
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
src.deleteRecursively()
|
||||||
|
dst.deleteRecursively()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@test fun helpers1() {
|
@test fun helpers1() {
|
||||||
val str = "123456789\n"
|
val str = "123456789\n"
|
||||||
System.setIn(str.byteInputStream())
|
System.setIn(str.byteInputStream())
|
||||||
|
|||||||
Reference in New Issue
Block a user