Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Variable Backup Files Purger #6851

Merged
merged 46 commits into from
Oct 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
dd20c5f
Starter Commits
TheAbsolutionism Jul 2, 2024
1479d21
Commit 2
TheAbsolutionism Jul 2, 2024
586f721
Commit 3
TheAbsolutionism Jul 2, 2024
67f110f
Removed un-needed import + details to config
TheAbsolutionism Jul 2, 2024
d421955
Fixed config.sk
TheAbsolutionism Jul 3, 2024
2e06165
Suggestion Changes
TheAbsolutionism Jul 7, 2024
de7a3ec
Revert
TheAbsolutionism Jul 7, 2024
9c9d831
Config Update
TheAbsolutionism Jul 7, 2024
60f2dbd
One Liner Change
TheAbsolutionism Jul 8, 2024
ddd3418
More Changes...
TheAbsolutionism Jul 10, 2024
4d2928c
Fixed Integer.class
TheAbsolutionism Jul 10, 2024
c0b1989
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Jul 10, 2024
29124bd
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Jul 12, 2024
283a73c
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Jul 12, 2024
cc7bf6d
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Jul 15, 2024
7833551
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Jul 19, 2024
10dc7e5
Merge branch 'dev/feature' into dev/backup-purge
sovdeeth Jul 24, 2024
effb895
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Jul 28, 2024
3e82791
Config Typos Fixed
TheAbsolutionism Aug 1, 2024
7615872
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Aug 2, 2024
0cad3b4
Disable Backups
TheAbsolutionism Aug 6, 2024
010b82b
Test Class
TheAbsolutionism Aug 8, 2024
ef38316
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Aug 8, 2024
1dc353e
Requested Changes
TheAbsolutionism Aug 11, 2024
9bb0702
IllegalArgumentException
TheAbsolutionism Aug 11, 2024
a068435
Requested Changes
TheAbsolutionism Aug 15, 2024
40e2944
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Aug 15, 2024
f6abc7a
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Aug 19, 2024
c67b3a8
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Aug 25, 2024
bc793b9
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Aug 30, 2024
a855ea5
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Aug 30, 2024
8ac9b78
Parameter Name Change
TheAbsolutionism Aug 30, 2024
68e96c9
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Sep 1, 2024
a851250
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Sep 2, 2024
6999b1c
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Sep 3, 2024
1d761e8
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Sep 9, 2024
4b91d6a
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Sep 19, 2024
58517fd
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Sep 21, 2024
8d451b7
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Sep 22, 2024
c618d19
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Sep 22, 2024
7331881
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Oct 1, 2024
6d100ca
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Oct 2, 2024
15a552e
Merge branch 'dev/feature' into dev/backup-purge
TheAbsolutionism Oct 6, 2024
38024f0
Fix Indentation
TheAbsolutionism Oct 6, 2024
09f4cd7
Merge branch 'dev/backup-purge' of https://github.com/TheAbsolutionis…
TheAbsolutionism Oct 6, 2024
9881981
Merge branch 'dev/feature' into dev/backup-purge
sovdeeth Oct 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 39 additions & 11 deletions src/main/java/ch/njol/skript/util/FileUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,18 @@
import java.nio.file.StandardCopyOption;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;

import org.skriptlang.skript.lang.converter.Converter;


