added skip all on error
This commit is contained in:
parent
61998ecc40
commit
f7d63027d4
1
.gitignore
vendored
1
.gitignore
vendored
@ -23,3 +23,4 @@ buildNumber.properties
|
|||||||
# OS
|
# OS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
.claude
|
||||||
@ -59,6 +59,7 @@ public class FileOperations {
|
|||||||
long totalItems = calculateTotalItems(cleanedItems);
|
long totalItems = calculateTotalItems(cleanedItems);
|
||||||
final long[] currentItem = {0};
|
final long[] currentItem = {0};
|
||||||
final OverwriteResponse[] globalResponse = {null};
|
final OverwriteResponse[] globalResponse = {null};
|
||||||
|
final ErrorResponse[] globalErrorResponse = {null};
|
||||||
|
|
||||||
for (FileItem item : cleanedItems) {
|
for (FileItem item : cleanedItems) {
|
||||||
if (callback != null && callback.isCancelled()) break;
|
if (callback != null && callback.isCancelled()) break;
|
||||||
@ -95,9 +96,10 @@ public class FileOperations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
if (globalErrorResponse[0] == ErrorResponse.SKIP_ALL) break;
|
||||||
try {
|
try {
|
||||||
if (source.isDirectory()) {
|
if (source.isDirectory()) {
|
||||||
copyDirectory(source, target, totalItems, currentItem, callback, globalResponse);
|
copyDirectory(source, target, totalItems, currentItem, callback, globalResponse, globalErrorResponse);
|
||||||
} else {
|
} else {
|
||||||
copyFileWithProgress(source, target, totalItems, currentItem, callback);
|
copyFileWithProgress(source, target, totalItems, currentItem, callback);
|
||||||
}
|
}
|
||||||
@ -107,6 +109,7 @@ public class FileOperations {
|
|||||||
ErrorResponse res = callback.onError(source, e);
|
ErrorResponse res = callback.onError(source, e);
|
||||||
if (res == ErrorResponse.ABORT) throw e;
|
if (res == ErrorResponse.ABORT) throw e;
|
||||||
if (res == ErrorResponse.RETRY) continue;
|
if (res == ErrorResponse.RETRY) continue;
|
||||||
|
if (res == ErrorResponse.SKIP_ALL) globalErrorResponse[0] = ErrorResponse.SKIP_ALL;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
throw e;
|
throw e;
|
||||||
@ -163,7 +166,7 @@ public class FileOperations {
|
|||||||
copyPermissions(source, target);
|
copyPermissions(source, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void copyDirectory(File source, File target, long totalItems, final long[] currentItem, ProgressCallback callback, final OverwriteResponse[] globalResponse) throws IOException {
|
private static void copyDirectory(File source, File target, long totalItems, final long[] currentItem, ProgressCallback callback, final OverwriteResponse[] globalResponse, final ErrorResponse[] globalErrorResponse) throws IOException {
|
||||||
if (!target.exists()) {
|
if (!target.exists()) {
|
||||||
if (!target.mkdirs()) {
|
if (!target.mkdirs()) {
|
||||||
throw new IOException("Failed to create directory: " + target.getAbsolutePath());
|
throw new IOException("Failed to create directory: " + target.getAbsolutePath());
|
||||||
@ -179,32 +182,52 @@ public class FileOperations {
|
|||||||
if (files != null) {
|
if (files != null) {
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
if (callback != null && callback.isCancelled()) break;
|
if (callback != null && callback.isCancelled()) break;
|
||||||
|
if (globalErrorResponse[0] == ErrorResponse.SKIP_ALL) break;
|
||||||
File targetFile = new File(target, file.getName());
|
File targetFile = new File(target, file.getName());
|
||||||
|
|
||||||
if (file.isDirectory()) {
|
while (true) {
|
||||||
copyDirectory(file, targetFile, totalItems, currentItem, callback, globalResponse);
|
try {
|
||||||
} else {
|
if (file.isDirectory()) {
|
||||||
if (targetFile.exists()) {
|
copyDirectory(file, targetFile, totalItems, currentItem, callback, globalResponse, globalErrorResponse);
|
||||||
if (globalResponse[0] == OverwriteResponse.NO_TO_ALL) {
|
} else {
|
||||||
currentItem[0] += countItems(file);
|
if (targetFile.exists()) {
|
||||||
continue;
|
if (globalResponse[0] == OverwriteResponse.NO_TO_ALL) {
|
||||||
|
currentItem[0] += countItems(file);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (globalResponse[0] != OverwriteResponse.YES_TO_ALL) {
|
||||||
|
OverwriteResponse res = callback.confirmOverwrite(file, targetFile);
|
||||||
|
if (res == OverwriteResponse.CANCEL) return;
|
||||||
|
if (res == OverwriteResponse.NO_TO_ALL) {
|
||||||
|
globalResponse[0] = OverwriteResponse.NO_TO_ALL;
|
||||||
|
currentItem[0] += countItems(file);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (res == OverwriteResponse.NO) {
|
||||||
|
currentItem[0] += countItems(file);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (res == OverwriteResponse.YES_TO_ALL)
|
||||||
|
globalResponse[0] = OverwriteResponse.YES_TO_ALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
copyFileWithProgress(file, targetFile, totalItems, currentItem, callback);
|
||||||
}
|
}
|
||||||
if (globalResponse[0] != OverwriteResponse.YES_TO_ALL) {
|
break;
|
||||||
OverwriteResponse res = callback.confirmOverwrite(file, targetFile);
|
} catch (IOException e) {
|
||||||
if (res == OverwriteResponse.CANCEL) return;
|
if (callback != null) {
|
||||||
if (res == OverwriteResponse.NO_TO_ALL) {
|
ErrorResponse res = callback.onError(file, e);
|
||||||
globalResponse[0] = OverwriteResponse.NO_TO_ALL;
|
if (res == ErrorResponse.ABORT) throw e;
|
||||||
currentItem[0] += countItems(file);
|
if (res == ErrorResponse.RETRY) continue;
|
||||||
continue;
|
if (res == ErrorResponse.SKIP_ALL) globalErrorResponse[0] = ErrorResponse.SKIP_ALL;
|
||||||
}
|
// SKIP: Break while(true) to continue with next file in for loop
|
||||||
if (res == OverwriteResponse.NO) {
|
// we don't increment currentItem here because it's hard to know
|
||||||
currentItem[0] += countItems(file);
|
// what exactly was processed inside copyDirectory if it failed midway.
|
||||||
continue;
|
break;
|
||||||
}
|
} else {
|
||||||
if (res == OverwriteResponse.YES_TO_ALL) globalResponse[0] = OverwriteResponse.YES_TO_ALL;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
copyFileWithProgress(file, targetFile, totalItems, currentItem, callback);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -273,6 +296,7 @@ public class FileOperations {
|
|||||||
long totalItems = calculateTotalItems(cleanedItems);
|
long totalItems = calculateTotalItems(cleanedItems);
|
||||||
long[] currentItem = {0};
|
long[] currentItem = {0};
|
||||||
final OverwriteResponse[] globalResponse = {null};
|
final OverwriteResponse[] globalResponse = {null};
|
||||||
|
final ErrorResponse[] globalErrorResponse = {null};
|
||||||
|
|
||||||
for (FileItem item : cleanedItems) {
|
for (FileItem item : cleanedItems) {
|
||||||
if (callback != null && callback.isCancelled()) break;
|
if (callback != null && callback.isCancelled()) break;
|
||||||
@ -306,6 +330,7 @@ public class FileOperations {
|
|||||||
|
|
||||||
long itemCount = countItems(source);
|
long itemCount = countItems(source);
|
||||||
while (true) {
|
while (true) {
|
||||||
|
if (globalErrorResponse[0] == ErrorResponse.SKIP_ALL) break;
|
||||||
try {
|
try {
|
||||||
if (source.renameTo(target)) {
|
if (source.renameTo(target)) {
|
||||||
currentItem[0] += itemCount;
|
currentItem[0] += itemCount;
|
||||||
@ -315,7 +340,7 @@ public class FileOperations {
|
|||||||
} else {
|
} else {
|
||||||
// Fallback for cross-device moves
|
// Fallback for cross-device moves
|
||||||
if (source.isDirectory()) {
|
if (source.isDirectory()) {
|
||||||
copyDirectory(source, target, totalItems, currentItem, callback, globalResponse);
|
copyDirectory(source, target, totalItems, currentItem, callback, globalResponse, globalErrorResponse);
|
||||||
deleteDirectoryInternal(source);
|
deleteDirectoryInternal(source);
|
||||||
} else {
|
} else {
|
||||||
copyFileWithProgress(source, target, totalItems, currentItem, callback);
|
copyFileWithProgress(source, target, totalItems, currentItem, callback);
|
||||||
@ -328,6 +353,7 @@ public class FileOperations {
|
|||||||
ErrorResponse res = callback.onError(source, e);
|
ErrorResponse res = callback.onError(source, e);
|
||||||
if (res == ErrorResponse.ABORT) throw e;
|
if (res == ErrorResponse.ABORT) throw e;
|
||||||
if (res == ErrorResponse.RETRY) continue;
|
if (res == ErrorResponse.RETRY) continue;
|
||||||
|
if (res == ErrorResponse.SKIP_ALL) globalErrorResponse[0] = ErrorResponse.SKIP_ALL;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
throw e;
|
throw e;
|
||||||
@ -348,15 +374,17 @@ public class FileOperations {
|
|||||||
List<FileItem> cleanedItems = cleanDuplicateItems(items);
|
List<FileItem> cleanedItems = cleanDuplicateItems(items);
|
||||||
long totalItems = calculateTotalItems(cleanedItems);
|
long totalItems = calculateTotalItems(cleanedItems);
|
||||||
long[] currentItem = {0};
|
long[] currentItem = {0};
|
||||||
|
final ErrorResponse[] globalErrorResponse = {null};
|
||||||
|
|
||||||
for (FileItem item : cleanedItems) {
|
for (FileItem item : cleanedItems) {
|
||||||
if (callback != null && callback.isCancelled()) break;
|
if (callback != null && callback.isCancelled()) break;
|
||||||
File file = item.getFile();
|
File file = item.getFile();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
if (globalErrorResponse[0] == ErrorResponse.SKIP_ALL) break;
|
||||||
try {
|
try {
|
||||||
if (file.isDirectory()) {
|
if (file.isDirectory()) {
|
||||||
deleteDirectoryRecursive(file, totalItems, currentItem, callback);
|
deleteDirectoryRecursive(file, totalItems, currentItem, callback, globalErrorResponse);
|
||||||
} else {
|
} else {
|
||||||
currentItem[0]++;
|
currentItem[0]++;
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
@ -370,6 +398,7 @@ public class FileOperations {
|
|||||||
ErrorResponse res = callback.onError(file, e);
|
ErrorResponse res = callback.onError(file, e);
|
||||||
if (res == ErrorResponse.ABORT) throw e;
|
if (res == ErrorResponse.ABORT) throw e;
|
||||||
if (res == ErrorResponse.RETRY) continue;
|
if (res == ErrorResponse.RETRY) continue;
|
||||||
|
if (res == ErrorResponse.SKIP_ALL) globalErrorResponse[0] = ErrorResponse.SKIP_ALL;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
throw e;
|
throw e;
|
||||||
@ -379,18 +408,36 @@ public class FileOperations {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void deleteDirectoryRecursive(File directory, long totalItems, long[] currentItem, ProgressCallback callback) throws IOException {
|
private static void deleteDirectoryRecursive(File directory, long totalItems, long[] currentItem, ProgressCallback callback, final ErrorResponse[] globalErrorResponse) throws IOException {
|
||||||
File[] children = directory.listFiles();
|
File[] children = directory.listFiles();
|
||||||
if (children != null) {
|
if (children != null) {
|
||||||
for (File child : children) {
|
for (File child : children) {
|
||||||
if (child.isDirectory()) {
|
if (callback != null && callback.isCancelled()) break;
|
||||||
deleteDirectoryRecursive(child, totalItems, currentItem, callback);
|
if (globalErrorResponse[0] == ErrorResponse.SKIP_ALL) break;
|
||||||
} else {
|
while (true) {
|
||||||
currentItem[0]++;
|
try {
|
||||||
if (callback != null) {
|
if (child.isDirectory()) {
|
||||||
callback.onProgress(currentItem[0], totalItems, child.getName());
|
deleteDirectoryRecursive(child, totalItems, currentItem, callback, globalErrorResponse);
|
||||||
|
} else {
|
||||||
|
currentItem[0]++;
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onProgress(currentItem[0], totalItems, child.getName());
|
||||||
|
}
|
||||||
|
deleteFileWithForce(child);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (callback != null) {
|
||||||
|
ErrorResponse res = callback.onError(child, e);
|
||||||
|
if (res == ErrorResponse.ABORT) throw e;
|
||||||
|
if (res == ErrorResponse.RETRY) continue;
|
||||||
|
if (res == ErrorResponse.SKIP_ALL) globalErrorResponse[0] = ErrorResponse.SKIP_ALL;
|
||||||
|
// SKIP:
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
deleteFileWithForce(child);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -490,9 +537,23 @@ public class FileOperations {
|
|||||||
public static void deleteFromFtp(List<FileItem> items, ProgressCallback callback) throws IOException {
|
public static void deleteFromFtp(List<FileItem> items, ProgressCallback callback) throws IOException {
|
||||||
for (FileItem item : items) {
|
for (FileItem item : items) {
|
||||||
if (callback != null && callback.isCancelled()) break;
|
if (callback != null && callback.isCancelled()) break;
|
||||||
FtpService.deleteOnFtp(item.getFtpProfile(), item.getFtpPath());
|
while (true) {
|
||||||
if (callback != null) {
|
try {
|
||||||
callback.onFileProgress(item.getSize(), item.getSize());
|
FtpService.deleteOnFtp(item.getFtpProfile(), item.getFtpPath());
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onFileProgress(item.getSize(), item.getSize());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (callback != null) {
|
||||||
|
ErrorResponse res = callback.onError(item.getFile(), e);
|
||||||
|
if (res == ErrorResponse.ABORT) throw e;
|
||||||
|
if (res == ErrorResponse.RETRY) continue;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -504,23 +565,37 @@ public class FileOperations {
|
|||||||
for (FileItem item : items) {
|
for (FileItem item : items) {
|
||||||
if (callback != null && callback.isCancelled()) break;
|
if (callback != null && callback.isCancelled()) break;
|
||||||
|
|
||||||
if (item.isDirectory()) {
|
while (true) {
|
||||||
if (item.isFtp()) {
|
try {
|
||||||
File tempDir = java.nio.file.Files.createTempDirectory("kf-ftp-copy").toFile();
|
if (item.isDirectory()) {
|
||||||
copyFromFtp(java.util.Collections.singletonList(item), tempDir, callback);
|
if (item.isFtp()) {
|
||||||
uploadLocalToFtp(profile, tempDir, remotePath + "/" + item.getName(), callback);
|
File tempDir = java.nio.file.Files.createTempDirectory("kf-ftp-copy").toFile();
|
||||||
deleteRecursively(tempDir);
|
copyFromFtp(java.util.Collections.singletonList(item), tempDir, callback);
|
||||||
} else {
|
uploadLocalToFtp(profile, tempDir, remotePath + "/" + item.getName(), callback);
|
||||||
uploadLocalToFtp(profile, item.getFile(), remotePath + "/" + item.getName(), callback);
|
deleteRecursively(tempDir);
|
||||||
}
|
} else {
|
||||||
} else {
|
uploadLocalToFtp(profile, item.getFile(), remotePath + "/" + item.getName(), callback);
|
||||||
if (item.isFtp()) {
|
}
|
||||||
File tempFile = java.nio.file.Files.createTempFile("kf-ftp-copy", ".tmp").toFile();
|
} else {
|
||||||
FtpService.downloadFile(item.getFtpProfile(), item.getFtpPath(), tempFile, callback);
|
if (item.isFtp()) {
|
||||||
FtpService.uploadFile(profile, tempFile, remotePath + "/" + item.getName(), callback);
|
File tempFile = java.nio.file.Files.createTempFile("kf-ftp-copy", ".tmp").toFile();
|
||||||
tempFile.delete();
|
FtpService.downloadFile(item.getFtpProfile(), item.getFtpPath(), tempFile, callback);
|
||||||
} else {
|
FtpService.uploadFile(profile, tempFile, remotePath + "/" + item.getName(), callback);
|
||||||
FtpService.uploadFile(profile, item.getFile(), remotePath + "/" + item.getName(), callback);
|
tempFile.delete();
|
||||||
|
} else {
|
||||||
|
FtpService.uploadFile(profile, item.getFile(), remotePath + "/" + item.getName(), callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (callback != null) {
|
||||||
|
ErrorResponse res = callback.onError(item.getFile(), e);
|
||||||
|
if (res == ErrorResponse.ABORT) throw e;
|
||||||
|
if (res == ErrorResponse.RETRY) continue;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -543,22 +618,36 @@ public class FileOperations {
|
|||||||
|
|
||||||
for (FileItem item : ftpItems) {
|
for (FileItem item : ftpItems) {
|
||||||
if (callback != null && callback.isCancelled()) break;
|
if (callback != null && callback.isCancelled()) break;
|
||||||
|
|
||||||
if (callback != null) {
|
|
||||||
callback.onProgress(currentItem[0], totalItems, item.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.isDirectory()) {
|
while (true) {
|
||||||
File targetDir = new File(localTarget, item.getName());
|
try {
|
||||||
FtpService.downloadDirectory(item.getFtpProfile(), item.getFtpPath(), targetDir, callback);
|
if (callback != null) {
|
||||||
} else {
|
callback.onProgress(currentItem[0], totalItems, item.getName());
|
||||||
File targetFile = new File(localTarget, item.getName());
|
}
|
||||||
FtpService.downloadFile(item.getFtpProfile(), item.getFtpPath(), targetFile, callback);
|
|
||||||
}
|
if (item.isDirectory()) {
|
||||||
|
File targetDir = new File(localTarget, item.getName());
|
||||||
currentItem[0]++;
|
FtpService.downloadDirectory(item.getFtpProfile(), item.getFtpPath(), targetDir, callback);
|
||||||
if (callback != null) {
|
} else {
|
||||||
callback.onProgress(currentItem[0], totalItems, item.getName());
|
File targetFile = new File(localTarget, item.getName());
|
||||||
|
FtpService.downloadFile(item.getFtpProfile(), item.getFtpPath(), targetFile, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentItem[0]++;
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onProgress(currentItem[0], totalItems, item.getName());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (callback != null) {
|
||||||
|
ErrorResponse res = callback.onError(item.getFile(), e);
|
||||||
|
if (res == ErrorResponse.ABORT) throw e;
|
||||||
|
if (res == ErrorResponse.RETRY) continue;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1635,7 +1724,7 @@ public class FileOperations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum ErrorResponse {
|
public enum ErrorResponse {
|
||||||
RETRY, SKIP, ABORT
|
RETRY, SKIP, SKIP_ALL, ABORT
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SymlinkResponse {
|
public enum SymlinkResponse {
|
||||||
|
|||||||
@ -3767,7 +3767,7 @@ public class MainWindow extends JFrame {
|
|||||||
final FileOperations.ErrorResponse[] result = new FileOperations.ErrorResponse[1];
|
final FileOperations.ErrorResponse[] result = new FileOperations.ErrorResponse[1];
|
||||||
try {
|
try {
|
||||||
SwingUtilities.invokeAndWait(() -> {
|
SwingUtilities.invokeAndWait(() -> {
|
||||||
Object[] options = {"Skip", "Retry", "Abort"};
|
Object[] options = {"Skip", "Skip All", "Retry", "Abort"};
|
||||||
int n = JOptionPane.showOptionDialog(progressDialog,
|
int n = JOptionPane.showOptionDialog(progressDialog,
|
||||||
"Error operating on file: " + file.getName() + "\n" + e.getMessage(),
|
"Error operating on file: " + file.getName() + "\n" + e.getMessage(),
|
||||||
"Error",
|
"Error",
|
||||||
@ -3779,7 +3779,8 @@ public class MainWindow extends JFrame {
|
|||||||
|
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case 0: result[0] = FileOperations.ErrorResponse.SKIP; break;
|
case 0: result[0] = FileOperations.ErrorResponse.SKIP; break;
|
||||||
case 1: result[0] = FileOperations.ErrorResponse.RETRY; break;
|
case 1: result[0] = FileOperations.ErrorResponse.SKIP_ALL; break;
|
||||||
|
case 2: result[0] = FileOperations.ErrorResponse.RETRY; break;
|
||||||
default:
|
default:
|
||||||
result[0] = FileOperations.ErrorResponse.ABORT;
|
result[0] = FileOperations.ErrorResponse.ABORT;
|
||||||
progressDialog.cancel();
|
progressDialog.cancel();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user