8000 Rework plugin config system #2 by DerEchtePilz · Pull Request #605 · CommandAPI/CommandAPI · GitHub
[go: up one dir, main page]

Skip to content

Rework plugin config system #2 #605

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

Merged
merged 10 commits into from
Oct 16, 2024
Merged
10 changes: 10 additions & 0 deletions commandapi-codecov/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@
<artifactId>commandapi-bukkit-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.jorel</groupId>
<artifactId>commandapi-plugin</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.jorel</groupId>
<artifactId>commandapi-bukkit-plugin-common</artifactId>
<version>${project.version}</version>
</dependency>

<!-- Code coverage the tests -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@
import java.util.Set;
import java.util.logging.Logger;

public record BukkitConfigurationAdapter(YamlConfiguration config) implements ConfigurationAdapter<YamlConfiguration> {
public class BukkitConfigurationAdapter extends ConfigurationAdapter<YamlConfiguration, DefaultBukkitConfig> {

private final YamlConfiguration config;

public BukkitConfigurationAdapter(YamlConfiguration config) {
this.config = config;
}

public static BukkitConfigurationAdapter createDummyInstance() {
return new BukkitConfigurationAdapter(null);
Expand Down Expand Up @@ -87,7 +93,7 @@ public void tryCreateSection(String key) {
}

@Override
public ConfigurationAdapter<YamlConfiguration> complete() {
public ConfigurationAdapter<YamlConfiguration, DefaultBukkitConfig> complete() {
String[] configStrings = config.saveToString().split("\n");
StringBuilder configBuilder = new StringBuilder();
for (String configString : configStrings) {
Expand All @@ -105,49 +111,29 @@ public ConfigurationAdapter<YamlConfiguration> complete() {
}

@Override
public ConfigurationAdapter<YamlConfiguration> createNew() {
public YamlConfiguration config() {
return config;
}

@Override
public ConfigurationAdapter<YamlConfiguration, DefaultBukkitConfig> createNew() {
return new BukkitConfigurationAdapter(new YamlConfiguration());
}

@Override
public void saveDefaultConfig(File directory, File configFile, Logger logger) {
ConfigGenerator configGenerator = ConfigGenerator.createNew(DefaultBukkitConfig.createDefault());
if (!directory.exists()) {
boolean createdDirectory = directory.mkdirs();
if (!createdDirectory) {
logger.severe("Failed to create directory for the CommandAPI's config.yml file!");
}
try {
ConfigurationAdapter<YamlConfiguration> bukkitConfigurationAdapter = new BukkitConfigurationAdapter(new YamlConfiguration());
configGenerator.populateDefaultConfig(bukkitConfigurationAdapter);
bukkitConfigurationAdapter.config().save(configFile);
} catch (IOException e) {
logger.severe("Could not create default config file! This is (probably) a bug.");
logger.severe("Error message: " + e.getMessage());
logger.severe("Stacktrace:");
for (StackTraceElement element : e.getStackTrace()) {
logger.severe(element.toString());
}
}
return;
}
// Update the config if necessary
try {
YamlConfiguration existingYamlConfig = YamlConfiguration.loadConfiguration(configFile);
ConfigurationAdapter<YamlConfiguration> existingConfig = new BukkitConfigurationAdapter(existingYamlConfig);
ConfigurationAdapter<YamlConfiguration> updatedConfig = configGenerator.generateWithNewValues(existingConfig);
if (updatedConfig == null) {
return;
}
updatedConfig.config().save(configFile);
} catch (IOException e) {
logger.severe("Could not update config! This is (probably) a bug.");
logger.severe("Error message: " + e.getMessage());
logger.severe("Stacktrace:");
for (StackTraceElement element : e.getStackTrace()) {
logger.severe(element.toString());
}
}
public DefaultBukkitConfig createDefaultConfig() {
return DefaultBukkitConfig.createDefault();
}

@Override
public ConfigurationAdapter<YamlConfiguration, DefaultBukkitConfig> loadFromFile(File file) {
YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
return new BukkitConfigurationAdapter(config);
}

@Override
public void saveToFile(File file) throws IOException {
config.save(file);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@
<artifactId>commandapi-bukkit-test-impl</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.jorel</groupId>
<artifactId>commandapi-bukkit-plugin-common</artifactId>
<version>${project.version}</version>
</dependency>

<!-- NBT API implementations (in no particular order) -->
<dependency>
Expand Down
< 8000 td id="diff-21dd1ae62f0e252febd3dc5b0a5ce9ae1d559924ffbf21fada0cbb50be47d5a9R147" data-line-number="147" class="blob-num blob-num-addition js-linkable-line-number js-blob-rnum">
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
package dev.jorel.commandapi.test;

import dev.jorel.commandapi.config.BukkitConfigurationAdapter;
import dev.jorel.commandapi.config.CommentedConfigOption;
import dev.jorel.commandapi.config.CommentedSection;
import dev.jorel.commandapi.config.ConfigGenerator;
import dev.jorel.commandapi.config.ConfigurationAdapter;
import dev.jorel.commandapi.config.DefaultBukkitConfig;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

class ConfigGenerationTests {

private CommentedConfigOption<Boolean> silentLogs;
private CommentedConfigOption<Boolean> verboseOutputs;
private CommentedConfigOption<String> missingExecutorImplementation;

private CommentedSection messages;

private ConfigGenerator generator;
private DefaultBukkitConfig bukkitConfig;
private BukkitConfigurationAdapter adapter;

@BeforeEach
public void setup() {
silentLogs = new CommentedConfigOption<>(new String[]{
"Silent logs (default: false)",
"If \"true\", turns off all logging from the CommandAPI, except for errors."
}, false);
verboseOutputs = new CommentedConfigOption<>(new String[]{
"Verbose outputs (default: false)",
"If \"true\", outputs command registration and unregistration logs in the console"
}, false);
missingExecutorImplementation = new CommentedConfigOption<>(new String[]{
"Missing executor implementation (default: \"This command has no implementations for %s\")",
"The message to display to senders when a command has no executor. Available",
"parameters are:",
" %s - the executor class (lowercase)",
" %S - the executor class (normal case)"
}, "This command has no implementations for %s");

messages = new CommentedSection(new String[]{
"Messages",
"Controls messages that the CommandAPI displays to players"
});

Map<String, CommentedConfigOption<?>> options = new LinkedHashMap<>();
options.put("silent-logs", silentLogs);
options.put("verbose-outputs", verboseOutputs);
options.put("messages.missing-executor-implementation", missingExecutorImplementation);

Map<String, CommentedSection> sections = new LinkedHashMap<>();
sections.put("messages", messages);

ConfigurationAdapter<YamlConfiguration, DefaultBukkitConfig> adapter = new BukkitConfigurationAdapter(new YamlConfiguration());
bukkitConfig = DefaultBukkitConfig.create(options, sections);
generator = ConfigGenerator.createNew(bukkitConfig);
this.adapter = (BukkitConfigurationAdapter) generator.generate(adapter);
}

@AfterEach
public void reset() {
this.silentLogs = null;
this.verboseOutputs = null;
this.missingExecutorImplementation = null;
this.messages = null;
this.generator = null;
this.bukkitConfig = null;
this.adapter = null;
}

// Test methods
private void validateConfigOptions(Set<String> options, BukkitConfigurationAdapter adapter) {
for (String option : options) {
assertTrue(adapter.contains(option), "Config option '" + option + "' does not exist!");
}
}

private void validateConfigOptionComments(Map<String, String[]> comments, BukkitConfigurationAdapter adapter) {
for (String option : comments.keySet()) {
String[] expectedComment = comments.get(option);
String[] generatedComment = adapter.getComment(option);
assertArrayEquals(expectedComment, generatedComment, "Config option comment for option '" + option + "' does not exist or was incorrect!");
}
}

private void validateConfigOptionsAbsent(Set<String> options, BukkitConfigurationAdapter adapter) {
for (String option : options) {
assertFalse(adapter.contains(option), "Config option '" + option + "' does still exist!");
}
}

private void validateSections(List<String> sections, String expectedOption, YamlConfiguration config) {
ConfigurationSection root = config.getConfigurationSection(sections.get(0));
assertNotNull(root, "Section '" + sections.get(0) + "' does not exist!");

for (int i = 1; i < sections.size(); i++) {
root = root.getConfigurationSection(sections.get(i));
assertNotNull(root, "Section '" + sections.get(i) + "' does not exist!");
}
Object expectedValue = root.get(expectedOption);
assertNotNull(expectedValue, "Expected option '" + expectedOption + "' was not found in section '" + root.getName() + "'!");
}

@Test
void testDefaultConfigOptionGeneration() {
validateConfigOptions(Set.of(
"silent-logs", "verbose-outputs", "messages.missing-executor-implementation"
), adapter);
}

@Test
void testDefaultConfigOptionCommentGeneration() {
validateConfigOptionComments(Map.ofEntries(
Map.entry("silent-logs", silentLogs.comment()),
Map.entry("verbose-outputs", verboseOutputs.comment()),
Map.entry("messages.missing-executor-implementation", missingExecutorImplementation.comment()),
Map.entry("messages", messages.comment())
), adapter);
}

@Test
void testConfigOptionAddition() {
CommentedConfigOption<Boolean> createDispatcherJson = new CommentedConfigOption<>(new String[] {
"Create dispatcher JSON (default: false)",
"If \"true\", the CommandAPI creates a command_registration.json file showing the",
"mapping of registered commands. This is designed to be used by developers -",
"setting this to \"false\" will improve command registration performance."
}, false);

bukkitConfig.getAllOptions().put("create-dispatcher-json", createDispatcherJson);
generator = ConfigGenerator.createNew(bukkitConfig);
BukkitConfigurationAdapter updatedAdapter = (BukkitConfigurationAdapter) generator.generate(adapter);

validateConfigOptions(Set.of(
"silent-logs", "verbose-outputs", "messages.missing-executor-implementation", "create-dispatcher-json"
), updatedAdapter);

validateConfigOptionComments(Map.ofEntries(
Map.entry("silent-logs", silentLogs.comment()),
Map.entry("verbose-outputs", verboseOutputs.comment()),
Map.entry("messages.missing-executor-implementation", missingExecutorImplementation.comment()),
Map.entry("create-dispatcher-json", createDispatcherJson.comment()),
Map.entry("messages", messages.comment())
), updatedAdapter);
}

@Test
void testConfigOptionDeletion() {
bukkitConfig.getAllOptions().remove("silent-logs");
generator = ConfigGenerator.createNew(bukkitConfig);
BukkitConfigurationAdapter updatedAdapter = (BukkitConfigurationAdapter) generator.generate(adapter);

validateConfigOptionsAbsent(Set.of("silent-logs"), updatedAdapter);
}

@Test
void testConfigOptionCommentUpdate() {
silentLogs = new CommentedConfigOption<>(new String[] {
"Defines if silent logs should happen"
}, false);

bukkitConfig.getAllOptions().put("silent-logs", silentLogs);
generator = ConfigGenerator.createNew(bukkitConfig);
BukkitConfigurationAdapter updatedAdapter = (BukkitConfigurationAdapter) generator.generate(adapter);

validateConfigOptionComments(Map.ofEntries(
Map.entry("silent-logs", silentLogs.comment())
), updatedAdapter);
}

@Test
void testNestedSections() {
CommentedConfigOption<Boolean> subSubOption = new CommentedConfigOption<>(new String[0], false);

bukkitConfig.getAllOptions().put("root.nested.option", subSubOption);
generator = ConfigGenerator.createNew(bukkitConfig);
BukkitConfigurationAdapter updatedAdapter = (BukkitConfigurationAdapter) generator.generate(adapter);

validateSections(List.of("root", "nested"), "option", updatedAdapter.config());
}

@Test
void testConfigUpdateNotNeeded() {
assertNull(generator.generate(adapter));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,17 @@ public CommandAPIMain(ProxyServer server, Logger logger, @DataDirectory Path dat
// Try to find the config file
Path configFile = dataDirectory.resolve("config.yml");

YamlConfigurationLoader loader = YamlConfigurationLoader.builder()
.nodeStyle(NodeStyle.BLOCK)
.path(configFile)
.build();

// Create or update config
VelocityConfigurationAdapter.createDummyInstance().saveDefaultConfig(configFile.getParent().toFile(), configFile.toFile(), logger);
VelocityConfigurationAdapter.createDummyInstance(loader).saveDefaultConfig(configFile.getParent().toFile(), configFile.toFile(), logger);

// Load the file as a yaml node
ConfigurationNode configYAML;
try {
YamlConfigurationLoader loader = YamlConfigurationLoader.builder()
.nodeStyle(NodeStyle.BLOCK)
.path(configFile)
.build();
configYAML = loader.load();
} catch (IOException e) {
throw new RuntimeException(e);
Expand Down
Loading
Loading
0