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,15 +182,18 @@ 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());
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
if (file.isDirectory()) {
|
if (file.isDirectory()) {
|
||||||
copyDirectory(file, targetFile, totalItems, currentItem, callback, globalResponse);
|
copyDirectory(file, targetFile, totalItems, currentItem, callback, globalResponse, globalErrorResponse);
|
||||||
} else {
|
} else {
|
||||||
if (targetFile.exists()) {
|
if (targetFile.exists()) {
|
||||||
if (globalResponse[0] == OverwriteResponse.NO_TO_ALL) {
|
if (globalResponse[0] == OverwriteResponse.NO_TO_ALL) {
|
||||||
currentItem[0] += countItems(file);
|
currentItem[0] += countItems(file);
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
if (globalResponse[0] != OverwriteResponse.YES_TO_ALL) {
|
if (globalResponse[0] != OverwriteResponse.YES_TO_ALL) {
|
||||||
OverwriteResponse res = callback.confirmOverwrite(file, targetFile);
|
OverwriteResponse res = callback.confirmOverwrite(file, targetFile);
|
||||||
@ -195,17 +201,34 @@ public class FileOperations {
|
|||||||
if (res == OverwriteResponse.NO_TO_ALL) {
|
if (res == OverwriteResponse.NO_TO_ALL) {
|
||||||
globalResponse[0] = OverwriteResponse.NO_TO_ALL;
|
globalResponse[0] = OverwriteResponse.NO_TO_ALL;
|
||||||
currentItem[0] += countItems(file);
|
currentItem[0] += countItems(file);
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
if (res == OverwriteResponse.NO) {
|
if (res == OverwriteResponse.NO) {
|
||||||
currentItem[0] += countItems(file);
|
currentItem[0] += countItems(file);
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
if (res == OverwriteResponse.YES_TO_ALL) globalResponse[0] = OverwriteResponse.YES_TO_ALL;
|
if (res == OverwriteResponse.YES_TO_ALL)
|
||||||
|
globalResponse[0] = OverwriteResponse.YES_TO_ALL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
copyFileWithProgress(file, targetFile, totalItems, currentItem, callback);
|
copyFileWithProgress(file, targetFile, totalItems, currentItem, callback);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (callback != null) {
|
||||||
|
ErrorResponse res = callback.onError(file, e);
|
||||||
|
if (res == ErrorResponse.ABORT) throw e;
|
||||||
|
if (res == ErrorResponse.RETRY) continue;
|
||||||
|
if (res == ErrorResponse.SKIP_ALL) globalErrorResponse[0] = ErrorResponse.SKIP_ALL;
|
||||||
|
// SKIP: Break while(true) to continue with next file in for loop
|
||||||
|
// we don't increment currentItem here because it's hard to know
|
||||||
|
// what exactly was processed inside copyDirectory if it failed midway.
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
target.setLastModified(source.lastModified());
|
target.setLastModified(source.lastModified());
|
||||||
@ -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,12 +408,16 @@ 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 (callback != null && callback.isCancelled()) break;
|
||||||
|
if (globalErrorResponse[0] == ErrorResponse.SKIP_ALL) break;
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
if (child.isDirectory()) {
|
if (child.isDirectory()) {
|
||||||
deleteDirectoryRecursive(child, totalItems, currentItem, callback);
|
deleteDirectoryRecursive(child, totalItems, currentItem, callback, globalErrorResponse);
|
||||||
} else {
|
} else {
|
||||||
currentItem[0]++;
|
currentItem[0]++;
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
@ -392,6 +425,20 @@ public class FileOperations {
|
|||||||
}
|
}
|
||||||
deleteFileWithForce(child);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentItem[0]++;
|
currentItem[0]++;
|
||||||
@ -490,10 +537,24 @@ 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;
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
FtpService.deleteOnFtp(item.getFtpProfile(), item.getFtpPath());
|
FtpService.deleteOnFtp(item.getFtpProfile(), item.getFtpPath());
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback.onFileProgress(item.getSize(), item.getSize());
|
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,6 +565,8 @@ public class FileOperations {
|
|||||||
for (FileItem item : items) {
|
for (FileItem item : items) {
|
||||||
if (callback != null && callback.isCancelled()) break;
|
if (callback != null && callback.isCancelled()) break;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
if (item.isDirectory()) {
|
if (item.isDirectory()) {
|
||||||
if (item.isFtp()) {
|
if (item.isFtp()) {
|
||||||
File tempDir = java.nio.file.Files.createTempDirectory("kf-ftp-copy").toFile();
|
File tempDir = java.nio.file.Files.createTempDirectory("kf-ftp-copy").toFile();
|
||||||
@ -523,6 +586,18 @@ public class FileOperations {
|
|||||||
FtpService.uploadFile(profile, item.getFile(), remotePath + "/" + item.getName(), callback);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,6 +619,8 @@ public class FileOperations {
|
|||||||
for (FileItem item : ftpItems) {
|
for (FileItem item : ftpItems) {
|
||||||
if (callback != null && callback.isCancelled()) break;
|
if (callback != null && callback.isCancelled()) break;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback.onProgress(currentItem[0], totalItems, item.getName());
|
callback.onProgress(currentItem[0], totalItems, item.getName());
|
||||||
}
|
}
|
||||||
@ -560,6 +637,18 @@ public class FileOperations {
|
|||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback.onProgress(currentItem[0], totalItems, item.getName());
|
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