Adds code for config migration with comment retaining
All checks were successful
KnarCraft/KnarLib/pipeline/head This commit looks good

This commit is contained in:
2025-09-05 19:09:29 +02:00
parent b408b0ebb3
commit 1b21f7a939
2 changed files with 458 additions and 0 deletions

View File

@@ -0,0 +1,162 @@
package net.knarcraft.knarlib.util;
import net.knarcraft.knarlib.config.StargateYamlConfiguration;
import net.knarcraft.knarlib.property.ColorConversion;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.MemorySection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.logging.Level;
/**
* A helper class for dealing with a plugin's configuration file
*/
@SuppressWarnings("unused")
public final class ConfigHelper {
private static final String CONFIG_FILE = "config.yml";
private static final String BACKUP_CONFIG_FILE = "config.yml.old";
private static final String MIGRATION_FILE = "config-migrations.txt";
private ConfigHelper() {
}
/**
* Gets the relative string path of the configuration file
*
* @return <p>The configuration file path</p>
*/
public static String getConfigFile() {
return CONFIG_FILE;
}
/**
* Saves any missing configuration values to the given plugin's configuration
*
* @param plugin <p>The plugin to add missing default values to</p>
*/
public static void saveDefaults(@NotNull Plugin plugin) {
plugin.saveDefaultConfig();
plugin.getConfig().options().copyDefaults(true);
plugin.reloadConfig();
plugin.saveConfig();
}
/**
* Changes all configuration values from the old name to the new name
*
* <p>Note: This method expects a file "config-migrations.txt" in the resources directory that contains mappings:
* oldKey=replacementKey in order to migrate from old to new configuration values.
* The old configuration file will be saved to config.yml.old</p>
*
* @param plugin <p>The plugin to migrate the configuration for</p>
* @return <p>True if the migration succeeded without any issues</p>
*/
public static boolean migrateConfig(@NotNull Plugin plugin) {
File dataFolder = plugin.getDataFolder();
//Save the old config just in case something goes wrong
try {
StargateYamlConfiguration currentConfiguration = new StargateYamlConfiguration();
currentConfiguration.load(new File(dataFolder, CONFIG_FILE));
currentConfiguration.save(new File(dataFolder, BACKUP_CONFIG_FILE));
} catch (IOException | InvalidConfigurationException exception) {
plugin.getLogger().log(Level.WARNING, "Unable to save old backup and do migration");
return false;
}
//Load old and new configuration
plugin.reloadConfig();
FileConfiguration oldConfiguration = plugin.getConfig();
InputStream configStream = FileHelper.getInputStreamForInternalFile("/" + CONFIG_FILE);
if (configStream == null) {
plugin.getLogger().log(Level.SEVERE, "Could not migrate the configuration, as the internal " +
"configuration could not be read!");
return false;
}
YamlConfiguration newConfiguration = StargateYamlConfiguration.loadConfiguration(
FileHelper.getBufferedReaderFromInputStream(configStream));
//Read all available config migrations
Map<String, String> migrationFields;
try {
InputStream migrationStream = FileHelper.getInputStreamForInternalFile("/" + MIGRATION_FILE);
if (migrationStream == null) {
plugin.getLogger().log(Level.SEVERE, "Could not migrate the configuration, as the internal " +
"migration paths could not be read!");
return false;
}
migrationFields = FileHelper.readKeyValuePairs(FileHelper.getBufferedReaderFromInputStream(migrationStream),
"=", ColorConversion.NONE);
} catch (IOException exception) {
plugin.getLogger().log(Level.WARNING, "Unable to load config migration file");
return false;
}
//Replace old config names with the new ones
for (String key : migrationFields.keySet()) {
if (oldConfiguration.contains(key)) {
migrateProperty(migrationFields, key, oldConfiguration);
}
}
// Copy all keys to the new config
for (String key : StargateYamlConfiguration.getKeysWithoutComments(oldConfiguration, true)) {
if (oldConfiguration.get(key) instanceof MemorySection) {
continue;
}
newConfiguration.set(key, oldConfiguration.get(key));
}
try {
newConfiguration.save(new File(dataFolder, CONFIG_FILE));
} catch (IOException exception) {
plugin.getLogger().log(Level.WARNING, "Unable to save migrated config");
return false;
}
plugin.reloadConfig();
return true;
}
/**
* Migrates one configuration property
*
* @param migrationFields <p>The configuration fields to be migrated</p>
* @param key <p>The key/path of the property to migrate</p>
* @param oldConfiguration <p>The original pre-migration configuration</p>
*/
private static void migrateProperty(@NotNull Map<String, String> migrationFields, @NotNull String key,
@NotNull FileConfiguration oldConfiguration) {
String newPath = migrationFields.get(key);
Object oldValue = oldConfiguration.get(key);
if (!newPath.trim().isEmpty()) {
if (oldConfiguration.isConfigurationSection(key)) {
// Copy each value of a configuration section
ConfigurationSection sourceSection = oldConfiguration.getConfigurationSection(key);
ConfigurationSection destinationSection = oldConfiguration.createSection(newPath);
if (sourceSection == null) {
return;
}
for (String path : StargateYamlConfiguration.getKeysWithoutComments(sourceSection, true)) {
destinationSection.set(path, sourceSection.get(path));
}
} else {
// Copy the value to the new path
oldConfiguration.set(newPath, oldValue);
}
}
// Remove the old path's value
oldConfiguration.set(key, null);
}
}