X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fio%2FBackupFiles.java;fp=src%2Fjalview%2Fio%2FBackupFiles.java;h=e943b23b88dd6254a786feafd5e7dbe0d0848aaf;hb=1f14c76854a077304c32c7bf3647a847469a36c6;hp=0150579042c7f406669e08d022c4cd389d79f15e;hpb=d5cd3ea16b732d2477df4209edc54333d1a369c0;p=jalview.git diff --git a/src/jalview/io/BackupFiles.java b/src/jalview/io/BackupFiles.java index 0150579..e943b23 100644 --- a/src/jalview/io/BackupFiles.java +++ b/src/jalview/io/BackupFiles.java @@ -20,19 +20,24 @@ */ package jalview.io; -import jalview.bin.Cache; -import jalview.gui.Desktop; -import jalview.gui.JvOptionPane; -import jalview.util.MessageManager; - import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; +import jalview.bin.Cache; +import jalview.gui.Desktop; +import jalview.gui.JvOptionPane; +import jalview.util.MessageManager; +import jalview.util.Platform; + /* * BackupFiles used for manipulating (naming rolling/deleting) backup/version files when an alignment or project file is saved. * User configurable options are: @@ -95,6 +100,10 @@ public class BackupFiles private static final SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss"); + private static final String newTempFileSuffix = "_newfile"; + + private static final String oldTempFileSuffix = "_oldfile_tobedeleted"; + public BackupFiles(String filename) { this(new File(filename)); @@ -106,7 +115,8 @@ public class BackupFiles { classInit(); this.file = file; - BackupFilesPresetEntry bfpe = BackupFilesPresetEntry.getSavedBackupEntry(); + BackupFilesPresetEntry bfpe = BackupFilesPresetEntry + .getSavedBackupEntry(); this.suffix = bfpe.suffix; this.noMax = bfpe.keepAll; this.max = bfpe.rollMax; @@ -121,30 +131,47 @@ public class BackupFiles { String tempfilename = file.getName(); File tempdir = file.getParentFile(); - temp = File.createTempFile(tempfilename, TEMP_FILE_EXT + "_newfile", - tempdir); + Cache.log.debug( + "BACKUPFILES [file!=null] attempting to create temp file for " + + tempfilename + " in dir " + tempdir); + temp = File.createTempFile(tempfilename, + TEMP_FILE_EXT + newTempFileSuffix, tempdir); + Cache.log.debug( + "BACKUPFILES using temp file " + temp.getAbsolutePath()); } else { + Cache.log.debug( + "BACKUPFILES [file==null] attempting to create default temp file " + + DEFAULT_TEMP_FILE + " with extension " + + TEMP_FILE_EXT); temp = File.createTempFile(DEFAULT_TEMP_FILE, TEMP_FILE_EXT); } } catch (IOException e) { - System.out.println( - "Could not create temp file to save into (IOException)"); + Cache.log + .error("Could not create temp file to save to (IOException)"); + Cache.log.error(e.getMessage()); + Cache.log.debug(Cache.getStackTraceString(e)); } catch (Exception e) { - System.out.println("Exception ctreating temp file for saving"); + Cache.log.error("Exception ctreating temp file for saving"); + Cache.log.debug(Cache.getStackTraceString(e)); } this.setTempFile(temp); } public static void classInit() { - setEnabled(Cache.getDefault(ENABLED, true)); + Cache.log.debug("BACKUPFILES classInit"); + boolean e = Cache.getDefault(ENABLED, true); + setEnabled(e); + Cache.log.debug("BACKUPFILES " + (e ? "enabled" : "disabled")); BackupFilesPresetEntry bfpe = BackupFilesPresetEntry .getSavedBackupEntry(); + Cache.log.debug("BACKUPFILES preset scheme " + bfpe.toString()); setConfirmDelete(bfpe.confirmDelete); + Cache.log.debug("BACKUPFILES confirm delete " + bfpe.confirmDelete); } public static void setEnabled(boolean flag) @@ -188,9 +215,10 @@ public class BackupFiles path = this.getTempFile().getCanonicalPath(); } catch (IOException e) { - System.out.println( + Cache.log.error( "IOException when getting Canonical Path of temp file '" + this.getTempFile().getName() + "'"); + Cache.log.debug(Cache.getStackTraceString(e)); } return path; } @@ -209,7 +237,7 @@ public class BackupFiles public boolean renameTempFile() { - return tempFile.renameTo(file); + return moveFileToFile(tempFile, file); } // roll the backupfiles @@ -226,24 +254,35 @@ public class BackupFiles || suffix.length() == 0) { // nothing to do + Cache.log.debug("BACKUPFILES rollBackupFiles nothing to do." + ", " + + "filename: " + (file != null ? file.getName() : "null") + + ", " + "file exists: " + file.exists() + ", " + "enabled: " + + enabled + ", " + "max: " + max + ", " + "suffix: '" + suffix + + "'"); return true; } + Cache.log.debug("BACKUPFILES rollBackupFiles starting"); + String dir = ""; File dirFile; try { dirFile = file.getParentFile(); dir = dirFile.getCanonicalPath(); + Cache.log.debug("BACKUPFILES dir: " + dir); } catch (Exception e) { - System.out.println( + Cache.log.error( "Could not get canonical path for file '" + file + "'"); + Cache.log.error(e.getMessage()); + Cache.log.debug(Cache.getStackTraceString(e)); return false; } String filename = file.getName(); String basename = filename; + Cache.log.debug("BACKUPFILES filename is " + filename); boolean ret = true; // Create/move backups up one @@ -255,9 +294,13 @@ public class BackupFiles File[] backupFiles = dirFile.listFiles(bff); int nextIndexNum = 0; + Cache.log + .debug("BACKUPFILES backupFiles.length: " + backupFiles.length); if (backupFiles.length == 0) { // No other backup files. Just need to move existing file to backupfile_1 + Cache.log.debug( + "BACKUPFILES no existing backup files, setting index to 1"); nextIndexNum = 1; } else @@ -270,7 +313,7 @@ public class BackupFiles if (reverseOrder) { // backup style numbering - + Cache.log.debug("BACKUPFILES rolling files in reverse order"); int tempMax = noMax ? -1 : max; // noMax == true means no limits @@ -287,7 +330,7 @@ public class BackupFiles tempMax = i; } } - + File previousFile = null; File fileToBeDeleted = null; for (int n = tempMax; n > 0; n--) @@ -302,6 +345,7 @@ public class BackupFiles // no "oldest" file to delete previousFile = backupfile_n; fileToBeDeleted = null; + Cache.log.debug("BACKUPFILES No oldest file to delete"); continue; } @@ -312,19 +356,23 @@ public class BackupFiles File replacementFile = backupfile_n; long fileToBeDeletedLMT = fileToBeDeleted.lastModified(); long replacementFileLMT = replacementFile.lastModified(); + Cache.log.debug("BACKUPFILES fileToBeDeleted is " + + fileToBeDeleted.getAbsolutePath()); + Cache.log.debug("BACKUPFILES replacementFile is " + + backupfile_n.getAbsolutePath()); try { File oldestTempFile = nextTempFile(fileToBeDeleted.getName(), dirFile); - + if (fileToBeDeletedLMT > replacementFileLMT) { String fileToBeDeletedLMTString = sdf .format(fileToBeDeletedLMT); String replacementFileLMTString = sdf .format(replacementFileLMT); - System.out.println("WARNING! I am set to delete backupfile " + Cache.log.warn("WARNING! I am set to delete backupfile " + fileToBeDeleted.getName() + " has modification time " + fileToBeDeletedLMTString @@ -335,6 +383,11 @@ public class BackupFiles boolean delete = confirmNewerDeleteFile(fileToBeDeleted, replacementFile, true); + Cache.log.debug("BACKUPFILES " + + (delete ? "confirmed" : "not") + " deleting file " + + fileToBeDeleted.getAbsolutePath() + + " which is newer than " + + replacementFile.getAbsolutePath()); if (delete) { @@ -343,21 +396,27 @@ public class BackupFiles } else { - fileToBeDeleted.renameTo(oldestTempFile); + Cache.log.debug("BACKUPFILES moving " + + fileToBeDeleted.getAbsolutePath() + " to " + + oldestTempFile.getAbsolutePath()); + moveFileToFile(fileToBeDeleted, oldestTempFile); } } else { - fileToBeDeleted.renameTo(oldestTempFile); + Cache.log.debug("BACKUPFILES going to move " + + fileToBeDeleted.getAbsolutePath() + " to " + + oldestTempFile.getAbsolutePath()); + moveFileToFile(fileToBeDeleted, oldestTempFile); addDeleteFile(oldestTempFile); } } catch (Exception e) { - System.out.println( + Cache.log.error( "Error occurred, probably making new temp file for '" + fileToBeDeleted.getName() + "'"); - e.printStackTrace(); + Cache.log.error(Cache.getStackTraceString(e)); } // reset @@ -372,7 +431,9 @@ public class BackupFiles { if (previousFile != null) { - ret = ret && backupfile_n.renameTo(previousFile); + // using boolean '&' instead of '&&' as don't want moveFileToFile + // attempt to be conditional (short-circuit) + ret = ret & moveFileToFile(backupfile_n, previousFile); } } @@ -382,19 +443,37 @@ public class BackupFiles // index to use for the latest backup nextIndexNum = 1; } - else + else // not reverse numbering { // version style numbering (with earliest file deletion if max files // reached) bfTreeMap.values().toArray(backupFiles); + StringBuilder bfsb = new StringBuilder(); + for (int i = 0; i < backupFiles.length; i++) + { + if (bfsb.length() > 0) + { + bfsb.append(", "); + } + bfsb.append(backupFiles[i].getName()); + } + Cache.log.debug("BACKUPFILES backupFiles: " + bfsb.toString()); // noMax == true means keep all backup files if ((!noMax) && bfTreeMap.size() >= max) { + Cache.log.debug("BACKUPFILES noMax: " + noMax + ", " + "max: " + + max + ", " + "bfTreeMap.size(): " + bfTreeMap.size()); // need to delete some files to keep number of backups to designated - // max - int numToDelete = bfTreeMap.size() - max + 1; + // max. + // Note that if the suffix is not numbered then do not delete any + // backup files later or we'll delete the new backup file (there can + // be only one). + int numToDelete = suffix.indexOf(NUM_PLACEHOLDER) > -1 + ? bfTreeMap.size() - max + 1 + : 0; + Cache.log.debug("BACKUPFILES numToDelete: " + numToDelete); // the "replacement" file is the latest backup file being kept (it's // not replacing though) File replacementFile = numToDelete < backupFiles.length @@ -407,6 +486,9 @@ public class BackupFiles File fileToBeDeleted = backupFiles[i]; boolean delete = true; + Cache.log.debug( + "BACKUPFILES fileToBeDeleted: " + fileToBeDeleted); + boolean newer = false; if (replacementFile != null) { @@ -421,14 +503,13 @@ public class BackupFiles String replacementFileLMTString = sdf .format(replacementFileLMT); - System.out - .println("WARNING! I am set to delete backupfile '" - + fileToBeDeleted.getName() - + "' has modification time " + Cache.log.warn("WARNING! I am set to delete backupfile '" + + fileToBeDeleted.getName() + + "' has modification time " + fileToBeDeletedLMTString - + " which is newer than the oldest backupfile being kept '" + + " which is newer than the oldest backupfile being kept '" + replacementFile.getName() - + "' with modification time " + + "' with modification time " + replacementFileLMTString); delete = confirmNewerDeleteFile(fileToBeDeleted, @@ -437,17 +518,23 @@ public class BackupFiles { // User has confirmed delete -- no need to add it to the list fileToBeDeleted.delete(); + Cache.log.debug("BACKUPFILES deleting fileToBeDeleted: " + + fileToBeDeleted); delete = false; } else { // keeping file, nothing to do! + Cache.log.debug("BACKUPFILES keeping fileToBeDeleted: " + + fileToBeDeleted); } } } if (delete) { addDeleteFile(fileToBeDeleted); + Cache.log.debug("BACKUPFILES addDeleteFile(fileToBeDeleted): " + + fileToBeDeleted); } } @@ -462,10 +549,17 @@ public class BackupFiles String latestBackupFilename = dir + File.separatorChar + BackupFilenameParts.getBackupFilename(nextIndexNum, basename, suffix, digits); - ret |= file.renameTo(new File(latestBackupFilename)); - + Cache.log.debug("BACKUPFILES Moving old file [" + file + + "] to latestBackupFilename [" + latestBackupFilename + "]"); + // using boolean '&' instead of '&&' as don't want moveFileToFile attempt to + // be conditional (short-circuit) + ret = ret & moveFileToFile(file, new File(latestBackupFilename)); + Cache.log.debug( + "BACKUPFILES moving " + file + " to " + latestBackupFilename + + " was " + (ret ? "" : "NOT ") + "successful"); if (tidyUp) { + Cache.log.debug("BACKUPFILES tidying up files"); tidyUpFiles(); } @@ -521,7 +615,7 @@ public class BackupFiles saveFile = nextTempFile(ftbd.getName(), ftbd.getParentFile()); } catch (Exception e) { - System.out.println( + Cache.log.error( "Error when confirming to keep backup file newer than other backup files."); e.printStackTrace(); } @@ -529,19 +623,27 @@ public class BackupFiles "label.newerdelete_replacement_line", new String[] { ftbd.getName(), rf.getName(), ftbdLMT, rfLMT, ftbdSize, rfSize })); + // "Backup file\n''{0}''\t(modified {2}, size {4})\nis to be deleted and + // replaced by apparently older file \n''{1}''\t(modified {3}, size + // {5})."" messageSB.append("\n\n"); messageSB.append(MessageManager.formatMessage( "label.confirm_deletion_or_rename", new String[] { ftbd.getName(), saveFile.getName() })); + // "Confirm deletion of ''{0}'' or rename to ''{1}''?" String[] options = new String[] { MessageManager.getString("label.delete"), MessageManager.getString("label.rename") }; - confirmButton = JvOptionPane.showOptionDialog(Desktop.desktop, - messageSB.toString(), - MessageManager.getString("label.backupfiles_confirm_delete"), - JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE, - null, options, options[0]); + confirmButton = Platform.isHeadless() ? JvOptionPane.YES_OPTION + : JvOptionPane.showOptionDialog(Desktop.desktop, + messageSB.toString(), + MessageManager.getString( + "label.backupfiles_confirm_delete"), + // "Confirm delete" + JvOptionPane.YES_NO_OPTION, + JvOptionPane.WARNING_MESSAGE, null, options, + options[0]); } else { @@ -549,22 +651,29 @@ public class BackupFiles .formatMessage("label.newerdelete_line", new String[] { ftbd.getName(), rf.getName(), ftbdLMT, rfLMT, ftbdSize, rfSize })); + // "Backup file\n''{0}''\t(modified {2}, size {4})\nis to be deleted but + // is newer than the oldest remaining backup file \n''{1}''\t(modified + // {3}, size {5})." messageSB.append("\n\n"); messageSB.append(MessageManager .formatMessage("label.confirm_deletion", new String[] { ftbd.getName() })); + // "Confirm deletion of ''{0}''?" String[] options = new String[] { MessageManager.getString("label.delete"), MessageManager.getString("label.keep") }; - confirmButton = JvOptionPane.showOptionDialog(Desktop.desktop, - messageSB.toString(), - MessageManager.getString("label.backupfiles_confirm_delete"), - JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE, - null, options, options[0]); + confirmButton = Platform.isHeadless() ? JvOptionPane.YES_OPTION + : JvOptionPane.showOptionDialog(Desktop.desktop, + messageSB.toString(), + MessageManager.getString( + "label.backupfiles_confirm_delete"), + // "Confirm delete" + JvOptionPane.YES_NO_OPTION, + JvOptionPane.WARNING_MESSAGE, null, options, + options[0]); } - // return should be TRUE if file is to be deleted return (confirmButton == JvOptionPane.YES_OPTION); } @@ -580,6 +689,8 @@ public class BackupFiles messageSB = new StringBuilder(); messageSB.append(MessageManager .getString("label.backupfiles_confirm_delete_old_files")); + // "Delete the following older backup files? (see the Backups tab in + // Preferences for more options)" for (int i = 0; i < deleteFiles.size(); i++) { File df = deleteFiles.get(i); @@ -590,13 +701,17 @@ public class BackupFiles new String[] { sdf.format(df.lastModified()), Long.toString(df.length()) })); + // "(modified {0}, size {1})" } - int confirmButton = JvOptionPane.showConfirmDialog(Desktop.desktop, - messageSB.toString(), - MessageManager - .getString("label.backupfiles_confirm_delete"), - JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE); + int confirmButton = Platform.isHeadless() ? JvOptionPane.YES_OPTION + : JvOptionPane.showConfirmDialog(Desktop.desktop, + messageSB.toString(), + MessageManager.getString( + "label.backupfiles_confirm_delete"), + // "Confirm delete" + JvOptionPane.YES_NO_OPTION, + JvOptionPane.WARNING_MESSAGE); doDelete = (confirmButton == JvOptionPane.YES_OPTION); } @@ -610,8 +725,10 @@ public class BackupFiles for (int i = 0; i < deleteFiles.size(); i++) { File fileToDelete = deleteFiles.get(i); + Cache.log.debug( + "BACKUPFILES deleting fileToDelete:" + fileToDelete); fileToDelete.delete(); - System.out.println("DELETING '" + fileToDelete.getName() + "'"); + Cache.log.warn("deleting '" + fileToDelete.getName() + "'"); } } @@ -621,8 +738,7 @@ public class BackupFiles } private TreeMap sortBackupFilesAsTreeMap( - File[] backupFiles, - String basename) + File[] backupFiles, String basename) { // sort the backup files (based on integer found in the suffix) using a // precomputed Hashmap for speed @@ -647,7 +763,7 @@ public class BackupFiles boolean rename = false; if (write) { - roll = this.rollBackupFiles(false); + roll = this.rollBackupFiles(false); // tidyUpFiles at the end rename = this.renameTempFile(); } @@ -661,7 +777,9 @@ public class BackupFiles if (!okay) { StringBuilder messageSB = new StringBuilder(); - messageSB.append(MessageManager.getString( "label.backupfiles_confirm_save_file_backupfiles_roll_wrong")); + messageSB.append(MessageManager.getString( + "label.backupfiles_confirm_save_file_backupfiles_roll_wrong")); + // "Something possibly went wrong with the backups of this file." if (rename) { if (messageSB.length() > 0) @@ -670,6 +788,7 @@ public class BackupFiles } messageSB.append(MessageManager.getString( "label.backupfiles_confirm_save_new_saved_file_ok")); + // "The new saved file seems okay." } else { @@ -679,13 +798,22 @@ public class BackupFiles } messageSB.append(MessageManager.getString( "label.backupfiles_confirm_save_new_saved_file_not_ok")); + // "The new saved file might not be okay." } - - int confirmButton = JvOptionPane.showConfirmDialog(Desktop.desktop, - messageSB.toString(), - MessageManager - .getString("label.backupfiles_confirm_save_file"), - JvOptionPane.OK_OPTION, JvOptionPane.WARNING_MESSAGE); + if (messageSB.length() > 0) + { + messageSB.append("\n"); + } + messageSB + .append(MessageManager.getString("label.continue_operation")); + + int confirmButton = Platform.isHeadless() ? JvOptionPane.OK_OPTION + : JvOptionPane.showConfirmDialog(Desktop.desktop, + messageSB.toString(), + MessageManager.getString( + "label.backupfiles_confirm_save_file"), + // "Confirm save file" + JvOptionPane.OK_OPTION, JvOptionPane.WARNING_MESSAGE); okay = confirmButton == JvOptionPane.OK_OPTION; } if (okay) @@ -709,7 +837,7 @@ public class BackupFiles dirFile = file.getParentFile(); } catch (Exception e) { - System.out.println( + Cache.log.error( "Could not get canonical path for file '" + file + "'"); return new TreeMap<>(); } @@ -751,13 +879,48 @@ public class BackupFiles int pos = deleteFiles.indexOf(fileToBeDeleted); if (pos > -1) { + Cache.log.debug("BACKUPFILES not adding file " + + fileToBeDeleted.getAbsolutePath() + + " to the delete list (already at index" + pos + ")"); return true; } else { + Cache.log.debug("BACKUPFILES adding file " + + fileToBeDeleted.getAbsolutePath() + " to the delete list"); deleteFiles.add(fileToBeDeleted); } return ret; } + public static boolean moveFileToFile(File oldFile, File newFile) + { + boolean ret = false; + Path oldPath = Paths.get(oldFile.getAbsolutePath()); + Path newPath = Paths.get(newFile.getAbsolutePath()); + try + { + // delete destination file - not usually necessary but Just In Case... + Cache.log.debug("BACKUPFILES deleting " + newFile.getAbsolutePath()); + newFile.delete(); + Cache.log.debug("BACKUPFILES moving " + oldFile.getAbsolutePath() + + " to " + newFile.getAbsolutePath()); + Files.move(oldPath, newPath, StandardCopyOption.REPLACE_EXISTING); + ret = true; + Cache.log.debug("BACKUPFILES move seems to have succeeded"); + } catch (IOException e) + { + Cache.log.warn("Could not move file '" + oldPath.toString() + "' to '" + + newPath.toString() + "'"); + Cache.log.error(e.getMessage()); + Cache.log.debug(Cache.getStackTraceString(e)); + ret = false; + } catch (Exception e) + { + Cache.log.error(e.getMessage()); + Cache.log.debug(Cache.getStackTraceString(e)); + ret = false; + } + return ret; + } }