173 lines
6.5 KiB
Java
173 lines
6.5 KiB
Java
package fr.xephi.authme.settings;
|
|
|
|
import com.google.common.annotations.VisibleForTesting;
|
|
import fr.xephi.authme.ConsoleLogger;
|
|
import fr.xephi.authme.settings.domain.Property;
|
|
import fr.xephi.authme.settings.properties.SettingsFieldRetriever;
|
|
import fr.xephi.authme.settings.propertymap.PropertyMap;
|
|
import fr.xephi.authme.util.CollectionUtils;
|
|
import fr.xephi.authme.util.StringUtils;
|
|
import org.bukkit.configuration.file.FileConfiguration;
|
|
import org.yaml.snakeyaml.DumperOptions;
|
|
import org.yaml.snakeyaml.Yaml;
|
|
|
|
import java.io.File;
|
|
import java.io.FileWriter;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
/**
|
|
* The new settings manager.
|
|
*/
|
|
public class NewSetting {
|
|
|
|
private File file;
|
|
private FileConfiguration configuration;
|
|
|
|
/**
|
|
* Constructor.
|
|
* Loads the file as YAML and checks its integrity.
|
|
*
|
|
* @param configuration The configuration to interact with
|
|
* @param file The configuration file
|
|
*/
|
|
public NewSetting(FileConfiguration configuration, File file) {
|
|
this.configuration = configuration;
|
|
this.file = file;
|
|
|
|
PropertyMap propertyMap = SettingsFieldRetriever.getAllPropertyFields();
|
|
if (SettingsMigrationService.checkAndMigrate(configuration, propertyMap)) {
|
|
ConsoleLogger.info("Merged new config options");
|
|
ConsoleLogger.info("Please check your config.yml file for new settings!");
|
|
save(propertyMap);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Constructor for testing purposes, allowing more options.
|
|
*
|
|
* @param configuration The FileConfiguration object to use
|
|
* @param file The file to write to
|
|
* @param propertyMap The property map whose properties should be verified for presence, or null to skip this
|
|
*/
|
|
@VisibleForTesting
|
|
NewSetting(FileConfiguration configuration, File file, PropertyMap propertyMap) {
|
|
this.configuration = configuration;
|
|
this.file = file;
|
|
|
|
if (propertyMap != null && SettingsMigrationService.checkAndMigrate(configuration, propertyMap)) {
|
|
save(propertyMap);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the given property from the configuration.
|
|
*
|
|
* @param property The property to retrieve
|
|
* @param <T> The property's type
|
|
* @return The property's value
|
|
*/
|
|
public <T> T getProperty(Property<T> property) {
|
|
return property.getFromFile(configuration);
|
|
}
|
|
|
|
public void save(PropertyMap propertyMap) {
|
|
try (FileWriter writer = new FileWriter(file)) {
|
|
writer.write("");
|
|
|
|
DumperOptions simpleOptions = new DumperOptions();
|
|
simpleOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
|
Yaml simpleYaml = new Yaml(simpleOptions);
|
|
DumperOptions singleQuoteOptions = new DumperOptions();
|
|
singleQuoteOptions.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED);
|
|
singleQuoteOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
|
Yaml singleQuoteYaml = new Yaml(singleQuoteOptions);
|
|
|
|
// Contains all but the last node of the setting, e.g. [DataSource, mysql] for "DataSource.mysql.username"
|
|
List<String> currentPath = new ArrayList<>();
|
|
for (Map.Entry<Property<?>, String[]> entry : propertyMap.entrySet()) {
|
|
Property<?> property = entry.getKey();
|
|
|
|
// Handle properties
|
|
List<String> propertyPath = Arrays.asList(property.getPath().split("\\."));
|
|
List<String> commonPathParts = CollectionUtils.filterCommonStart(
|
|
currentPath, propertyPath.subList(0, propertyPath.size() - 1));
|
|
List<String> newPathParts = CollectionUtils.getRange(propertyPath, commonPathParts.size());
|
|
|
|
if (commonPathParts.isEmpty()) {
|
|
writer.append("\n");
|
|
}
|
|
|
|
int indentationLevel = commonPathParts.size();
|
|
if (newPathParts.size() > 1) {
|
|
for (String path : newPathParts.subList(0, newPathParts.size() - 1)) {
|
|
writer.append("\n")
|
|
.append(indent(indentationLevel))
|
|
.append(path)
|
|
.append(": ");
|
|
++indentationLevel;
|
|
}
|
|
}
|
|
for (String comment : entry.getValue()) {
|
|
writer.append("\n")
|
|
.append(indent(indentationLevel))
|
|
.append("# ")
|
|
.append(comment);
|
|
}
|
|
writer.append("\n")
|
|
.append(indent(indentationLevel))
|
|
.append(CollectionUtils.getRange(newPathParts, newPathParts.size() - 1).get(0))
|
|
.append(": ")
|
|
.append(toYaml(property, indentationLevel, simpleYaml, singleQuoteYaml));
|
|
|
|
currentPath = propertyPath.subList(0, propertyPath.size() - 1);
|
|
}
|
|
writer.flush();
|
|
writer.close();
|
|
} catch (IOException e) {
|
|
ConsoleLogger.showError("Could not save config file - " + StringUtils.formatException(e));
|
|
ConsoleLogger.writeStackTrace(e);
|
|
}
|
|
}
|
|
|
|
private <T> String toYaml(Property<T> property, int indent, Yaml simpleYaml, Yaml singleQuoteYaml) {
|
|
T value = property.getFromFile(configuration);
|
|
String representation = property.hasSingleQuotes()
|
|
? singleQuoteYaml.dump(value)
|
|
: simpleYaml.dump(value);
|
|
|
|
// If the property is a non-empty list we need to append a new line because it will be
|
|
// something like the following, which requires a new line:
|
|
// - 'item 1'
|
|
// - 'second item in list'
|
|
if (property.isList() && !((List) value).isEmpty()) {
|
|
representation = "\n" + representation;
|
|
}
|
|
|
|
return join("\n" + indent(indent), representation.split("\\n"));
|
|
}
|
|
|
|
private static String join(String delimiter, String[] items) {
|
|
StringBuilder sb = new StringBuilder();
|
|
String delim = "";
|
|
for (String item : items) {
|
|
sb.append(delim).append(item);
|
|
delim = delimiter;
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
private static String indent(int level) {
|
|
// YAML uses indentation of 4 spaces
|
|
StringBuilder sb = new StringBuilder(level * 4);
|
|
for (int i = 0; i < level; ++i) {
|
|
sb.append(" ");
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
}
|