mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-12-18 22:57:47 +01:00
#1467 Create backup before migrating; output newly added message keys
- Extract logic for creating a backup timestamp into FileUtils
This commit is contained in:
parent
ffeb04c0a2
commit
9dd4039fdd
@ -1,5 +1,6 @@
|
|||||||
package fr.xephi.authme.datasource;
|
package fr.xephi.authme.datasource;
|
||||||
|
|
||||||
|
import com.google.common.io.Files;
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.settings.Settings;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
||||||
@ -8,14 +9,10 @@ import fr.xephi.authme.util.FileUtils;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.DatabaseMetaData;
|
import java.sql.DatabaseMetaData;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Migrates the SQLite database when necessary.
|
* Migrates the SQLite database when necessary.
|
||||||
@ -70,11 +67,10 @@ class SqLiteMigrater {
|
|||||||
File backupDirectory = new File(dataFolder, "backups");
|
File backupDirectory = new File(dataFolder, "backups");
|
||||||
FileUtils.createDirectory(backupDirectory);
|
FileUtils.createDirectory(backupDirectory);
|
||||||
|
|
||||||
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm");
|
String backupName = "backup-" + databaseName + FileUtils.createCurrentTimeString() + ".db";
|
||||||
String backupName = "backup-" + databaseName + dateFormat.format(new Date()) + ".db";
|
|
||||||
File backup = new File(backupDirectory, backupName);
|
File backup = new File(backupDirectory, backupName);
|
||||||
try {
|
try {
|
||||||
Files.copy(sqLite.toPath(), backup.toPath());
|
Files.copy(sqLite, backup);
|
||||||
return backupName;
|
return backupName;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IllegalStateException("Failed to create SQLite backup before migration", e);
|
throw new IllegalStateException("Failed to create SQLite backup before migration", e);
|
||||||
|
@ -19,7 +19,7 @@ import java.util.Objects;
|
|||||||
* Implementation of {@link PropertyReader} which can read a file or a stream with
|
* Implementation of {@link PropertyReader} which can read a file or a stream with
|
||||||
* a specified charset.
|
* a specified charset.
|
||||||
*/
|
*/
|
||||||
public class MessageMigraterPropertyReader implements PropertyReader {
|
public final class MessageMigraterPropertyReader implements PropertyReader {
|
||||||
|
|
||||||
public static final Charset CHARSET = StandardCharsets.UTF_8;
|
public static final Charset CHARSET = StandardCharsets.UTF_8;
|
||||||
|
|
||||||
@ -31,6 +31,12 @@ public class MessageMigraterPropertyReader implements PropertyReader {
|
|||||||
root = valuesMap;
|
root = valuesMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new property reader for the given file.
|
||||||
|
*
|
||||||
|
* @param file the file to load
|
||||||
|
* @return the created property reader
|
||||||
|
*/
|
||||||
public static MessageMigraterPropertyReader loadFromFile(File file) {
|
public static MessageMigraterPropertyReader loadFromFile(File file) {
|
||||||
Map<String, Object> valuesMap;
|
Map<String, Object> valuesMap;
|
||||||
try (InputStream is = new FileInputStream(file)) {
|
try (InputStream is = new FileInputStream(file)) {
|
||||||
|
@ -7,12 +7,17 @@ import ch.jalu.configme.properties.Property;
|
|||||||
import ch.jalu.configme.properties.StringProperty;
|
import ch.jalu.configme.properties.StringProperty;
|
||||||
import ch.jalu.configme.resource.YamlFileResource;
|
import ch.jalu.configme.resource.YamlFileResource;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.io.Files;
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
|
import fr.xephi.authme.util.FileUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -60,6 +65,8 @@ public class MessageUpdater {
|
|||||||
boolean addedMissingKeys = addMissingKeys(jarMessageSource, userResource);
|
boolean addedMissingKeys = addMissingKeys(jarMessageSource, userResource);
|
||||||
|
|
||||||
if (movedOldKeys || addedMissingKeys) {
|
if (movedOldKeys || addedMissingKeys) {
|
||||||
|
backupMessagesFile(userFile);
|
||||||
|
|
||||||
SettingsManager settingsManager = new SettingsManager(userResource, null, CONFIGURATION_DATA);
|
SettingsManager settingsManager = new SettingsManager(userResource, null, CONFIGURATION_DATA);
|
||||||
settingsManager.save();
|
settingsManager.save();
|
||||||
ConsoleLogger.debug("Successfully saved {0}", userFile);
|
ConsoleLogger.debug("Successfully saved {0}", userFile);
|
||||||
@ -77,20 +84,32 @@ public class MessageUpdater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean addMissingKeys(JarMessageSource jarMessageSource, YamlFileResource userResource) {
|
private boolean addMissingKeys(JarMessageSource jarMessageSource, YamlFileResource userResource) {
|
||||||
int addedKeys = 0;
|
List<String> addedKeys = new ArrayList<>();
|
||||||
for (Property<?> property : CONFIGURATION_DATA.getProperties()) {
|
for (Property<?> property : CONFIGURATION_DATA.getProperties()) {
|
||||||
if (userResource.getString(property.getPath()) == null) {
|
final String key = property.getPath();
|
||||||
userResource.setValue(property.getPath(), jarMessageSource.getMessageFromJar(property));
|
if (userResource.getString(key) == null) {
|
||||||
++addedKeys;
|
userResource.setValue(key, jarMessageSource.getMessageFromJar(property));
|
||||||
|
addedKeys.add(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (addedKeys > 0) {
|
if (!addedKeys.isEmpty()) {
|
||||||
ConsoleLogger.info("Added " + addedKeys + " missing keys to your messages_xx.yml file");
|
ConsoleLogger.info(
|
||||||
|
"Added " + addedKeys.size() + " missing keys to your messages_xx.yml file: " + addedKeys);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void backupMessagesFile(File messagesFile) {
|
||||||
|
String backupName = FileUtils.createBackupFilePath(messagesFile);
|
||||||
|
File backupFile = new File(backupName);
|
||||||
|
try {
|
||||||
|
Files.copy(messagesFile, backupFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IllegalStateException("Could not back up '" + messagesFile + "' to '" + backupFile + "'", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs the {@link ConfigurationData} for exporting a messages file in its entirety.
|
* Constructs the {@link ConfigurationData} for exporting a messages file in its entirety.
|
||||||
*
|
*
|
||||||
|
@ -16,8 +16,6 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import static fr.xephi.authme.util.Utils.logAndSendMessage;
|
import static fr.xephi.authme.util.Utils.logAndSendMessage;
|
||||||
import static fr.xephi.authme.util.Utils.logAndSendWarning;
|
import static fr.xephi.authme.util.Utils.logAndSendWarning;
|
||||||
@ -27,7 +25,6 @@ import static fr.xephi.authme.util.Utils.logAndSendWarning;
|
|||||||
*/
|
*/
|
||||||
public class BackupService {
|
public class BackupService {
|
||||||
|
|
||||||
private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm");
|
|
||||||
private final File dataFolder;
|
private final File dataFolder;
|
||||||
private final File backupFolder;
|
private final File backupFolder;
|
||||||
private final Settings settings;
|
private final Settings settings;
|
||||||
@ -181,7 +178,7 @@ public class BackupService {
|
|||||||
* @return the file to back up the data to
|
* @return the file to back up the data to
|
||||||
*/
|
*/
|
||||||
private File constructBackupFile(String fileExtension) {
|
private File constructBackupFile(String fileExtension) {
|
||||||
String dateString = dateFormat.format(new Date());
|
String dateString = FileUtils.createCurrentTimeString();
|
||||||
return new File(backupFolder, "backup" + dateString + "." + fileExtension);
|
return new File(backupFolder, "backup" + dateString + "." + fileExtension);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
package fr.xephi.authme.util;
|
package fr.xephi.authme.util;
|
||||||
|
|
||||||
|
import com.google.common.io.Files;
|
||||||
import fr.xephi.authme.AuthMe;
|
import fr.xephi.authme.AuthMe;
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.file.Files;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
import static java.lang.String.format;
|
import static java.lang.String.format;
|
||||||
|
|
||||||
@ -15,6 +17,9 @@ import static java.lang.String.format;
|
|||||||
*/
|
*/
|
||||||
public final class FileUtils {
|
public final class FileUtils {
|
||||||
|
|
||||||
|
private static final DateTimeFormatter CURRENT_DATE_STRING_FORMATTER =
|
||||||
|
DateTimeFormatter.ofPattern("yyyyMMdd_HHmm");
|
||||||
|
|
||||||
// Utility class
|
// Utility class
|
||||||
private FileUtils() {
|
private FileUtils() {
|
||||||
}
|
}
|
||||||
@ -40,7 +45,7 @@ public final class FileUtils {
|
|||||||
ConsoleLogger.warning(format("Cannot copy resource '%s' to file '%s': cannot load resource",
|
ConsoleLogger.warning(format("Cannot copy resource '%s' to file '%s': cannot load resource",
|
||||||
resourcePath, destinationFile.getPath()));
|
resourcePath, destinationFile.getPath()));
|
||||||
} else {
|
} else {
|
||||||
Files.copy(is, destinationFile.toPath());
|
java.nio.file.Files.copy(is, destinationFile.toPath());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -138,4 +143,28 @@ public final class FileUtils {
|
|||||||
public static String makePath(String... elements) {
|
public static String makePath(String... elements) {
|
||||||
return String.join(File.separator, elements);
|
return String.join(File.separator, elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a textual representation of the current time (including minutes), e.g. useful for
|
||||||
|
* automatically generated backup files.
|
||||||
|
*
|
||||||
|
* @return string of the current time for use in file names
|
||||||
|
*/
|
||||||
|
public static String createCurrentTimeString() {
|
||||||
|
return LocalDateTime.now().format(CURRENT_DATE_STRING_FORMATTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a path to a new file (which doesn't exist yet) with a timestamp in the name in the same
|
||||||
|
* folder as the given file and containing the given file's filename.
|
||||||
|
*
|
||||||
|
* @param file the file based on which a new file path should be created
|
||||||
|
* @return path to a file suitably named for storing a backup
|
||||||
|
*/
|
||||||
|
public static String createBackupFilePath(File file) {
|
||||||
|
String filename = "backup_" + Files.getNameWithoutExtension(file.getName())
|
||||||
|
+ "_" + createCurrentTimeString()
|
||||||
|
+ "." + Files.getFileExtension(file.getName());
|
||||||
|
return makePath(file.getParent(), filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.matchesPattern;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
@ -20,6 +21,9 @@ import static org.junit.Assert.assertThat;
|
|||||||
*/
|
*/
|
||||||
public class FileUtilsTest {
|
public class FileUtilsTest {
|
||||||
|
|
||||||
|
/** Regex that matches timestamps such as 20180211_1048. */
|
||||||
|
private static final String BACKUP_TIMESTAMP_PATTERN = "20\\d{6}_\\d{4}";
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void initLogger() {
|
public static void initLogger() {
|
||||||
TestHelper.setupLogger();
|
TestHelper.setupLogger();
|
||||||
@ -186,6 +190,29 @@ public class FileUtilsTest {
|
|||||||
TestHelper.validateHasOnlyPrivateEmptyConstructor(FileUtils.class);
|
TestHelper.validateHasOnlyPrivateEmptyConstructor(FileUtils.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateCurrentTimestampString() {
|
||||||
|
// given / when
|
||||||
|
String currentTimeString = FileUtils.createCurrentTimeString();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(currentTimeString, matchesPattern(BACKUP_TIMESTAMP_PATTERN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateBackupFile() {
|
||||||
|
// given
|
||||||
|
File file = new File("some/folders/config.yml");
|
||||||
|
|
||||||
|
// when
|
||||||
|
String backupFile = FileUtils.createBackupFilePath(file);
|
||||||
|
|
||||||
|
// then
|
||||||
|
String folders = String.join(File.separator,"some", "folders", "").replace("\\", "\\\\");
|
||||||
|
assertThat(backupFile, matchesPattern(folders + "backup_config_" + BACKUP_TIMESTAMP_PATTERN + "\\.yml"));
|
||||||
|
}
|
||||||
|
|
||||||
private static void createFiles(File... files) throws IOException {
|
private static void createFiles(File... files) throws IOException {
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
boolean result = file.getParentFile().mkdirs() & file.createNewFile();
|
boolean result = file.getParentFile().mkdirs() & file.createNewFile();
|
||||||
|
Loading…
Reference in New Issue
Block a user