/**
* @author Peter Güttinger
*/
public abstract class FileUtils {

private static boolean RUNNINGJAVA6 = true;// = System.getProperty("java.version").startsWith("1.6"); // doesn't work reliably?
static {
try {
Expand All @@ -47,11 +50,11 @@ public abstract class FileUtils {
RUNNINGJAVA6 = false;
}
}

private FileUtils() {}

private final static SimpleDateFormat backupFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");

/**
* @return The current date and time
*/
Expand All @@ -60,7 +63,32 @@ public static String getBackupSuffix() {
return "" + backupFormat.format(System.currentTimeMillis());
}
}


/**
* Deletes files in backup directory to meet desired target, starting from oldest to newest
*
* @param csvFile Variable file in order to get 'backups' directory
* @param toKeep Integer of how many files are to be left remaining
* @throws IOException If 'backups' directory is not found
* @throws IllegalArgumentException If 'toKeep' parameter is less than 0
*/
public static void backupPurge(File varFile, int toKeep) throws IOException, IllegalArgumentException {
if (toKeep < 0)
throw new IllegalArgumentException("Called with invalid input, 'toKeep' can not be less than 0");
File backupDir = new File(varFile.getParentFile(), "backups" + File.separator);
if (!backupDir.exists() || !backupDir.isDirectory())
throw new IOException("Backup directory not found");
ArrayList<File> files = new ArrayList<File>(Arrays.asList(backupDir.listFiles()));
if (files == null || files.size() <= toKeep)
return;
if (toKeep > 0)
files.sort(Comparator.comparingLong(File::lastModified));
int numberToRemove = files.size() - toKeep;
for (int i = 0; i < numberToRemove; i++) {
files.get(i).delete();
}
}

public static File backup(final File f) throws IOException {
String name = f.getName();
final int c = name.lastIndexOf('.');
Expand All @@ -76,7 +104,7 @@ public static File backup(final File f) throws IOException {
copy(f, backup);
return backup;
}

public static File move(final File from, final File to, final boolean replace) throws IOException {
if (!replace && to.exists())
throw new IOException("Can't rename " + from.getName() + " to " + to.getName() + ": The target file already exists");
Expand Down Expand Up @@ -105,7 +133,7 @@ public static File move(final File from, final File to, final boolean replace) t
}
return to;
}

public static void copy(final File from, final File to) throws IOException {
if (!RUNNINGJAVA6) {
Files.copy(from.toPath(), to.toPath(), StandardCopyOption.COPY_ATTRIBUTES);
Expand Down Expand Up @@ -135,7 +163,7 @@ public static void copy(final File from, final File to) throws IOException {
}
}
}

/**
* @param directory
* @param renamer Renames files. Return null to leave a file as-is.
Expand All @@ -161,10 +189,10 @@ public static Collection<File> renameAll(final File directory, final Converter<S
}
return changed;
}

/**
* Saves the contents of an InputStream in a file.
*
*
* @param in The InputStream to read from. This stream will not be closed when this method returns.
* @param file The file to save to. Will be replaced if it exists, or created if it doesn't.
* @throws IOException
Expand All @@ -184,5 +212,5 @@ public static void save(final InputStream in, final File file) throws IOExceptio
out.close();
}
}

}
30 changes: 26 additions & 4 deletions src/main/java/ch/njol/skript/variables/VariablesStorage.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
* @see DatabaseStorage
*/
// FIXME ! large databases (>25 MB) cause the server to be unresponsive instead of loading slowly
@SuppressWarnings("SuspiciousIndentAfterControlStatement")
public abstract class VariablesStorage implements Closeable {

/**
Expand Down Expand Up @@ -224,9 +225,24 @@ public final boolean load(SectionNode sectionNode) {
// Set the backup interval, if present & enabled
if (!"0".equals(getValue(sectionNode, "backup interval"))) {
Timespan backupInterval = getValue(sectionNode, "backup interval", Timespan.class);

int toKeep = getValue(sectionNode, "backups to keep", Integer.class);
boolean removeBackups = false;
boolean startBackup = true;
if (backupInterval != null)
startBackupTask(backupInterval);
if (toKeep == 0) {
startBackup = false;
} else if (toKeep >= 1) {
removeBackups = true;
}
if (startBackup) {
startBackupTask(backupInterval, removeBackups, toKeep);
} else {
try {
FileUtils.backupPurge(file, toKeep);
} catch (IOException e) {
Skript.error("Variables backup wipe failed: " + e.getLocalizedMessage());
}
}
}
}

Expand Down Expand Up @@ -307,11 +323,10 @@ public final boolean load(SectionNode sectionNode) {
*
* @param backupInterval the backup interval.
*/
public void startBackupTask(Timespan backupInterval) {
public void startBackupTask(Timespan backupInterval, boolean removeBackups, int toKeep) {
// File is null or backup interval is invalid
if (file == null || backupInterval.getTicks() == 0)
return;

backupTask = new Task(Skript.getInstance(), backupInterval.getTicks(), backupInterval.getTicks(), true) {
@Override
public void run() {
Expand All @@ -321,6 +336,13 @@ public void run() {
try {
// ..., then backup
FileUtils.backup(file);
if (removeBackups) {
try {
FileUtils.backupPurge(file, toKeep);
} catch (IOException | IllegalArgumentException e) {
Skript.error("Automatic variables backup purge failed: " + e.getLocalizedMessage());
}
}
} catch (IOException e) {
Skript.error("Automatic variables backup failed: " + e.getLocalizedMessage());
} finally {
Expand Down
11 changes: 11 additions & 0 deletions src/main/resources/config.sk
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,12 @@ databases:
# Variables are saved constantly no matter what is set here, thus a server crash will never make you loose any variables.
# Set this to 0 to disable this feature.

backups to keep: -1
# if set to a value greater than -1, Skript will ensure only that many backups are kept.
# Backups are removed from oldest to newest.
# If disabled (set to -1), no backup files will be deleted.
# WARNING: Setting to 0 will delete all files located in the backup directory upon plugin start/reload


MySQL example:
# A MySQL database example, with options unrelated to MySQL removed.
Expand Down Expand Up @@ -325,6 +331,8 @@ databases:
monitor changes: false
monitor interval: 20 seconds

backups to keep: -1
TheLimeGlass marked this conversation as resolved.
Show resolved Hide resolved

default:
# The default "database" is a simple text file, with each variable on a separate line and the variable's name, type, and value separated by commas.
# This is the last database in this list to catch all variables that have not been saved anywhere else.
Expand All @@ -338,6 +346,9 @@ databases:

backup interval: 2 hours

backups to keep: -1


# PS: If you don't want some variables to be saved in any database (e.g. variables that contain an %entity% which usually despawn when the server is shut down)
# you can modify the last database's pattern to not match all variables, e.g. use '(?!x_).*' to match all variables that don't start with 'x_'.
# Be very cautious when doing this however as unsaved variables cannot be recovered after the server has been stopped.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.skriptlang.skript.test.tests.files;

import ch.njol.skript.util.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;

public class BackupPurgeTest {

@Test
public void testPurge() throws IOException {
File dir = new File("plugins/Skript/backups/");
if (!dir.exists()) {
dir.mkdir();
}

File vars = new File("plugins/Skript/variables.csv");
if (!vars.exists()) {
vars.createNewFile();
}

// Create Filler Files to be used for testing
for (int i = 0; i < 100; i++) {
(new File(dir, ("PurgeTest_"+i))).createNewFile();
}
// Test 100 filler files were created
assertEquals("Filler Files != 100", 100, (new ArrayList<File>(Arrays.asList(dir.listFiles()))).size());

// Test 'backupPurge' method deleting to 50
FileUtils.backupPurge(vars, 50);
assertEquals("Backup Purge did not delete down to 50", 50, (new ArrayList<File>(Arrays.asList(dir.listFiles()))).size());

// Test 'backupPurge' method deleting to 20
FileUtils.backupPurge(vars, 20);
assertEquals("Backup Purge did not delete down to 20", 20, (new ArrayList<File>(Arrays.asList(dir.listFiles()))).size());

// Test 'backupPurge' method deleting all files
FileUtils.backupPurge(vars, 0);
assertEquals("Backup Purge did not delete all files", 0, (new ArrayList<File>(Arrays.asList(dir.listFiles()))).size());

// Test calling with invalid input
assertThrows("Backup Purge did not throw exception for invalid input", IllegalArgumentException.class, () -> FileUtils.backupPurge(vars, -1));

}

}