From e6b27ba462f378dd5c18c7c00fc5d07c63b2a742 Mon Sep 17 00:00:00 2001 From: Robert Goldmann <deadlocker@gmx.de> Date: Sun, 8 Mar 2020 13:11:42 +0100 Subject: [PATCH] #455 - rotating backups --- .../database/DatabaseService.java | 70 +++++++++++++++++-- src/main/resources/languages/_de.properties | 2 +- src/main/resources/languages/_en.properties | 2 +- 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseService.java b/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseService.java index 81e106291..a130efc5f 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseService.java +++ b/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseService.java @@ -9,6 +9,7 @@ import de.deadlocker8.budgetmaster.accounts.AccountService; import de.deadlocker8.budgetmaster.categories.Category; import de.deadlocker8.budgetmaster.categories.CategoryService; import de.deadlocker8.budgetmaster.repeating.RepeatingOption; +import de.deadlocker8.budgetmaster.settings.SettingsService; import de.deadlocker8.budgetmaster.tags.TagService; import de.deadlocker8.budgetmaster.transactions.Transaction; import de.deadlocker8.budgetmaster.transactions.TransactionService; @@ -23,9 +24,13 @@ import org.springframework.stereotype.Service; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; @Service public class DatabaseService @@ -41,14 +46,17 @@ public class DatabaseService private CategoryService categoryService; private TransactionService transactionService; private TagService tagService; + private SettingsService settingsService; + @Autowired - public DatabaseService(AccountService accountService, CategoryService categoryService, TransactionService transactionService, TagService tagService) + public DatabaseService(AccountService accountService, CategoryService categoryService, TransactionService transactionService, TagService tagService, SettingsService settingsService) { this.accountService = accountService; this.categoryService = categoryService; this.transactionService = transactionService; this.tagService = tagService; + this.settingsService = settingsService; } public void reset() @@ -91,20 +99,74 @@ public class DatabaseService LOGGER.info("All tags reset."); } + private void rotatingBackup(Path backupFolderPath) + { + final Integer numberOfFilesToKeep = settingsService.getSettings().getAutoBackupFilesToKeep(); + if(numberOfFilesToKeep == 0) + { + LOGGER.debug("Skipping backup rotation since number of files to keep is set to unlimited"); + return; + } + + final List<String> existingBackups = getExistingBackups(backupFolderPath); + if(existingBackups.size() < numberOfFilesToKeep) + { + LOGGER.debug("Skipping backup rotation (existing backups: " + existingBackups.size() + ", files to keep: " + numberOfFilesToKeep + ")"); + return; + } + + LOGGER.debug("Removing old backups (existing backups: " + existingBackups.size() + ", files to keep: " + numberOfFilesToKeep + ")"); + // reserve 1 file for the backup created afterwards + final int allowedNumberOfFiles = existingBackups.size() - numberOfFilesToKeep + 1; + for(int i = 0; i < allowedNumberOfFiles; i++) + { + final Path oldBackup = Paths.get(existingBackups.get(i)); + LOGGER.debug("Deleting old backup: " + oldBackup.toString()); + try + { + Files.deleteIfExists(oldBackup); + } + catch(IOException e) + { + e.printStackTrace(); + } + } + } + + private List<String> getExistingBackups(Path backupFolderPath) + { + try(Stream<Path> walk = Files.walk(backupFolderPath)) + { + return walk.filter(Files::isRegularFile) + .map(Path::toString) + .filter(path -> path.endsWith(".json")) + .sorted() + .collect(Collectors.toList()); + } + catch(IOException e) + { + e.printStackTrace(); + } + + return new ArrayList<>(); + } + public void backupDatabase(Path backupFolderPath) { - LOGGER.debug("Backup database..."); + LOGGER.info("Backup database..."); PathUtils.createDirectoriesIfNotExists(backupFolderPath); + rotatingBackup(backupFolderPath); + final Database databaseForJsonSerialization = getDatabaseForJsonSerialization(); final String fileName = "BudgetMasterDatabase_" + DateTime.now().toString("yyyy_MM_dd_HH_mm_ss") + ".json"; final String backupPath = backupFolderPath.resolve(fileName).toString(); try(Writer writer = new FileWriter(backupPath)) { - LOGGER.debug("Backup database to: " + backupPath); + LOGGER.info("Backup database to: " + backupPath); DatabaseService.GSON.toJson(databaseForJsonSerialization, writer); - LOGGER.debug("Backup database DONE"); + LOGGER.info("Backup database DONE"); } catch(IOException e) { diff --git a/src/main/resources/languages/_de.properties b/src/main/resources/languages/_de.properties index ec30d6ac0..779be78e6 100644 --- a/src/main/resources/languages/_de.properties +++ b/src/main/resources/languages/_de.properties @@ -178,7 +178,7 @@ settings.backup.auto.deactivated=Aus settings.backup.auto.activated=An settings.backup.auto.days=Intervall in Tagen settings.backup.auto.time=Uhrzeit -settings.backup.auto.files.to.keep=Anzahl aufzubewahrender Backups +settings.backup.auto.files.to.keep=Anzahl aufzubewahrender Backups (0 f�r unbegrenzt) settings.database.import=Importieren settings.database.export=Exportieren diff --git a/src/main/resources/languages/_en.properties b/src/main/resources/languages/_en.properties index fd7f42ff0..ce75833d2 100644 --- a/src/main/resources/languages/_en.properties +++ b/src/main/resources/languages/_en.properties @@ -178,7 +178,7 @@ settings.backup.auto.deactivated=Off settings.backup.auto.activated=On settings.backup.auto.days=Interval in days settings.backup.auto.time=Time of day -settings.backup.auto.files.to.keep=Number of backups to keep +settings.backup.auto.files.to.keep=Number of backups to keep (0 for unlimited) settings.database.import=Import settings.database.export=Export -- GitLab