commit
51ad310136
|
@ -2,13 +2,13 @@
|
||||||
org.gradle.jvmargs=-Xmx1G
|
org.gradle.jvmargs=-Xmx1G
|
||||||
|
|
||||||
minecraft_version=1.16.1
|
minecraft_version=1.16.1
|
||||||
yarn_mappings=1.16.1+build.18
|
yarn_mappings=1.16.1+build.20
|
||||||
loader_version=0.8.8+build.202
|
loader_version=0.8.9+build.203
|
||||||
|
|
||||||
#Fabric api
|
#Fabric api
|
||||||
fabric_version=0.14.0+build.371-1.16
|
fabric_version=0.14.1+build.372-1.16
|
||||||
|
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version = 1.2.3
|
mod_version = 1.2.4
|
||||||
maven_group = net.szum123321
|
maven_group = net.szum123321
|
||||||
archives_base_name = textile_backup
|
archives_base_name = textile_backup
|
|
@ -45,13 +45,14 @@ public class ConfigHandler {
|
||||||
@Comment("\nShould every world has its won backup folder?\n")
|
@Comment("\nShould every world has its won backup folder?\n")
|
||||||
public boolean perWorldBackup = false;
|
public boolean perWorldBackup = false;
|
||||||
|
|
||||||
@Comment("\nMaximum number of backups to keep. If set to 0 then no backup will be deleted based their its amount\n")
|
@Comment("\nMaximum number of backups to keep. If set to 0 then no backup will be deleted based their amount\n")
|
||||||
public int backupsToKeep = 10;
|
public int backupsToKeep = 10;
|
||||||
|
|
||||||
@Comment("\nMaximum age of backups to keep in seconds.\n If set to 0 then backups will not be deleted based their its age \n")
|
@Comment("\nMaximum age of backups to keep in seconds.\n If set to 0 then backups will not be deleted based their age \n")
|
||||||
public long maxAge = 0;
|
public long maxAge = 0;
|
||||||
|
|
||||||
@Comment("\nMaximum size of backup folder in kilo bytes (1024).\n")
|
@Comment("\nMaximum size of backup folder in kilo bytes (1024).\n" +
|
||||||
|
"If set to 0 then backups will not be deleted\n")
|
||||||
public int maxSize = 0;
|
public int maxSize = 0;
|
||||||
|
|
||||||
@Comment("\nCompression level \n0 - 9\n Only affects zip compression.\n")
|
@Comment("\nCompression level \n0 - 9\n Only affects zip compression.\n")
|
||||||
|
|
|
@ -21,18 +21,15 @@ package net.szum123321.textile_backup.core;
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.command.ServerCommandSource;
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
import net.szum123321.textile_backup.ConfigHandler;
|
|
||||||
import net.szum123321.textile_backup.TextileBackup;
|
import net.szum123321.textile_backup.TextileBackup;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.attribute.FileTime;
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Objects;
|
import java.util.Comparator;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
public class BackupHelper {
|
public class BackupHelper {
|
||||||
public static Thread create(MinecraftServer server, ServerCommandSource ctx, boolean save, String comment) {
|
public static Thread create(MinecraftServer server, ServerCommandSource ctx, boolean save, String comment) {
|
||||||
|
@ -66,89 +63,57 @@ public class BackupHelper {
|
||||||
public static void executeFileLimit(ServerCommandSource ctx, String worldName) {
|
public static void executeFileLimit(ServerCommandSource ctx, String worldName) {
|
||||||
File root = getBackupRootPath(worldName);
|
File root = getBackupRootPath(worldName);
|
||||||
|
|
||||||
if (root.isDirectory() && root.exists()) {
|
if (root.isDirectory() && root.exists() && root.listFiles() != null) {
|
||||||
if (TextileBackup.config.maxAge > 0) {
|
if (TextileBackup.config.maxAge > 0) { // delete files older that configured
|
||||||
LocalDateTime now = LocalDateTime.now();
|
final LocalDateTime now = LocalDateTime.now();
|
||||||
|
|
||||||
Arrays.stream(root.listFiles()).filter(f -> f.exists() && f.isFile()).forEach(f -> {
|
Arrays.stream(root.listFiles())
|
||||||
LocalDateTime creationTime;
|
.filter(BackupHelper::isFileOk)
|
||||||
|
.filter(f -> Utilities.getFileCreationTime(f).isPresent()) // We check if we can get file's creation date so that the next line won't throw an exception
|
||||||
try {
|
.filter(f -> now.toEpochSecond(ZoneOffset.UTC) - Utilities.getFileCreationTime(f).get().toEpochSecond(ZoneOffset.UTC) > TextileBackup.config.maxAge)
|
||||||
try {
|
.forEach(f -> {
|
||||||
FileTime fileTime = (FileTime) Files.getAttribute(f.toPath(), "creationTime");
|
if(f.delete())
|
||||||
|
|
||||||
creationTime = LocalDateTime.ofInstant(fileTime.toInstant(), ZoneOffset.UTC);
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
try {
|
|
||||||
creationTime = LocalDateTime.from(
|
|
||||||
Utilities.getDateTimeFormatter().parse(
|
|
||||||
f.getName().split(Objects.requireNonNull(getFileExtension(f)))[0].split("#")[0]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} catch (Exception ignored2) {
|
|
||||||
creationTime = LocalDateTime.from(
|
|
||||||
Utilities.getBackupDateTimeFormatter().parse(
|
|
||||||
f.getName().split(Objects.requireNonNull(getFileExtension(f)))[0].split("#")[0]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (now.toEpochSecond(ZoneOffset.UTC) - creationTime.toEpochSecond(ZoneOffset.UTC) > TextileBackup.config.maxAge) {
|
|
||||||
Utilities.info("Deleting: " + f.getName(), ctx);
|
Utilities.info("Deleting: " + f.getName(), ctx);
|
||||||
f.delete();
|
else
|
||||||
}
|
Utilities.sendError("Something went wrong while deleting: " + f.getName(), ctx);
|
||||||
} catch (NullPointerException e) {
|
|
||||||
TextileBackup.LOGGER.error("File: {}, was not deleted because could not parse date and time. Please delete it by hand.", f.getName());
|
|
||||||
|
|
||||||
Utilities.sendError("File: " + f.getName() + ", was not deleted because could not parse date and time. Please delete it by hand.", ctx);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TextileBackup.config.backupsToKeep > 0 && root.listFiles().length > TextileBackup.config.backupsToKeep) {
|
if (TextileBackup.config.backupsToKeep > 0 && root.listFiles().length > TextileBackup.config.backupsToKeep) {
|
||||||
int var1 = root.listFiles().length - TextileBackup.config.backupsToKeep;
|
AtomicInteger i = new AtomicInteger(root.listFiles().length);
|
||||||
|
|
||||||
File[] files = root.listFiles();
|
Arrays.stream(root.listFiles())
|
||||||
assert files != null;
|
.filter(BackupHelper::isFileOk)
|
||||||
|
.filter(f -> Utilities.getFileCreationTime(f).isPresent())
|
||||||
|
.sorted(Comparator.comparing(f -> Utilities.getFileCreationTime(f).get()))
|
||||||
|
.takeWhile(f -> i.get() > TextileBackup.config.backupsToKeep)
|
||||||
|
.forEach(f -> {
|
||||||
|
if(f.delete())
|
||||||
|
Utilities.info("Deleting: " + f.getName(), ctx);
|
||||||
|
else
|
||||||
|
Utilities.sendError("Something went wrong while deleting: " + f.getName(), ctx);
|
||||||
|
|
||||||
Arrays.sort(files);
|
i.getAndDecrement();
|
||||||
|
});
|
||||||
for (int i = 0; i < var1; i++) {
|
|
||||||
Utilities.info("Deleting: " + files[i].getName(), ctx);
|
|
||||||
files[i].delete();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TextileBackup.config.maxSize > 0 && FileUtils.sizeOfDirectory(root) / 1024 > TextileBackup.config.maxSize) {
|
if (TextileBackup.config.maxSize > 0 && FileUtils.sizeOfDirectory(root) / 1024 > TextileBackup.config.maxSize) {
|
||||||
Arrays.stream(root.listFiles()).filter(File::isFile).sorted().forEach(e -> {
|
Arrays.stream(root.listFiles())
|
||||||
if (FileUtils.sizeOfDirectory(root) / 1024 > TextileBackup.config.maxSize) {
|
.filter(BackupHelper::isFileOk)
|
||||||
Utilities.info("Deleting: " + e.getName(), ctx);
|
.filter(f -> Utilities.getFileCreationTime(f).isPresent())
|
||||||
e.delete();
|
.sorted(Comparator.comparing(f -> Utilities.getFileCreationTime(f).get()))
|
||||||
}
|
.takeWhile(f -> FileUtils.sizeOfDirectory(root) / 1024 > TextileBackup.config.maxSize)
|
||||||
|
.forEach(f -> {
|
||||||
|
if(f.delete())
|
||||||
|
Utilities.info("Deleting: " + f.getName(), ctx);
|
||||||
|
else
|
||||||
|
Utilities.sendError("Something went wrong while deleting: " + f.getName(), ctx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getFileExtension(File f) {
|
private static boolean isFileOk(File f) {return f.exists() && f.isFile(); }
|
||||||
String[] parts = f.getName().split("\\.");
|
|
||||||
|
|
||||||
switch (parts[parts.length - 1]) {
|
|
||||||
case "zip":
|
|
||||||
return ConfigHandler.ArchiveFormat.ZIP.getExtension();
|
|
||||||
case "bz2":
|
|
||||||
return ConfigHandler.ArchiveFormat.BZIP2.getExtension();
|
|
||||||
case "gz":
|
|
||||||
return ConfigHandler.ArchiveFormat.GZIP.getExtension();
|
|
||||||
case "xz":
|
|
||||||
return ConfigHandler.ArchiveFormat.LZMA.getExtension();
|
|
||||||
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static File getBackupRootPath(String worldName) {
|
public static File getBackupRootPath(String worldName) {
|
||||||
File path = new File(TextileBackup.config.path).getAbsoluteFile();
|
File path = new File(TextileBackup.config.path).getAbsoluteFile();
|
||||||
|
|
|
@ -51,7 +51,7 @@ public class MakeBackupThread implements Runnable {
|
||||||
|
|
||||||
File world = ((MinecraftServerSessionAccessor)server)
|
File world = ((MinecraftServerSessionAccessor)server)
|
||||||
.getSession()
|
.getSession()
|
||||||
.method_27424(RegistryKey.of(Registry.DIMENSION, DimensionType.OVERWORLD_REGISTRY_KEY.getValue()));
|
.getWorldDirectory(RegistryKey.of(Registry.DIMENSION, DimensionType.OVERWORLD_REGISTRY_KEY.getValue()));
|
||||||
|
|
||||||
TextileBackup.LOGGER.trace("Minecraft world is: {}", world);
|
TextileBackup.LOGGER.trace("Minecraft world is: {}", world);
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,19 @@ import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.command.ServerCommandSource;
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
import net.minecraft.text.LiteralText;
|
import net.minecraft.text.LiteralText;
|
||||||
import net.minecraft.util.Formatting;
|
import net.minecraft.util.Formatting;
|
||||||
|
import net.szum123321.textile_backup.ConfigHandler;
|
||||||
import net.szum123321.textile_backup.TextileBackup;
|
import net.szum123321.textile_backup.TextileBackup;
|
||||||
import net.szum123321.textile_backup.mixin.MinecraftServerSessionAccessor;
|
import net.szum123321.textile_backup.mixin.MinecraftServerSessionAccessor;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.attribute.FileTime;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public class Utilities {
|
public class Utilities {
|
||||||
public static String getLevelName(MinecraftServer server) {
|
public static String getLevelName(MinecraftServer server) {
|
||||||
|
@ -35,6 +43,55 @@ public class Utilities {
|
||||||
return System.getProperty("os.name").toLowerCase().contains("win");
|
return System.getProperty("os.name").toLowerCase().contains("win");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Optional<String> getFileExtension(File f) {
|
||||||
|
String[] parts = f.getName().split("\\.");
|
||||||
|
|
||||||
|
switch (parts[parts.length - 1]) {
|
||||||
|
case "zip":
|
||||||
|
return Optional.of(ConfigHandler.ArchiveFormat.ZIP.getExtension());
|
||||||
|
case "bz2":
|
||||||
|
return Optional.of(ConfigHandler.ArchiveFormat.BZIP2.getExtension());
|
||||||
|
case "gz":
|
||||||
|
return Optional.of(ConfigHandler.ArchiveFormat.GZIP.getExtension());
|
||||||
|
case "xz":
|
||||||
|
return Optional.of(ConfigHandler.ArchiveFormat.LZMA.getExtension());
|
||||||
|
|
||||||
|
default:
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<LocalDateTime> getFileCreationTime(File file) {
|
||||||
|
LocalDateTime creationTime = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
FileTime fileTime = (FileTime) Files.getAttribute(file.toPath(), "creationTime");
|
||||||
|
creationTime = LocalDateTime.ofInstant(fileTime.toInstant(), ZoneOffset.systemDefault());
|
||||||
|
} catch (IOException ignored) {}
|
||||||
|
|
||||||
|
if(creationTime == null) {
|
||||||
|
try {
|
||||||
|
creationTime = LocalDateTime.from(
|
||||||
|
Utilities.getDateTimeFormatter().parse(
|
||||||
|
file.getName().split(getFileExtension(file).orElseThrow())[0].split("#")[0]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} catch (Exception ignored2) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(creationTime == null) {
|
||||||
|
try {
|
||||||
|
creationTime = LocalDateTime.from(
|
||||||
|
Utilities.getBackupDateTimeFormatter().parse(
|
||||||
|
file.getName().split(getFileExtension(file).orElseThrow())[0].split("#")[0]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} catch (Exception ignored3){}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.ofNullable(creationTime);
|
||||||
|
}
|
||||||
|
|
||||||
public static DateTimeFormatter getDateTimeFormatter(){
|
public static DateTimeFormatter getDateTimeFormatter(){
|
||||||
if(!TextileBackup.config.dateTimeFormat.equals(""))
|
if(!TextileBackup.config.dateTimeFormat.equals(""))
|
||||||
return DateTimeFormatter.ofPattern(TextileBackup.config.dateTimeFormat);
|
return DateTimeFormatter.ofPattern(TextileBackup.config.dateTimeFormat);
|
||||||
|
|
Loading…
Reference in New Issue