summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/keuin/kbackupfabric/KBCommands.java149
-rw-r--r--src/main/java/com/keuin/kbackupfabric/KBCommandsRegister.java26
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/BackupOperation.java19
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/DeleteOperation.java20
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java30
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/backup/BackupMethod.java26
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/backup/IncrementalBackupMethod.java62
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/backup/IncrementalBackupUtil.java90
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/backup/PrimitiveBackupMethod.java45
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/backup/feedback/BackupFeedback.java5
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/backup/feedback/PrimitiveBackupFeedback.java29
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/BackupFilesystemUtil.java27
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/BackupType.java33
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/builder/BackupFileNameBuilder.java24
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/builder/ObjectTreeBackupFileNameBuilder.java20
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/builder/PrimitiveZipBackupFileNameBuilder.java22
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/formatter/BackupFileNameFormatter.java31
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/formatter/ObjectTreeBackupFileNameFormatter.java44
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/formatter/PrimitiveZipBackupFileNameFormatter.java43
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionFactory.java6
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionSerializer.java3
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/FileIdentifierProvider.java (renamed from src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/FileIdentifierFactory.java)2
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/Sha256Identifier.java4
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/name/BackupFileNameEncoder.java49
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/name/PrimitiveBackupFileNameEncoder.java34
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/suggestion/BackupMethodSuggestionProvider.java36
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/suggestion/BackupNameSuggestionProvider.java3
-rw-r--r--src/test/java/IncrementalBackupUtilTest.java16
-rw-r--r--src/test/java/com/keuin/kbackupfabric/util/backup/name/PrimitiveBackupFileNameEncoderTest.java21
29 files changed, 303 insertions, 616 deletions
diff --git a/src/main/java/com/keuin/kbackupfabric/KBCommands.java b/src/main/java/com/keuin/kbackupfabric/KBCommands.java
index 571333f..ef4a401 100644
--- a/src/main/java/com/keuin/kbackupfabric/KBCommands.java
+++ b/src/main/java/com/keuin/kbackupfabric/KBCommands.java
@@ -5,13 +5,9 @@ import com.keuin.kbackupfabric.operation.BackupOperation;
import com.keuin.kbackupfabric.operation.DeleteOperation;
import com.keuin.kbackupfabric.operation.RestoreOperation;
import com.keuin.kbackupfabric.operation.abstracts.i.Invokable;
-import com.keuin.kbackupfabric.operation.backup.BackupMethod;
-import com.keuin.kbackupfabric.operation.backup.IncrementalBackupMethod;
import com.keuin.kbackupfabric.operation.backup.PrimitiveBackupMethod;
import com.keuin.kbackupfabric.util.PrintUtil;
import com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil;
-import com.keuin.kbackupfabric.util.backup.BackupNameTimeFormatter;
-import com.keuin.kbackupfabric.util.backup.BackupType;
import com.keuin.kbackupfabric.util.backup.suggestion.BackupNameSuggestionProvider;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.context.CommandContext;
@@ -33,10 +29,11 @@ public final class KBCommands {
private static final int SUCCESS = 1;
private static final int FAILED = -1;
private static final String DEFAULT_BACKUP_NAME = "noname";
+ private static boolean notifiedPreviousRestoration = false;
//private static final Logger LOGGER = LogManager.getLogger();
- private static final List<String> backupNameList = new ArrayList<>(); // index -> backupName
+ private static final List<String> backupFileNameList = new ArrayList<>(); // index -> backupName
private static Invokable pendingOperation = null;
//private static BackupMethod activatedBackupMethod = new PrimitiveBackupMethod(); // The backup method we currently using
@@ -65,8 +62,9 @@ public final class KBCommands {
*/
public static int kb(CommandContext<ServerCommandSource> context) {
int statCode = list(context);
- if (MetadataHolder.hasMetadata()) {
+ if (MetadataHolder.hasMetadata() && !notifiedPreviousRestoration) {
// Output metadata info
+ notifiedPreviousRestoration = true;
msgStress(context, "Restored from backup " + MetadataHolder.getMetadata().getBackupName());
}
return statCode;
@@ -84,19 +82,20 @@ public final class KBCommands {
(dir, name) -> dir.isDirectory() && name.toLowerCase().endsWith(".zip") && name.toLowerCase().startsWith(getBackupFileNamePrefix())
);
- backupNameList.clear();
+ backupFileNameList.clear();
if (files != null) {
if (files.length != 0) {
msgInfo(context, "Available backups: (file is not checked, manipulation may affect this plugin)");
} else {
- msgInfo(context, "There are no available backups. To make a new backup, check /kb backup.");
+ msgInfo(context, "There are no available backups. To make a new backup, run /kb backup.");
}
int i = 0;
for (File file : files) {
++i;
- String backupName = getBackupName(file.getName());
- backupNameList.add(backupName);
- msgInfo(context, String.format("[%d] %s, size: %.1fMB", i, backupName, file.length() * 1.0 / 1024 / 1024));
+ String backupFileName = file.getName();
+ String sizeString = getFriendlyFileSizeString(file.length());
+ msgInfo(context, String.format("[%d] %s, size: %s", i, backupFileName, sizeString));
+ backupFileNameList.add(backupFileName);
}
} else {
msgErr(context, "Error: failed to list files in backup folder.");
@@ -112,13 +111,13 @@ public final class KBCommands {
*/
public static int primitiveBackup(CommandContext<ServerCommandSource> context) {
//KBMain.backup("name")
- String backupName = StringArgumentType.getString(context, "backupName");
- if (backupName.matches("[0-9]*")) {
+ String customBackupName = StringArgumentType.getString(context, "backupName");
+ if (customBackupName.matches("[0-9]*")) {
// Numeric param is not allowed
- backupName = String.format("a%s", backupName);
- msgWarn(context, String.format("Pure numeric name is not allowed. Renaming to %s", backupName));
+ customBackupName = String.format("a%s", customBackupName);
+ msgWarn(context, String.format("Pure numeric name is not allowed. Renaming to %s", customBackupName));
}
- return doBackup(context, backupName, PrimitiveBackupMethod.getInstance());
+ return doBackup(context, customBackupName);
}
/**
@@ -128,23 +127,23 @@ public final class KBCommands {
* @return stat code.
*/
public static int primitiveBackupWithDefaultName(CommandContext<ServerCommandSource> context) {
- return doBackup(context, DEFAULT_BACKUP_NAME, PrimitiveBackupMethod.getInstance());
+ return doBackup(context, DEFAULT_BACKUP_NAME);
}
- public static int incrementalBackup(CommandContext<ServerCommandSource> context) {
- //KBMain.backup("name")
- String backupName = StringArgumentType.getString(context, "backupName");
- if (backupName.matches("[0-9]*")) {
- // Numeric param is not allowed
- backupName = String.format("a%s", backupName);
- msgWarn(context, String.format("Pure numeric name is not allowed. Renaming to %s", backupName));
- }
- return doBackup(context, backupName, IncrementalBackupMethod.getInstance());
- }
-
- public static int incrementalBackupWithDefaultName(CommandContext<ServerCommandSource> context) {
- return doBackup(context, DEFAULT_BACKUP_NAME, IncrementalBackupMethod.getInstance());
- }
+// public static int incrementalBackup(CommandContext<ServerCommandSource> context) {
+// //KBMain.backup("name")
+// String backupName = StringArgumentType.getString(context, "backupName");
+// if (backupName.matches("[0-9]*")) {
+// // Numeric param is not allowed
+// backupName = String.format("a%s", backupName);
+// msgWarn(context, String.format("Pure numeric name is not allowed. Renaming to %s", backupName));
+// }
+// return doBackup(context, backupName, IncrementalBackupMethod.getInstance());
+// }
+//
+// public static int incrementalBackupWithDefaultName(CommandContext<ServerCommandSource> context) {
+// return doBackup(context, DEFAULT_BACKUP_NAME, IncrementalBackupMethod.getInstance());
+// }
/**
* Delete an existing backup with context parameter backupName.
@@ -155,14 +154,14 @@ public final class KBCommands {
*/
public static int delete(CommandContext<ServerCommandSource> context) {
- String backupName = parseBackupName(context, StringArgumentType.getString(context, "backupName"));
+ String backupFileName = parseBackupFileName(context, StringArgumentType.getString(context, "backupName"));
MinecraftServer server = context.getSource().getMinecraftServer();
- if (backupName == null)
+ if (backupFileName == null)
return list(context); // Show the list and return
// Validate backupName
- if (!isBackupNameValid(backupName, server)) {
+ if (!isBackupFileExists(backupFileName, server)) {
// Invalid backupName
msgErr(context, "Invalid backup name! Please check your input. The list index number is also valid.");
return FAILED;
@@ -170,9 +169,9 @@ public final class KBCommands {
// Update pending task
//pendingOperation = AbstractConfirmableOperation.createDeleteOperation(context, backupName);
- pendingOperation = new DeleteOperation(context, backupName);
+ pendingOperation = new DeleteOperation(context, backupFileName);
- msgWarn(context, String.format("DELETION WARNING: The deletion is irreversible! You will lose the backup %s permanently. Use /kb confirm to start or /kb cancel to abort.", backupName), true);
+ msgWarn(context, String.format("DELETION WARNING: The deletion is irreversible! You will lose the backup %s permanently. Use /kb confirm to start or /kb cancel to abort.", backupFileName), true);
return SUCCESS;
}
@@ -187,14 +186,14 @@ public final class KBCommands {
public static int restore(CommandContext<ServerCommandSource> context) {
//KBMain.restore("name")
MinecraftServer server = context.getSource().getMinecraftServer();
- String backupName = parseBackupName(context, StringArgumentType.getString(context, "backupName"));
- backupName = parseBackupName(context, backupName);
+ String backupFileName = parseBackupFileName(context, StringArgumentType.getString(context, "backupName"));
+ backupFileName = parseBackupFileName(context, backupFileName);
- if (backupName == null)
+ if (backupFileName == null)
return list(context); // Show the list and return
// Validate backupName
- if (!isBackupNameValid(backupName, server)) {
+ if (!isBackupFileExists(backupFileName, server)) {
// Invalid backupName
msgErr(context, "Invalid backup name! Please check your input. The list index number is also valid.", false);
return FAILED;
@@ -205,22 +204,22 @@ public final class KBCommands {
// Update pending task
//pendingOperation = AbstractConfirmableOperation.createRestoreOperation(context, backupName);
- File backupFile = new File(getBackupSaveDirectory(server), getBackupFileName(backupName));
- pendingOperation = new RestoreOperation(context, backupFile.getAbsolutePath(), getLevelPath(server), backupName);
+// File backupFile = new File(getBackupSaveDirectory(server), getBackupFileName(backupName));
+ pendingOperation = new RestoreOperation(context, getBackupSaveDirectory(server).getAbsolutePath(), getLevelPath(server), backupFileName);
- msgWarn(context, String.format("RESET WARNING: You will LOSE YOUR CURRENT WORLD PERMANENTLY! The worlds will be replaced with backup %s . Use /kb confirm to start or /kb cancel to abort.", backupName), true);
+ msgWarn(context, String.format("RESET WARNING: You will LOSE YOUR CURRENT WORLD PERMANENTLY! The worlds will be replaced with backup %s . Use /kb confirm to start or /kb cancel to abort.", backupFileName), true);
return SUCCESS;
}
- private static int doBackup(CommandContext<ServerCommandSource> context, String customBackupName, BackupMethod backupMethod) {
+ private static int doBackup(CommandContext<ServerCommandSource> context, String customBackupName) {
// Real backup name (compatible with legacy backup): date_name, such as 2020-04-23_21-03-00_test
//KBMain.backup("name")
- String backupName = BackupNameTimeFormatter.getTimeString() + "_" + customBackupName;
+// String backupName = BackupNameTimeFormatter.getTimeString() + "_" + customBackupName;
// Validate file name
final char[] ILLEGAL_CHARACTERS = {'/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':'};
for (char c : ILLEGAL_CHARACTERS) {
- if (backupName.contains(String.valueOf(c))) {
+ if (customBackupName.contains(String.valueOf(c))) {
msgErr(context, String.format("Name cannot contain special character \"%c\".", c));
return FAILED;
}
@@ -229,7 +228,7 @@ public final class KBCommands {
// Do backup
PrintUtil.info("Invoking backup worker ...");
//BackupWorker.invoke(context, backupName, metadata);
- BackupOperation operation = new BackupOperation(context, backupName, backupMethod);
+ BackupOperation operation = new BackupOperation(context, customBackupName, PrimitiveBackupMethod.getInstance());
if (operation.invoke()) {
return SUCCESS;
} else if (operation.isBlocked()) {
@@ -293,15 +292,15 @@ public final class KBCommands {
files.removeIf(f -> !f.getName().startsWith(BackupFilesystemUtil.getBackupFileNamePrefix()));
files.sort((x, y) -> (int) (BackupFilesystemUtil.getBackupTimeFromBackupFileName(y.getName()) - BackupFilesystemUtil.getBackupTimeFromBackupFileName(x.getName())));
File prevBackupFile = files.get(0);
- String backupName = getBackupName(prevBackupFile.getName());
- int i = backupNameList.indexOf(backupName);
+ String backupFileName = prevBackupFile.getName();
+ int i = backupFileNameList.indexOf(backupFileName);
if (i == -1) {
- backupNameList.add(backupName);
- i = backupNameList.size();
+ backupFileNameList.add(backupFileName);
+ i = backupFileNameList.size();
} else {
++i;
}
- msgInfo(context, String.format("The most recent backup: [%d] %s , size: %s", i, backupName, getFriendlyFileSizeString(prevBackupFile.length())));
+ msgInfo(context, String.format("The most recent backup: [%d] %s , size: %s", i, backupFileName, getFriendlyFileSizeString(prevBackupFile.length())));
} catch (NullPointerException e) {
msgInfo(context, "There are no backups available.");
} catch (SecurityException ignored) {
@@ -311,35 +310,35 @@ public final class KBCommands {
return SUCCESS;
}
- /**
- * Select the backup method we use.
- * @param context the context.
- * @return stat code.
- */
- public static int setMethod(CommandContext<ServerCommandSource> context) {
- String desiredMethodName = StringArgumentType.getString(context, "backupMethod");
- List<BackupType> backupMethods = Arrays.asList(BackupType.PRIMITIVE_ZIP_BACKUP, BackupType.OBJECT_TREE_BACKUP);
- for (BackupType method : backupMethods) {
- if(method.getName().equals(desiredMethodName)) {
- // Incremental backup
-// activatedBackupMethod =
- msgInfo(context, String.format("Backup method is set to: %s", desiredMethodName));
- return SUCCESS;
- }
- }
-
- return SUCCESS;
- }
-
-
- private static String parseBackupName(CommandContext<ServerCommandSource> context, String userInput) {
+// /**
+// * Select the backup method we use.
+// * @param context the context.
+// * @return stat code.
+// */
+// public static int setMethod(CommandContext<ServerCommandSource> context) {
+// String desiredMethodName = StringArgumentType.getString(context, "backupMethod");
+// List<BackupType> backupMethods = Arrays.asList(BackupType.PRIMITIVE_ZIP_BACKUP, BackupType.OBJECT_TREE_BACKUP);
+// for (BackupType method : backupMethods) {
+// if(method.getName().equals(desiredMethodName)) {
+// // Incremental backup
+//// activatedBackupMethod =
+// msgInfo(context, String.format("Backup method is set to: %s", desiredMethodName));
+// return SUCCESS;
+// }
+// }
+//
+// return SUCCESS;
+// }
+
+
+ private static String parseBackupFileName(CommandContext<ServerCommandSource> context, String userInput) {
try {
String backupName = StringArgumentType.getString(context, "backupName");
if (backupName.matches("[0-9]*")) {
// If numeric input
int index = Integer.parseInt(backupName) - 1;
- return backupNameList.get(index); // Replace input number with real backup name.
+ return backupFileNameList.get(index); // Replace input number with real backup file name.
}
} catch (NumberFormatException | IndexOutOfBoundsException ignored) {
}
diff --git a/src/main/java/com/keuin/kbackupfabric/KBCommandsRegister.java b/src/main/java/com/keuin/kbackupfabric/KBCommandsRegister.java
index 3376ac9..4154464 100644
--- a/src/main/java/com/keuin/kbackupfabric/KBCommandsRegister.java
+++ b/src/main/java/com/keuin/kbackupfabric/KBCommandsRegister.java
@@ -1,8 +1,7 @@
package com.keuin.kbackupfabric;
-import com.keuin.kbackupfabric.util.backup.suggestion.BackupMethodSuggestionProvider;
-import com.keuin.kbackupfabric.util.backup.suggestion.BackupNameSuggestionProvider;
import com.keuin.kbackupfabric.util.PermissionValidator;
+import com.keuin.kbackupfabric.util.backup.suggestion.BackupNameSuggestionProvider;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import net.minecraft.server.command.CommandManager;
@@ -19,19 +18,12 @@ public final class KBCommandsRegister {
// register /kb list for showing the backup list. OP is required.
dispatcher.register(CommandManager.literal("kb").then(CommandManager.literal("list").requires(PermissionValidator::op).executes(KBCommands::list)));
- // register /kb backup zip [name] as a alias
- dispatcher.register(CommandManager.literal("kb").then(CommandManager.literal("backup").then(
- CommandManager.literal("zip").then(
- CommandManager.argument("backupName", StringArgumentType.greedyString()).requires(PermissionValidator::op).executes(KBCommands::primitiveBackup)
- ).requires(PermissionValidator::op).executes(KBCommands::primitiveBackupWithDefaultName)))
- );
-
- // register /kb backup incremental [name]
- dispatcher.register(CommandManager.literal("kb").then(CommandManager.literal("backup").then(
- CommandManager.literal("incremental").then(
- CommandManager.argument("backupName", StringArgumentType.greedyString()).requires(PermissionValidator::op).executes(KBCommands::incrementalBackup)
- ).requires(PermissionValidator::op).executes(KBCommands::incrementalBackupWithDefaultName)))
- );
+// // register /kb backup incremental [name]
+// dispatcher.register(CommandManager.literal("kb").then(CommandManager.literal("backup").then(
+// CommandManager.literal("incremental").then(
+// CommandManager.argument("backupName", StringArgumentType.greedyString()).requires(PermissionValidator::op).executes(KBCommands::incrementalBackup)
+// ).requires(PermissionValidator::op).executes(KBCommands::incrementalBackupWithDefaultName)))
+// );
// register /kb backup [name] for performing backup. OP is required.
dispatcher.register(CommandManager.literal("kb").then(CommandManager.literal("backup").then(
@@ -53,7 +45,7 @@ public final class KBCommandsRegister {
// register /kb prev for showing the latest backup.
dispatcher.register(CommandManager.literal("kb").then(CommandManager.literal("prev").requires(PermissionValidator::op).executes(KBCommands::prev)));
- // register /kb setMethod for selecting backup method (zip, incremental)
- dispatcher.register(CommandManager.literal("kb").then(CommandManager.literal("setMethod").then(CommandManager.argument("backupMethod", StringArgumentType.string()).suggests(BackupMethodSuggestionProvider.getProvider()).requires(PermissionValidator::op).executes(KBCommands::setMethod))));
+// // register /kb setMethod for selecting backup method (zip, incremental)
+// dispatcher.register(CommandManager.literal("kb").then(CommandManager.literal("setMethod").then(CommandManager.argument("backupMethod", StringArgumentType.string()).suggests(BackupMethodSuggestionProvider.getProvider()).requires(PermissionValidator::op).executes(KBCommands::setMethod))));
}
}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/BackupOperation.java b/src/main/java/com/keuin/kbackupfabric/operation/BackupOperation.java
index 465b293..f8736c8 100644
--- a/src/main/java/com/keuin/kbackupfabric/operation/BackupOperation.java
+++ b/src/main/java/com/keuin/kbackupfabric/operation/BackupOperation.java
@@ -2,6 +2,7 @@ package com.keuin.kbackupfabric.operation;
import com.keuin.kbackupfabric.operation.abstracts.InvokableAsyncBlockingOperation;
import com.keuin.kbackupfabric.operation.backup.BackupMethod;
+import com.keuin.kbackupfabric.operation.backup.feedback.PrimitiveBackupFeedback;
import com.keuin.kbackupfabric.util.PrintUtil;
import com.mojang.brigadier.context.CommandContext;
import net.minecraft.server.MinecraftServer;
@@ -19,16 +20,16 @@ import static com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil.*;
public class BackupOperation extends InvokableAsyncBlockingOperation {
private final CommandContext<ServerCommandSource> context;
- private final String backupName;
+ private final String customBackupName;
private final Map<World, Boolean> oldWorldsSavingDisabled = new HashMap<>();
private final BackupMethod backupMethod;
private long startTime;
- public BackupOperation(CommandContext<ServerCommandSource> context, String backupName, BackupMethod backupMethod) {
+ public BackupOperation(CommandContext<ServerCommandSource> context, String customBackupName, BackupMethod backupMethod) {
super("BackupWorker");
this.context = context;
- this.backupName = backupName;
+ this.customBackupName = customBackupName;
this.backupMethod = backupMethod;
}
@@ -49,18 +50,16 @@ public class BackupOperation extends InvokableAsyncBlockingOperation {
// Make zip
String levelPath = getLevelPath(server);
- String backupFileName = getBackupFileName(backupName);
+ String backupFileName = getBackupFileName(customBackupName);
- BackupMethod.BackupResult result = backupMethod.backup(backupName,levelPath,backupSaveDirectory);
+ PrimitiveBackupFeedback result = backupMethod.backup(customBackupName,levelPath,backupSaveDirectory);
if(result.isSuccess()) {
- // Restore old autosave switch stat
+ // Restore old auto-save switch stat
server.getWorlds().forEach(world -> world.savingDisabled = oldWorldsSavingDisabled.getOrDefault(world, true));
// Print finish message: time elapsed and file size
long timeElapsedMillis = System.currentTimeMillis() - startTime;
- String msgText = String.format("Backup finished. Time elapsed: %.2fs.", timeElapsedMillis / 1000.0);
- File backupZipFile = new File(backupSaveDirectory, backupFileName);
- msgText += String.format(" File size: %s.", getFriendlyFileSizeString(result.getBackupSizeBytes()));
+ String msgText = String.format("Backup finished. Time elapsed: %.2fs. ", timeElapsedMillis / 1000.0) + result.getFeedback();
PrintUtil.msgInfo(context, msgText, true);
} else {
// failed
@@ -77,7 +76,7 @@ public class BackupOperation extends InvokableAsyncBlockingOperation {
protected boolean sync() {
//// Save world, save old autosave configs
- PrintUtil.broadcast(String.format("Making backup %s, please wait ...", backupName));
+ PrintUtil.broadcast(String.format("Making backup %s, please wait ...", customBackupName));
// Get server
MinecraftServer server = context.getSource().getMinecraftServer();
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/DeleteOperation.java b/src/main/java/com/keuin/kbackupfabric/operation/DeleteOperation.java
index 444ca9a..3ae09f5 100644
--- a/src/main/java/com/keuin/kbackupfabric/operation/DeleteOperation.java
+++ b/src/main/java/com/keuin/kbackupfabric/operation/DeleteOperation.java
@@ -1,8 +1,8 @@
package com.keuin.kbackupfabric.operation;
import com.keuin.kbackupfabric.operation.abstracts.InvokableAsyncBlockingOperation;
-import com.keuin.kbackupfabric.util.backup.suggestion.BackupNameSuggestionProvider;
import com.keuin.kbackupfabric.util.PrintUtil;
+import com.keuin.kbackupfabric.util.backup.suggestion.BackupNameSuggestionProvider;
import com.mojang.brigadier.context.CommandContext;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.ServerCommandSource;
@@ -10,27 +10,26 @@ import net.minecraft.server.command.ServerCommandSource;
import java.io.File;
import java.io.IOException;
-import static com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil.getBackupFileName;
-import static com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil.getBackupSaveDirectory;
import static com.keuin.kbackupfabric.util.PrintUtil.msgErr;
import static com.keuin.kbackupfabric.util.PrintUtil.msgInfo;
+import static com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil.getBackupSaveDirectory;
import static org.apache.commons.io.FileUtils.forceDelete;
public class DeleteOperation extends InvokableAsyncBlockingOperation {
//private static final Logger LOGGER = LogManager.getLogger();
- private final String backupName;
+ private final String backupFileName;
private final CommandContext<ServerCommandSource> context;
- public DeleteOperation(CommandContext<ServerCommandSource> context, String backupName) {
+ public DeleteOperation(CommandContext<ServerCommandSource> context, String backupFileName) {
super("BackupDeletingWorker");
- this.backupName = backupName;
+ this.backupFileName = backupFileName;
this.context = context;
}
@Override
public String toString() {
- return String.format("deletion of %s", backupName);
+ return String.format("deletion of %s", backupFileName);
}
@Override
@@ -41,8 +40,7 @@ public class DeleteOperation extends InvokableAsyncBlockingOperation {
private void delete() {
MinecraftServer server = context.getSource().getMinecraftServer();
- String backupFileName = getBackupFileName(backupName);
- PrintUtil.info("Deleting backup " + backupName);
+ PrintUtil.info("Deleting backup file " + this.backupFileName);
File backupFile = new File(getBackupSaveDirectory(server), backupFileName);
int tryCounter = 0;
do {
@@ -59,7 +57,7 @@ public class DeleteOperation extends InvokableAsyncBlockingOperation {
}
++tryCounter;
} while (backupFile.exists());
- PrintUtil.info("Deleted backup " + backupName);
- msgInfo(context, "Deleted backup " + backupName);
+ PrintUtil.info("Successfully deleted backup file " + this.backupFileName);
+ msgInfo(context, "Successfully deleted backup file " + this.backupFileName);
}
}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java b/src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java
index 22397a1..b95c767 100644
--- a/src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java
+++ b/src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java
@@ -1,9 +1,9 @@
package com.keuin.kbackupfabric.operation;
-import com.keuin.kbackupfabric.exception.ZipUtilException;
import com.keuin.kbackupfabric.operation.abstracts.InvokableBlockingOperation;
+import com.keuin.kbackupfabric.operation.backup.BackupMethod;
+import com.keuin.kbackupfabric.operation.backup.PrimitiveBackupMethod;
import com.keuin.kbackupfabric.util.PrintUtil;
-import com.keuin.kbackupfabric.util.ZipUtil;
import com.mojang.brigadier.context.CommandContext;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.ServerCommandSource;
@@ -13,33 +13,33 @@ import java.io.IOException;
import static com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil.getBackupFileName;
import static com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil.getBackupSaveDirectory;
-import static org.apache.commons.io.FileUtils.forceDelete;
public class RestoreOperation extends InvokableBlockingOperation {
//private static final Logger LOGGER = LogManager.getLogger();
- private final String backupName;
+ private final String backupFileName;
private final Thread serverThread;
- private final String backupFilePath;
- private final String levelDirectory;
+ private final String backupSavePath;
+ private final String levelPath;
private final CommandContext<ServerCommandSource> context;
private final MinecraftServer server;
+ private final BackupMethod backupMethod = PrimitiveBackupMethod.getInstance();
- public RestoreOperation(CommandContext<ServerCommandSource> context, String backupFilePath, String levelDirectory, String backupName) {
+ public RestoreOperation(CommandContext<ServerCommandSource> context, String backupSavePath, String levelPath, String backupFileName) {
server = context.getSource().getMinecraftServer();
- this.backupName = backupName;
+ this.backupFileName = backupFileName;
this.serverThread = server.getThread();
- this.backupFilePath = backupFilePath;
- this.levelDirectory = levelDirectory;
+ this.backupSavePath = backupSavePath;
+ this.levelPath = levelPath;
this.context = context;
}
@Override
protected boolean blockingContext() {
// do restore to backupName
- PrintUtil.broadcast(String.format("Restoring to previous world %s ...", backupName));
+ PrintUtil.broadcast(String.format("Restoring to backup %s ...", backupFileName));
- String backupFileName = getBackupFileName(backupName);
+ String backupFileName = getBackupFileName(this.backupFileName);
PrintUtil.debug("Backup file name: " + backupFileName);
File backupFile = new File(getBackupSaveDirectory(server), backupFileName);
@@ -67,7 +67,7 @@ public class RestoreOperation extends InvokableBlockingOperation {
@Override
public String toString() {
- return String.format("restoration from %s", backupName);
+ return String.format("restoration from %s", backupFileName);
}
private class WorkerThread implements Runnable {
@@ -94,12 +94,16 @@ public class RestoreOperation extends InvokableBlockingOperation {
}while(--cnt > 0);
////////////////////
+ backupMethod.restore(backupFileName, levelPath, backupSavePath);
//ServerRestartUtil.forkAndRestart();
System.exit(111);
} catch (SecurityException e) {
PrintUtil.error("An exception occurred while restoring: " + e.getMessage());
+ } catch (IOException e) {
+ PrintUtil.error(e.toString());
+ PrintUtil.error("Failed to restore.");
}
}
}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/backup/BackupMethod.java b/src/main/java/com/keuin/kbackupfabric/operation/backup/BackupMethod.java
index 4e9eb6c..b65a076 100644
--- a/src/main/java/com/keuin/kbackupfabric/operation/backup/BackupMethod.java
+++ b/src/main/java/com/keuin/kbackupfabric/operation/backup/BackupMethod.java
@@ -1,7 +1,6 @@
package com.keuin.kbackupfabric.operation.backup;
-import com.keuin.kbackupfabric.util.backup.builder.BackupFileNameBuilder;
-import com.keuin.kbackupfabric.util.backup.formatter.BackupFileNameFormatter;
+import com.keuin.kbackupfabric.operation.backup.feedback.PrimitiveBackupFeedback;
import java.io.IOException;
@@ -16,29 +15,8 @@ public interface BackupMethod {
* @param backupName the backup name.
* @return if the backup operation succeed.
*/
- BackupResult backup(String backupName, String levelPath, String backupSaveDirectory) throws IOException;
+ PrimitiveBackupFeedback backup(String backupName, String levelPath, String backupSaveDirectory) throws IOException;
boolean restore(String backupName, String levelPath, String backupSaveDirectory) throws IOException;
- BackupFileNameBuilder getBackupFileNameBuilder();
-
- BackupFileNameFormatter getBackupFileNameFormatter();
-
- class BackupResult {
- private final boolean success;
- private final long backupSizeBytes;
-
- public BackupResult(boolean success, long backupSizeBytes) {
- this.success = success;
- this.backupSizeBytes = backupSizeBytes;
- }
-
- public boolean isSuccess() {
- return success;
- }
-
- public long getBackupSizeBytes() {
- return backupSizeBytes;
- }
- }
}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/backup/IncrementalBackupMethod.java b/src/main/java/com/keuin/kbackupfabric/operation/backup/IncrementalBackupMethod.java
deleted file mode 100644
index 4a87bb3..0000000
--- a/src/main/java/com/keuin/kbackupfabric/operation/backup/IncrementalBackupMethod.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.keuin.kbackupfabric.operation.backup;
-
-import com.google.gson.JsonObject;
-import com.keuin.kbackupfabric.util.PrintUtil;
-import com.keuin.kbackupfabric.util.backup.builder.BackupFileNameBuilder;
-import com.keuin.kbackupfabric.util.backup.builder.ObjectTreeBackupFileNameBuilder;
-import com.keuin.kbackupfabric.util.backup.formatter.BackupFileNameFormatter;
-import com.keuin.kbackupfabric.util.backup.formatter.ObjectTreeBackupFileNameFormatter;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Paths;
-import java.time.LocalDateTime;
-
-public class IncrementalBackupMethod implements BackupMethod {
-
- private static final IncrementalBackupMethod INSTANCE = new IncrementalBackupMethod();
-
- public static IncrementalBackupMethod getInstance() {
- return INSTANCE;
- }
-
- @Override
- public BackupResult backup(String backupName, String levelPath, String backupSaveDirectory) throws IOException {
- /*
- 1. Analyze the save directory, to get a json containing md5 values of all files.
- 2. Copy new files which we do not have in our backup repository.
- 3. Save the above json as a backup file. When restoring from this,
- what we have to do is just copy all files back from the repository,
- based on their md5 digests.
- */
-
- boolean success = true;
- // Generate JSON
- JsonObject hashJson = IncrementalBackupUtil.generateDirectoryJsonObject(levelPath);
- // Copy files
- long newFilesSizeBytes = IncrementalBackupUtil.saveNewFiles(backupSaveDirectory, levelPath, hashJson);
- if(newFilesSizeBytes < 0) {
- success = false;
- PrintUtil.error("Failed to copy new files to object tree.");
- }
- // Save JSON tree
- File jsonFile = new File(String.valueOf(Paths.get(backupSaveDirectory, BackupFileNameBuilder.objectTreeBackup().build(LocalDateTime.now(), backupName))));
- // TODO
- return new BackupResult(success, newFilesSizeBytes);
- }
-
- @Override
- public boolean restore(String backupName, String levelPath, String backupSaveDirectory) throws IOException {
- return false;
- }
-
- @Override
- public BackupFileNameBuilder getBackupFileNameBuilder() {
- return null;
- }
-
- @Override
- public BackupFileNameFormatter getBackupFileNameFormatter() {
- return null;
- }
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/backup/IncrementalBackupUtil.java b/src/main/java/com/keuin/kbackupfabric/operation/backup/IncrementalBackupUtil.java
deleted file mode 100644
index f90aef1..0000000
--- a/src/main/java/com/keuin/kbackupfabric/operation/backup/IncrementalBackupUtil.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package com.keuin.kbackupfabric.operation.backup;
-
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.keuin.kbackupfabric.util.FilesystemUtil;
-import org.apache.commons.codec.digest.DigestUtils;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.*;
-import java.util.Map;
-
-public class IncrementalBackupUtil {
- /**
- * Generate a json object representing a directory and its all sub files and directories.
- * @param path path to the directory.
- * @return a json object.
- */
- public static JsonObject generateDirectoryJsonObject(String path) throws IOException {
- JsonObject json = new JsonObject();
- File directory = new File(path);
- if (!(directory.isDirectory() && directory.exists()))
- throw new IOException(String.format("Path %s is not a valid directory.", path));
-
- // Iterate all sub files using BFS.
- try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get(path))) {
- for (Path sub : directoryStream) {
- if (sub.toFile().isFile()) {
- // A sub file
- // Just hash and add it as a string
- try (InputStream is = Files.newInputStream(sub)) {
- String md5 = org.apache.commons.codec.digest.DigestUtils.md5Hex(is);
- json.addProperty(sub.getFileName().toString(), md5);
- }
- } else {
- // A sub directory
- // Search into
- json.addProperty(String.valueOf(sub.getFileName()), sub.toString());
- }
- }
- }
-
- return json;
- }
-
- /**
- * Save new (or modified) files to target path, based on hash json.
- * @param targetSavePath where we should save new files.
- * @param sourcePath where new files come from. This path must be the base directory of given hash json.
- * @param hashJson the json object obtained by calling generateDirectoryJsonObject method.
- * @return total size of new files. If failed, will return -1.
- */
- public static long saveNewFiles(String targetSavePath, String sourcePath, JsonObject hashJson) throws IOException {
- long bytesCopied = 0;
- for (Map.Entry<String, JsonElement> entry : hashJson.entrySet()) {
- String key = entry.getKey();
- JsonElement value = entry.getValue();
- if (value.isJsonPrimitive() && value.getAsJsonPrimitive().isString()) {
- // A sub file
- // key is file name
- // value is file md5
- String md5 = value.getAsJsonPrimitive().getAsString();
- File saveTarget = new File(targetSavePath, md5);
- if (!saveTarget.exists()) {
- // Target file does not exist. We have to copy this to the target.
- File sourceFile = new File(sourcePath, key);
- Files.copy(sourceFile.toPath(), saveTarget.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
- try {
- bytesCopied += sourceFile.length();
- } catch (SecurityException ignored) {
- // failed to get the file size. Just ignore this.
- }
- }
- } else if (value.isJsonObject()) {
- // A sub directory
- // key is directory name
- // value is directory json object
- // Go into
- if(!value.isJsonObject())
- throw new IllegalArgumentException(String.format("Hash json contains illegal argument of a directory item: %s -> %s.", key, value));
- Path pathSource = Paths.get(sourcePath, key);
- bytesCopied += saveNewFiles(targetSavePath, pathSource.toString(), value.getAsJsonObject());
- } else {
- throw new IllegalArgumentException(String.format("Hash json contains illegal element: %s -> %s.", key, value));
- }
- }
- return bytesCopied;
- }
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/backup/PrimitiveBackupMethod.java b/src/main/java/com/keuin/kbackupfabric/operation/backup/PrimitiveBackupMethod.java
index 854355d..9c065a6 100644
--- a/src/main/java/com/keuin/kbackupfabric/operation/backup/PrimitiveBackupMethod.java
+++ b/src/main/java/com/keuin/kbackupfabric/operation/backup/PrimitiveBackupMethod.java
@@ -2,11 +2,13 @@ package com.keuin.kbackupfabric.operation.backup;
import com.keuin.kbackupfabric.exception.ZipUtilException;
import com.keuin.kbackupfabric.metadata.BackupMetadata;
+import com.keuin.kbackupfabric.operation.backup.feedback.PrimitiveBackupFeedback;
import com.keuin.kbackupfabric.util.FilesystemUtil;
import com.keuin.kbackupfabric.util.PrintUtil;
import com.keuin.kbackupfabric.util.ZipUtil;
-import com.keuin.kbackupfabric.util.backup.builder.BackupFileNameBuilder;
-import com.keuin.kbackupfabric.util.backup.formatter.BackupFileNameFormatter;
+import com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil;
+import com.keuin.kbackupfabric.util.backup.BackupNameTimeFormatter;
+import com.keuin.kbackupfabric.util.backup.name.PrimitiveBackupFileNameEncoder;
import java.io.File;
import java.io.IOException;
@@ -23,27 +25,32 @@ public class PrimitiveBackupMethod implements BackupMethod {
return INSTANCE;
}
+ @Deprecated
+ private String getBackupFileName(LocalDateTime time, String backupName) {
+ String timeString = BackupNameTimeFormatter.localDateTimeToString(time);
+ return String.format("%s%s_%s%s", BackupFilesystemUtil.getBackupFileNamePrefix(), timeString, backupName, ".zip");
+ }
+
@Override
- public BackupResult backup(String backupName, String levelPath, String backupSaveDirectory) throws IOException {
- String backupFileName = BackupFileNameBuilder.primitiveZipBackup().build(LocalDateTime.now(),backupName);
+ public PrimitiveBackupFeedback backup(String customBackupName, String levelPath, String backupSavePath) throws IOException {
+// String backupFileName = getBackupFileName(LocalDateTime.now(),backupName);
+ String backupFileName = new PrimitiveBackupFileNameEncoder().encode(customBackupName, LocalDateTime.now());
try {
- BackupMetadata backupMetadata = new BackupMetadata(System.currentTimeMillis(), backupName);
-
- PrintUtil.info(String.format("zip(srcPath=%s, destPath=%s)", levelPath, backupSaveDirectory));
+ BackupMetadata backupMetadata = new BackupMetadata(System.currentTimeMillis(), customBackupName);
+ PrintUtil.info(String.format("zip(srcPath=%s, destPath=%s)", levelPath, backupSavePath));
PrintUtil.info("Compressing level ...");
- ZipUtil.makeBackupZip(levelPath, backupSaveDirectory, backupFileName, backupMetadata);
-
+ ZipUtil.makeBackupZip(levelPath, backupSavePath, backupFileName, backupMetadata);
} catch (ZipUtilException exception) {
PrintUtil.info("Infinite recursive of directory tree detected, backup was aborted.");
- return new BackupResult(false, 0);
+ return new PrimitiveBackupFeedback(false, 0);
}
// Get backup file size and return
- return new BackupResult(true, FilesystemUtil.getFileSizeBytes(backupSaveDirectory, backupFileName));
+ return new PrimitiveBackupFeedback(true, FilesystemUtil.getFileSizeBytes(backupSavePath, backupFileName));
}
@Override
- public boolean restore(String backupName, String levelDirectory, String backupSaveDirectory) throws IOException {
+ public boolean restore(String backupFileName, String levelDirectory, String backupSaveDirectory) throws IOException {
// Delete old level
PrintUtil.info("Server stopped. Deleting old level ...");
File levelDirFile = new File(levelDirectory);
@@ -73,10 +80,10 @@ public class PrimitiveBackupMethod implements BackupMethod {
// TODO: Refactor this to the concrete BackupMethod.
// Decompress archive
PrintUtil.info("Decompressing archived level ...");
- ZipUtil.unzip(Paths.get(backupSaveDirectory, backupName).toString(), levelDirectory, false);
+ ZipUtil.unzip(Paths.get(backupSaveDirectory, backupFileName).toString(), levelDirectory, false);
long endTime = System.currentTimeMillis();
PrintUtil.info(String.format("Restore complete! (%.2fs) Please restart the server manually.", (endTime - startTime) / 1000.0));
- PrintUtil.info("If you want to restart automatically after restoring, please visit the project manual at: https://github.com/keuin/KBackup-Fabric/blob/master/README.md");
+ PrintUtil.info("If you want to restart automatically after restoring, please check the manual at: https://github.com/keuin/KBackup-Fabric/blob/master/README.md");
// try {
// Thread.sleep(1000);
@@ -85,14 +92,4 @@ public class PrimitiveBackupMethod implements BackupMethod {
return true;
}
-
- @Override
- public BackupFileNameBuilder getBackupFileNameBuilder() {
- return BackupFileNameBuilder.primitiveZipBackup();
- }
-
- @Override
- public BackupFileNameFormatter getBackupFileNameFormatter() {
- return BackupFileNameFormatter.primitiveZipBackup();
- }
}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/backup/feedback/BackupFeedback.java b/src/main/java/com/keuin/kbackupfabric/operation/backup/feedback/BackupFeedback.java
new file mode 100644
index 0000000..92a9f39
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/operation/backup/feedback/BackupFeedback.java
@@ -0,0 +1,5 @@
+package com.keuin.kbackupfabric.operation.backup.feedback;
+
+public interface BackupFeedback {
+ String getFeedback();
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/backup/feedback/PrimitiveBackupFeedback.java b/src/main/java/com/keuin/kbackupfabric/operation/backup/feedback/PrimitiveBackupFeedback.java
new file mode 100644
index 0000000..6d7a15b
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/operation/backup/feedback/PrimitiveBackupFeedback.java
@@ -0,0 +1,29 @@
+package com.keuin.kbackupfabric.operation.backup.feedback;
+
+import static com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil.getFriendlyFileSizeString;
+
+public class PrimitiveBackupFeedback implements BackupFeedback {
+ private final boolean success;
+ private final long backupSizeBytes;
+
+ public PrimitiveBackupFeedback(boolean success, long backupSizeBytes) {
+ this.success = success;
+ this.backupSizeBytes = backupSizeBytes;
+ }
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public long getBackupSizeBytes() {
+ return backupSizeBytes;
+ }
+
+ @Override
+ public String getFeedback() {
+ if (success && backupSizeBytes >= 0)
+ return String.format(" File size: %s.", getFriendlyFileSizeString(backupSizeBytes));
+ else
+ return "";
+ }
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/BackupFilesystemUtil.java b/src/main/java/com/keuin/kbackupfabric/util/backup/BackupFilesystemUtil.java
index d0c7500..c1aa5fe 100644
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/BackupFilesystemUtil.java
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/BackupFilesystemUtil.java
@@ -17,6 +17,7 @@ public final class BackupFilesystemUtil {
private static final String backupSaveDirectoryName = "backups";
private static final String backupFileNamePrefix = "kbackup-";
+ @Deprecated
public static String getBackupFileNamePrefix() {
return backupFileNamePrefix;
}
@@ -26,18 +27,18 @@ public final class BackupFilesystemUtil {
return backupFileNamePrefix + backupName + ".zip";
}
- @Deprecated
- public static String getBackupName(String backupFileName) {
- try {
- if (backupFileName.matches(backupFileNamePrefix + ".+\\.zip"))
- return backupFileName.substring(backupFileNamePrefix.length(), backupFileName.length() - 4);
- } catch (IndexOutOfBoundsException ignored) {
- }
- return backupFileName;
- }
+// @Deprecated
+// public static String getBackupName(String backupFileName) {
+// try {
+// if (backupFileName.matches(backupFileNamePrefix + ".+\\.zip"))
+// return backupFileName.substring(backupFileNamePrefix.length(), backupFileName.length() - 4);
+// } catch (IndexOutOfBoundsException ignored) {
+// }
+// return backupFileName;
+// }
- public static boolean isBackupNameValid(String backupName, MinecraftServer server) {
- File backupFile = new File(getBackupSaveDirectory(server), getBackupFileName(backupName));
+ public static boolean isBackupFileExists(String backupFileName, MinecraftServer server) {
+ File backupFile = new File(getBackupSaveDirectory(server), backupFileName);
return backupFile.isFile();
}
@@ -70,8 +71,8 @@ public final class BackupFilesystemUtil {
return -1;
}
- public static String getFriendlyFileSizeString(long size) {
- double fileSize = size * 1.0 / 1024 / 1024; // Default unit is MB
+ public static String getFriendlyFileSizeString(long sizeBytes) {
+ double fileSize = sizeBytes * 1.0 / 1024 / 1024; // Default unit is MB
if (fileSize > 1000)
//msgInfo(context, String.format("File size: %.2fGB", fileSize / 1024));
return String.format("%.2fGB", fileSize / 1024);
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/BackupType.java b/src/main/java/com/keuin/kbackupfabric/util/backup/BackupType.java
deleted file mode 100644
index d02ce77..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/BackupType.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.keuin.kbackupfabric.util.backup;
-
-/**
- * Representing the backup type.
- * Should only be used in BackupFileNameBuilder and BackupFileNameFormatter
- */
-@Deprecated
-public enum BackupType {
-
- PRIMITIVE_ZIP_BACKUP("Primitive Zip Backup", "zip"),
- OBJECT_TREE_BACKUP("Object Tree Backup", "incremental");
-
- private final String friendlyName; // e.g. Primitive Zip Backup
- private final String name; // e.g. zip
-
- BackupType(String friendlyName, String name) {
- this.friendlyName = friendlyName;
- this.name = name;
- }
-
- /**
- * Get name used in command.
- * @return name (such as "zip", "incremental").
- */
- public String getName() {
- return name;
- }
-
- @Override
- public String toString() {
- return friendlyName;
- }
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/builder/BackupFileNameBuilder.java b/src/main/java/com/keuin/kbackupfabric/util/backup/builder/BackupFileNameBuilder.java
deleted file mode 100644
index f57302c..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/builder/BackupFileNameBuilder.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.builder;
-
-
-import java.time.LocalDateTime;
-
-public interface BackupFileNameBuilder {
-
- static BackupFileNameBuilder primitiveZipBackup() {
- return PrimitiveZipBackupFileNameBuilder.getInstance();
- }
-
- static BackupFileNameBuilder objectTreeBackup() {
- return ObjectTreeBackupFileNameBuilder.getInstance();
- }
-
- /**
- * Build a backup file name based on given information.
- * @param time when the backup was created.
- * @param backupName the custom name of this backup. Note that this should be a valid file name in current file system.
- * @return the backup file name string.
- */
- String build(LocalDateTime time, String backupName);
-
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/builder/ObjectTreeBackupFileNameBuilder.java b/src/main/java/com/keuin/kbackupfabric/util/backup/builder/ObjectTreeBackupFileNameBuilder.java
deleted file mode 100644
index c3d8257..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/builder/ObjectTreeBackupFileNameBuilder.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.builder;
-
-import com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil;
-import com.keuin.kbackupfabric.util.backup.BackupNameTimeFormatter;
-
-import java.time.LocalDateTime;
-
-public class ObjectTreeBackupFileNameBuilder implements BackupFileNameBuilder {
- private static final ObjectTreeBackupFileNameBuilder instance = new ObjectTreeBackupFileNameBuilder();
-
- public static ObjectTreeBackupFileNameBuilder getInstance() {
- return instance;
- }
-
- @Override
- public String build(LocalDateTime time, String backupName) {
- String timeString = BackupNameTimeFormatter.localDateTimeToString(time);
- return String.format("%s%s_%s%s", BackupFilesystemUtil.getBackupFileNamePrefix(), timeString, backupName, ".json");
- }
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/builder/PrimitiveZipBackupFileNameBuilder.java b/src/main/java/com/keuin/kbackupfabric/util/backup/builder/PrimitiveZipBackupFileNameBuilder.java
deleted file mode 100644
index 6d8b5f5..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/builder/PrimitiveZipBackupFileNameBuilder.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.builder;
-
-import com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil;
-import com.keuin.kbackupfabric.util.backup.BackupNameTimeFormatter;
-
-import java.time.LocalDateTime;
-
-public class PrimitiveZipBackupFileNameBuilder implements BackupFileNameBuilder {
-
- private static final PrimitiveZipBackupFileNameBuilder instance = new PrimitiveZipBackupFileNameBuilder();
-
- public static PrimitiveZipBackupFileNameBuilder getInstance() {
- return instance;
- }
-
- @Override
- public String build(LocalDateTime time, String backupName) {
- String timeString = BackupNameTimeFormatter.localDateTimeToString(time);
- return String.format("%s%s_%s%s", BackupFilesystemUtil.getBackupFileNamePrefix(), timeString, backupName, ".zip");
- }
-
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/formatter/BackupFileNameFormatter.java b/src/main/java/com/keuin/kbackupfabric/util/backup/formatter/BackupFileNameFormatter.java
deleted file mode 100644
index a437629..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/formatter/BackupFileNameFormatter.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.formatter;
-
-import com.keuin.kbackupfabric.util.backup.BackupNameTimeFormatter;
-
-import java.time.LocalDateTime;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public interface BackupFileNameFormatter {
-
- BackupFileName format(String fileName);
-
- class BackupFileName {
- public final LocalDateTime time;
- public final String name;
-
- public BackupFileName(LocalDateTime time, String name) {
- this.time = time;
- this.name = name;
- }
- }
-
- static BackupFileNameFormatter objectTreeBackup() {
- return ObjectTreeBackupFileNameFormatter.getInstance();
- }
-
- static BackupFileNameFormatter primitiveZipBackup() {
- return PrimitiveZipBackupFileNameFormatter.getInstance();
- }
-
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/formatter/ObjectTreeBackupFileNameFormatter.java b/src/main/java/com/keuin/kbackupfabric/util/backup/formatter/ObjectTreeBackupFileNameFormatter.java
deleted file mode 100644
index 08805b2..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/formatter/ObjectTreeBackupFileNameFormatter.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.formatter;
-
-import com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil;
-import com.keuin.kbackupfabric.util.backup.BackupNameTimeFormatter;
-import org.spongepowered.asm.mixin.Overwrite;
-
-import java.time.LocalDateTime;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class ObjectTreeBackupFileNameFormatter implements BackupFileNameFormatter {
-
- private static final ObjectTreeBackupFileNameFormatter instance = new ObjectTreeBackupFileNameFormatter();
-
- public static ObjectTreeBackupFileNameFormatter getInstance() {
- return instance;
- }
-
- @Override
- public BackupFileNameFormatter.BackupFileName format(String fileName) {
- LocalDateTime time = getTime(fileName);
- String name = getBackupName(fileName);
- return new BackupFileNameFormatter.BackupFileName(time,name);
- }
-
- private LocalDateTime getTime(String fileName) {
- Matcher matcher = Pattern.compile("[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}-[0-9]{2}").matcher(fileName);
- if (matcher.find()) {
- String timeString = matcher.group(0);
- return BackupNameTimeFormatter.timeStringToLocalDateTime(timeString);
- }
- return null;
- }
-
- private String getBackupName(String backupFileName) {
- try {
- if (backupFileName.matches(BackupFilesystemUtil.getBackupFileNamePrefix() + ".+\\.json"))
- return backupFileName.substring(BackupFilesystemUtil.getBackupFileNamePrefix().length(), backupFileName.length() - 4);
- } catch (IndexOutOfBoundsException ignored) {
- }
- return backupFileName;
- }
-
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/formatter/PrimitiveZipBackupFileNameFormatter.java b/src/main/java/com/keuin/kbackupfabric/util/backup/formatter/PrimitiveZipBackupFileNameFormatter.java
deleted file mode 100644
index 2d50d17..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/formatter/PrimitiveZipBackupFileNameFormatter.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.formatter;
-
-import com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil;
-import com.keuin.kbackupfabric.util.backup.BackupNameTimeFormatter;
-
-import java.time.LocalDateTime;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class PrimitiveZipBackupFileNameFormatter implements BackupFileNameFormatter {
-
- private static final PrimitiveZipBackupFileNameFormatter instance = new PrimitiveZipBackupFileNameFormatter();
-
- public static PrimitiveZipBackupFileNameFormatter getInstance() {
- return instance;
- }
-
- @Override
- public BackupFileNameFormatter.BackupFileName format(String fileName) {
- LocalDateTime time = getTime(fileName);
- String name = getBackupName(fileName);
- return new BackupFileNameFormatter.BackupFileName(time,name);
- }
-
- private LocalDateTime getTime(String fileName) {
- Matcher matcher = Pattern.compile("[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}-[0-9]{2}").matcher(fileName);
- if (matcher.find()) {
- String timeString = matcher.group(0);
- return BackupNameTimeFormatter.timeStringToLocalDateTime(timeString);
- }
- return null;
- }
-
- private String getBackupName(String backupFileName) {
- try {
- if (backupFileName.matches(BackupFilesystemUtil.getBackupFileNamePrefix() + ".+\\.zip"))
- return backupFileName.substring(BackupFilesystemUtil.getBackupFileNamePrefix().length(), backupFileName.length() - 4);
- } catch (IndexOutOfBoundsException ignored) {
- }
- return backupFileName;
- }
-
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionFactory.java b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionFactory.java
index ea9edd9..ac87883 100644
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionFactory.java
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionFactory.java
@@ -1,6 +1,6 @@
package com.keuin.kbackupfabric.util.backup.incremental;
-import com.keuin.kbackupfabric.util.backup.incremental.identifier.FileIdentifierFactory;
+import com.keuin.kbackupfabric.util.backup.incremental.identifier.FileIdentifierProvider;
import com.keuin.kbackupfabric.util.backup.incremental.identifier.ObjectIdentifier;
import java.io.File;
@@ -17,9 +17,9 @@ import java.util.*;
*/
public class ObjectCollectionFactory <T extends ObjectIdentifier> {
- private final FileIdentifierFactory<T> identifierFactory;
+ private final FileIdentifierProvider<T> identifierFactory;
- public ObjectCollectionFactory(FileIdentifierFactory<T> identifierFactory) {
+ public ObjectCollectionFactory(FileIdentifierProvider<T> identifierFactory) {
this.identifierFactory = identifierFactory;
}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionSerializer.java b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionSerializer.java
index cc77837..6f9b792 100644
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionSerializer.java
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionSerializer.java
@@ -3,6 +3,9 @@ package com.keuin.kbackupfabric.util.backup.incremental;
import java.io.*;
import java.util.Objects;
+/**
+ * Serialize and deserialize ObjectCollection from/to the disk file.
+ */
public class ObjectCollectionSerializer {
public static ObjectCollection fromFile(File file) throws IOException {
Objects.requireNonNull(file);
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/FileIdentifierFactory.java b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/FileIdentifierProvider.java
index 34ad9a0..9a03371 100644
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/FileIdentifierFactory.java
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/FileIdentifierProvider.java
@@ -3,6 +3,6 @@ package com.keuin.kbackupfabric.util.backup.incremental.identifier;
import java.io.File;
import java.io.IOException;
-public interface FileIdentifierFactory<T extends ObjectIdentifier> {
+public interface FileIdentifierProvider<T extends ObjectIdentifier> {
T fromFile(File file) throws IOException;
}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/Sha256Identifier.java b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/Sha256Identifier.java
index 9ecf2d3..cbf1bb9 100644
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/Sha256Identifier.java
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/Sha256Identifier.java
@@ -15,7 +15,7 @@ public class Sha256Identifier extends SingleHashIdentifier {
private static final int SHA256_LENGTH = 32;
private static final Sha256Identifier DUMMY = new Sha256Identifier(new byte[SHA256_LENGTH]); // only for using its hash method
- private static final FileIdentifierFactory<Sha256Identifier> factory = Sha256Identifier::fromFile;
+ private static final FileIdentifierProvider<Sha256Identifier> factory = Sha256Identifier::fromFile;
public static Sha256Identifier fromFile(File file) throws IOException {
if (!Objects.requireNonNull(file).isFile()) {
@@ -24,7 +24,7 @@ public class Sha256Identifier extends SingleHashIdentifier {
return new Sha256Identifier(DUMMY.hash(file));
}
- public static FileIdentifierFactory<Sha256Identifier> getFactory() {
+ public static FileIdentifierProvider<Sha256Identifier> getFactory() {
return factory;
}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/name/BackupFileNameEncoder.java b/src/main/java/com/keuin/kbackupfabric/util/backup/name/BackupFileNameEncoder.java
new file mode 100644
index 0000000..83967b7
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/name/BackupFileNameEncoder.java
@@ -0,0 +1,49 @@
+package com.keuin.kbackupfabric.util.backup.name;
+
+import java.time.LocalDateTime;
+
+/**
+ * Encode and decode backup file name for a specific backup type.
+ */
+public interface BackupFileNameEncoder {
+
+ /**
+ * Construct full backup file name from custom name and creation time.
+ * @param customName the custom name. If the custom name contains invalid chars, an exception will be thrown.
+ * @param time the creation time.
+ * @return the file name.
+ */
+ String encode(String customName, LocalDateTime time);
+
+ /**
+ * Extract custom and backup time from backup file name.
+ * @param fileName the backup file name.
+ * @return the information. If the given file name is invalid, return null.
+ */
+ BackupBasicInformation decode(String fileName);
+
+ /**
+ * Check if the given string is a valid custom backup name.
+ * @param customName the custom backup name.
+ * @return if the name is valid.
+ */
+ default boolean isValidCustomName(String customName) {
+ final char[] ILLEGAL_CHARACTERS = {'/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':'};
+ for (char c : ILLEGAL_CHARACTERS) {
+ if (customName.contains(String.valueOf(c))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ class BackupBasicInformation {
+ public final String customName;
+ public final LocalDateTime time;
+
+ BackupBasicInformation(String customName, LocalDateTime time) {
+ this.customName = customName;
+ this.time = time;
+ }
+ }
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/name/PrimitiveBackupFileNameEncoder.java b/src/main/java/com/keuin/kbackupfabric/util/backup/name/PrimitiveBackupFileNameEncoder.java
new file mode 100644
index 0000000..39c2403
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/name/PrimitiveBackupFileNameEncoder.java
@@ -0,0 +1,34 @@
+package com.keuin.kbackupfabric.util.backup.name;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class PrimitiveBackupFileNameEncoder implements BackupFileNameEncoder {
+
+ private static final String backupFileNamePrefix = "kbackup";
+ private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss");
+
+ @Override
+ public String encode(String customName, LocalDateTime time) {
+ if (!isValidCustomName(customName))
+ throw new IllegalArgumentException("Invalid custom name");
+ String timeString = time.format(formatter);
+ return backupFileNamePrefix + "-" + timeString + "_" + customName + ".zip";
+ }
+
+ @Override
+ public BackupBasicInformation decode(String fileName) {
+ Pattern pattern = Pattern.compile(
+ backupFileNamePrefix + "-" + "([0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}-[0-9]{2})_(.+)\\.zip"
+ );
+ Matcher matcher = pattern.matcher(fileName);
+ if (matcher.find()) {
+ String timeString = matcher.group(1);
+ String customName = matcher.group(2);
+ return new BackupBasicInformation(customName, LocalDateTime.parse(timeString, formatter));
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/suggestion/BackupMethodSuggestionProvider.java b/src/main/java/com/keuin/kbackupfabric/util/backup/suggestion/BackupMethodSuggestionProvider.java
deleted file mode 100644
index 320d9bf..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/suggestion/BackupMethodSuggestionProvider.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.suggestion;
-
-import com.keuin.kbackupfabric.util.backup.BackupType;
-import com.mojang.brigadier.suggestion.SuggestionProvider;
-import com.mojang.brigadier.suggestion.Suggestions;
-import com.mojang.brigadier.suggestion.SuggestionsBuilder;
-import net.minecraft.server.command.ServerCommandSource;
-
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Locale;
-import java.util.concurrent.CompletableFuture;
-
-public class BackupMethodSuggestionProvider {
-
- private static final List<String> suggestions = Arrays.asList(
- BackupType.OBJECT_TREE_BACKUP.getName(),
- BackupType.PRIMITIVE_ZIP_BACKUP.getName()
- ); // All backup methods
-
- public static SuggestionProvider<ServerCommandSource> getProvider() {
- return (context, builder) -> getCompletableFuture(builder);
- }
-
- private static CompletableFuture<Suggestions> getCompletableFuture(SuggestionsBuilder builder) {
- String remaining = builder.getRemaining().toLowerCase(Locale.ROOT);
- for (String string : suggestions) { // Iterate through the supplied list
- if (string.toLowerCase(Locale.ROOT).startsWith(remaining)) {
- builder.suggest(string); // Add every single entry to suggestions list.
- }
- }
- return builder.buildFuture(); // Create the CompletableFuture containing all the suggestions
- }
-
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/suggestion/BackupNameSuggestionProvider.java b/src/main/java/com/keuin/kbackupfabric/util/backup/suggestion/BackupNameSuggestionProvider.java
index f6f4056..01152c2 100644
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/suggestion/BackupNameSuggestionProvider.java
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/suggestion/BackupNameSuggestionProvider.java
@@ -1,6 +1,5 @@
package com.keuin.kbackupfabric.util.backup.suggestion;
-import com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
@@ -38,7 +37,7 @@ public class BackupNameSuggestionProvider {
if (files == null)
return;
for (File f : files)
- candidateCacheList.add(BackupFilesystemUtil.getBackupName(f.getName()));
+ candidateCacheList.add(f.getName());
cacheUpdateTime = System.currentTimeMillis();
} catch (NullPointerException ignored) {
}
diff --git a/src/test/java/IncrementalBackupUtilTest.java b/src/test/java/IncrementalBackupUtilTest.java
deleted file mode 100644
index b050a91..0000000
--- a/src/test/java/IncrementalBackupUtilTest.java
+++ /dev/null
@@ -1,16 +0,0 @@
-import com.keuin.kbackupfabric.operation.backup.IncrementalBackupUtil;
-
-import java.io.IOException;
-
-public class IncrementalBackupUtilTest {
-
- @org.junit.Test
- public void generateDirectoryJsonObject() {
- try {
- System.out.println(IncrementalBackupUtil.generateDirectoryJsonObject("D:\\1"));
- } catch (IOException exception) {
- exception.printStackTrace();
- }
-
- }
-} \ No newline at end of file
diff --git a/src/test/java/com/keuin/kbackupfabric/util/backup/name/PrimitiveBackupFileNameEncoderTest.java b/src/test/java/com/keuin/kbackupfabric/util/backup/name/PrimitiveBackupFileNameEncoderTest.java
new file mode 100644
index 0000000..4823575
--- /dev/null
+++ b/src/test/java/com/keuin/kbackupfabric/util/backup/name/PrimitiveBackupFileNameEncoderTest.java
@@ -0,0 +1,21 @@
+package com.keuin.kbackupfabric.util.backup.name;
+
+import org.junit.Test;
+
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+
+import static org.junit.Assert.assertEquals;
+
+public class PrimitiveBackupFileNameEncoderTest {
+
+ @Test
+ public void testConsistency() {
+ LocalDateTime time = LocalDateTime.ofEpochSecond(System.currentTimeMillis()/1000, 0, ZoneOffset.UTC);
+ String name = "Test Na_me";
+ PrimitiveBackupFileNameEncoder encoder = new PrimitiveBackupFileNameEncoder();
+ BackupFileNameEncoder.BackupBasicInformation information = encoder.decode(encoder.encode(name, time));
+ assertEquals(time, information.time);
+ assertEquals(name, information.customName);
+ }
+} \ No newline at end of file