10000 Merge pull request #605 from JorelAli/dev/config-experiment · CommandAPI/CommandAPI@eddcb5c · GitHub
[go: up one dir, main page]

Skip to content

Commit eddcb5c

Browse files
authored
Merge pull request #605 from JorelAli/dev/config-experiment
Rework plugin config system #2
2 parents 0739a4f + ed82a36 commit eddcb5c

File tree

9 files changed

+302
-119
lines changed

9 files changed

+302
-119
lines changed

commandapi-codecov/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@
4040
<artifactId>commandapi-bukkit-core</artifactId>
4141
<version>${project.version}</version>
4242
</dependency>
43+
<dependency>
44+
<groupId>dev.jorel</groupId>
45+
<artifactId>commandapi-plugin</artifactId>
46+
<version>${project.version}</version>
47+
</dependency>
48+
<dependency>
49+
<groupId>dev.jorel</groupId>
50+
<artifactId>commandapi-bukkit-plugin-common</artifactId>
51+
<version>${project.version}</version>
52+
</dependency>
4353

4454
<!-- Code coverage the tests -->
4555
<dependency>

commandapi-platforms/commandapi-bukkit/commandapi-bukkit-plugin-common/src/main/java/dev/jorel/commandapi/CommandAPIMain.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public void onEnable() {
145145
@Override
146146
public void saveDefaultConfig() {
147147
File configFile = new File(getDataFolder(), "config.yml");
148-
BukkitConfigurationAdapter.createDummyInstance().saveDefaultConfig(getDataFolder(), configFile, getLogger());
148+
BukkitConfigurationAdapter.createMinimalInstance(configFile).saveDefaultConfig(getDataFolder(), getLogger());
149149
}
150150

151151
}

commandapi-platforms/commandapi-bukkit/commandapi-bukkit-plugin-common/src/main/java/dev/jorel/commandapi/config/BukkitConfigurationAdapter.java

Lines changed: 18 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,11 @@
1212
import java.util.List;
1313
import java.util.Objects;
1414
import java.util.Set;
15-
import java.util.logging.Logger;
1615

17-
public record BukkitConfigurationAdapter(YamlConfiguration config) implements ConfigurationAdapter<YamlConfiguration> {
16+
public record BukkitConfigurationAdapter(YamlConfiguration config, File configFile) implements ConfigurationAdapter<YamlConfiguration> {
1817

19-
public static BukkitConfigurationAdapter createDummyInstance() {
20-
return new BukkitConfigurationAdapter(null);
18+
public static BukkitConfigurationAdapter createMinimalInstance(File configFile) {
19+
return new BukkitConfigurationAdapter(null, configFile);
2120
}
2221

2322
@Override
@@ -104,50 +103,26 @@ public ConfigurationAdapter<YamlConfiguration> complete() {
104103
return this;
105104
}
106105

106+
107107
@Override
108108
public ConfigurationAdapter<YamlConfiguration> createNew() {
109-
return new BukkitConfigurationAdapter(new YamlConfiguration());
109+
return new BukkitConfigurationAdapter(new YamlConfiguration(), configFile);
110110
}
111111

112112
@Override
113-
public void saveDefaultConfig(File directory, File configFile, Logger logger) {
114-
ConfigGenerator configGenerator = ConfigGenerator.createNew(DefaultBukkitConfig.createDefault());
115-
if (!directory.exists()) {
116-
boolean createdDirectory = directory.mkdirs();
117-
if (!createdDirectory) {
118-
logger.severe("Failed to create directory for the CommandAPI's config.yml file!");
119-
}
120-
try {
121-
ConfigurationAdapter<YamlConfiguration> bukkitConfigurationAdapter = new BukkitConfigurationAdapter(new YamlConfiguration());
122-
configGenerator.populateDefaultConfig(bukkitConfigurationAdapter);
123-
bukkitConfigurationAdapter.config().save(configFile);
124-
} catch (IOException e) {
125-
logger.severe("Could not create default config file! This is (probably) a bug.");
126-
logger.severe("Error message: " + e.getMessage());
127-
logger.severe("Stacktrace:");
128-
for (StackTraceElement element : e.getStackTrace()) {
129-
logger.severe(element.toString());
130-
}
131-
}
132-
return;
133-
}
134-
// Update the config if necessary
135-
try {
136-
YamlConfiguration existingYamlConfig = YamlConfiguration.loadConfiguration(configFile);
137-
ConfigurationAdapter<YamlConfiguration> existingConfig = new BukkitConfigurationAdapter(existingYamlConfig);
138-
ConfigurationAdapter<YamlConfiguration> updatedConfig = configGenerator.generateWithNewValues(existingConfig);
139-
if (updatedConfig == null) {
140-
return;
141-
}
142-
updatedConfig.config().save(configFile);
143-
} catch (IOException e) {
144-
logger.severe("Could not update config! This is (probably) a bug.");
145-
logger.severe("Error message: " + e.getMessage());
146-
logger.severe("Stacktrace:");
147-
for (StackTraceElement element : e.getStackTrace()) {
148-
logger.severe(element.toString());
149-
}
150-
}
113+
public DefaultBukkitConfig createDefaultConfig() {
114+
return DefaultBukkitConfig.createDefault();
115+
}
116+
117+
@Override
118+
public ConfigurationAdapter<YamlConfiguration> loadFromFile() {
119+
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
120+
return new BukkitConfigurationAdapter(config, configFile);
121+
}
122+
123+
@Override
124+
public void saveToFile() throws IOException {
125+
config.save(configFile);
151126
}
152127

153128
}

commandapi-platforms/commandapi-bukkit/commandapi-bukkit-test/commandapi-bukkit-test-tests/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@
8686
<artifactId>commandapi-bukkit-test-impl</artifactId>
8787
<version>${project.version}</version>
8888
</dependency>
89+
<dependency>
90+
<groupId>dev.jorel</groupId>
91+
<artifactId>commandapi-bukkit-plugin-common</artifactId>
92+
<version>${project.version}</version>
93+
</dependency>
8994

9095
<!-- NBT API implementations (in no particular order) -->
9196
<dependency>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
package dev.jorel.commandapi.test;
2+
3+
import dev.jorel.commandapi.config.BukkitConfigurationAdapter;
4+
import dev.jorel.commandapi.config.CommentedConfigOption;
5+
import dev.jorel.commandapi.config.CommentedSection;
6+
import dev.jorel.commandapi.config.ConfigGenerator;
7+
import dev.jorel.commandapi.config.ConfigurationAdapter;
8+
import dev.jorel.commandapi.config.DefaultBukkitConfig;
9+
import org.bukkit.configuration.ConfigurationSection;
10+
import org.bukkit.configuration.file.YamlConfiguration;
11+
import org.junit.jupiter.api.AfterEach;
12+
import org.junit.jupiter.api.BeforeEach;
13+
import org.junit.jupiter.api.Test;
14+
15+
import java.util.Arrays;
16+
import java.util.LinkedHashMap;
17+
import java.util.List;
18+
import java.util.Map;
19+
import java.util.Set;
20+
21+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
22+
import static org.junit.jupiter.api.Assertions.assertFalse;
23+
import static org.junit.jupiter.api.Assertions.assertNotNull;
24+
import static org.junit.jupiter.api.Assertions.assertNull;
25+
import static org.junit.jupiter.api.Assertions.assertTrue;
26+
27+
class ConfigGenerationTests {
28+
29+
private CommentedConfigOption<Boolean> silentLogs;
30+
private CommentedConfigOption<Boolean> verboseOutputs;
31+
private CommentedConfigOption<String> missingExecutorImplementation;
32+
33+
private CommentedSection messages;
34+
35+
private ConfigGenerator generator;
36+
private DefaultBukkitConfig bukkitConfig;
37+
private BukkitConfigurationAdapter adapter;
38+
39+
@BeforeEach
40+
public void setup() {
41+
silentLogs = new CommentedConfigOption<>(new String[]{
42+
"Silent logs (default: false)",
43+
"If \"true\", turns off all logging from the CommandAPI, except for errors."
44+
}, false);
45+
verboseOutputs = new CommentedConfigOption<>(new String[]{
46+
"Verbose outputs (default: false)",
47+
"If \"true\", outputs command registration and unregistration logs in the console"
48+
}, false);
49+
missingExecutorImplementation = new CommentedConfigOption<>(new String[]{
50+
"Missing executor implementation (default: \"This command has no implementations for %s\")",
51+
"The message to display to senders when a command has no executor. Available",
52+
"parameters are:",
53+
" %s - the executor class (lowercase)",
54+
" %S - the executor class (normal case)"
55+
}, "This command has no implementations for %s");
56+
57+
messages = new CommentedSection(new String[]{
58+
"Messages",
59+
"Controls messages that the CommandAPI displays to players"
60+
});
61+
62+
Map<String, CommentedConfigOption<?>> options = new LinkedHashMap<>();
63+
options.put("silent-logs", silentLogs);
64+
options.put("verbose-outputs", verboseOutputs);
65+
options.put("messages.missing-executor-implementation", missingExecutorImplementation);
66+
67+
Map<String, CommentedSection> sections = new LinkedHashMap<>();
68+
sections.put("messages", messages);
69+
70+
ConfigurationAdapter<YamlConfiguration> adapter = new BukkitConfigurationAdapter(new YamlConfiguration(), null);
71+
bukkitConfig = DefaultBukkitConfig.create(options, sections);
72+
generator = ConfigGenerator.createNew(bukkitConfig);
73+
this.adapter = (BukkitConfigurationAdapter) generator.generate(adapter);
74+
}
75+
76+
@AfterEach
77+
public void reset() {
78+
this.silentLogs = null;
79+
this.verboseOutputs = null;
80+
this.missingExecutorImplementation = null;
81+
this.messages = null;
82+
this.generator = null;
83+
this.bukkitConfig = null;
84+
this.adapter = null;
85+
}
86+
87+
// Test methods
88+
private void validateConfigOptions(Set<String> options, BukkitConfigurationAdapter adapter) {
89+
for (String option : options) {
90+
assertTrue(adapter.contains(option), "Config option '" + option + "' does not exist!");
91+
}
92+
}
93+
94+
private void validateConfigOptionComments(Map<String, String[]> comments, BukkitConfigurationAdapter adapter) {
95+
for (String option : comments.keySet()) {
96+
String[] expectedComment = comments.get(option);
97+
String[] generatedComment = adapter.getComment(option);
98+
assertArrayEquals(expectedComment, generatedComment, "Config option comment for option '" + option + "' does not exist or was incorrect!");
99+
}
100+
}
101+
102+
private void validateConfigOptionsAbsent(Set<String> options, BukkitConfigurationAdapter adapter) {
103+
for (String option : options) {
104+
assertFalse(adapter.contains(option), "Config option '" + option + "' does still exist!");
105+
}
106+
}
107+
108+
private void validateSections(List<String> sections, String expectedOption, YamlConfiguration config) {
109+
ConfigurationSection root = config;
110+
111+
for (String section : sections) {
112+
root = root.getConfigurationSection(section);
113+
assertNotNull(root, "Section '" + section + "' does not exist!");
114+
}
115+
Object expectedValue = root.get(expectedOption);
116+
assertNotNull(expectedValue, "Expected option '" + expectedOption + "' was not found in section '" + root.getName() + "'!");
117+
}
118+
119+
@Test
120+
void testDefaultConfigOptionGeneration() {
121+
validateConfigOptions(Set.of(
122+
"silent-logs", "verbose-outputs", "messages.missing-executor-implementation"
123+
), adapter);
124+
}
125+
126+
@Test
127+
void testDefaultConfigOptionCommentGeneration() {
128+
validateConfigOptionComments(Map.ofEntries(
129+
Map.entry("silent-logs", silentLogs.comment()),
130+
Map.entry("verbose-outputs", verboseOutputs.comment()),
131+
Map.entry("messages.missing-executor-implementation", missingExecutorImplementation.comment()),
132+
Map.entry("messages", messages.comment())
133+
), adapter);
134+
}
135+
136+
@Test
137+
void testConfigOptionAddition() {
138+
CommentedConfigOption<Boolean> createDispatcherJson = new CommentedConfigOption<>(new String[] {
139+
"Create dispatcher JSON (default: false)",
140+
"If \"true\", the CommandAPI creates a command_registration.json file showing the",
141+
"mapping of registered commands. This is designed to be used by developers -",
142+
"setting this to \"false\" will improve command registration performance."
143+
}, false);
144+
145+
bukkitConfig.getAllOptions().put("create-dispatcher-json", createDispatcherJson);
146+
generator = ConfigGenerator.createNew(bukkitConfig);
147+
BukkitConfigurationAdapter updatedAdapter = (BukkitConfigurationAdapter) generator.generate(adapter);
148+
149+
validateConfigOptions(Set.of(
150+
"silent-logs", "verbose-outputs", "messages.missing-executor-implementation", "create-dispatcher-json"
151+
), updatedAdapter);
152+
153+
validateConfigOptionComments(Map.ofEntries(
154+
Map.entry("silent-logs", silentLogs.comment()),
155+
Map.entry("verbose-outputs", verboseOutputs.comment()),
156+
Map.entry("messages.missing-executor-implementation", missingExecutorImplementation.comment()),
157+
Map.entry("create-dispatcher-json", createDispatcherJson.comment()),
158+
Map.entry("messages", messages.comment())
159+
), updatedAdapter);
160+
}
161+
162+
@Test
163+
void testConfigOptionDeletion() {
164+
bukkitConfig.getAllOptions().remove("silent-logs");
165+
generator = ConfigGenerator.createNew(bukkitConfig);
166+
BukkitConfigurationAdapter updatedAdapter = (BukkitConfigurationAdapter) generator.generate(adapter);
167+
168+
validateConfigOptionsAbsent(Set.of("silent-logs"), updatedAdapter);
169+
}
170+
171+
@Test
172+
void testConfigOptionCommentUpdate() {
173+
silentLogs = new CommentedConfigOption<>(new String[] {
174+
"Defines if silent logs should happen"
175+
}, false);
176+
177+
bukkitConfig.getAllOptions().put("silent-logs", silentLogs);
178+
generator = ConfigGenerator.createNew(bukkitConfig);
179+
BukkitConfigurationAdapter updatedAdapter = (BukkitConfigurationAdapter) generator.generate(adapter);
180+
181+
validateConfigOptionComments(Map.ofEntries(
182+
Map.entry("silent-logs", silentLogs.comment())
183+
), updatedAdapter);
184+
}
185+
186+
@Test
187+
void testNestedSections() {
188+
CommentedConfigOption<Boolean> subSubOption = new CommentedConfigOption<>(new String[0], false);
189+
190+
bukkitConfig.getAllOptions().put("root.nested.option", subSubOption);
191+
generator = ConfigGenerator.createNew(bukkitConfig);
192+
BukkitConfigurationAdapter updatedAdapter = (BukkitConfigurationAdapter) generator.generate(adapter);
193+
194+
validateSections(List.of("root", "nested"), "option", updatedAdapter.config());
195+
}
196+
197+
@Test
198+
void testConfigUpdateNotNeeded() {
199+
assertNull(generator.generate(adapter));
200+
}
201+
202+
}

commandapi-platforms/commandapi-velocity/commandapi-velocity-plugin/src/main/java/dev/jorel/commandapi/CommandAPIMain.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,17 @@ public CommandAPIMain(ProxyServer server, Logger logger, @DataDirectory Path dat
3535
// Try to find the config file
3636
Path configFile = dataDirectory.resolve("config.yml");
3737

38+
YamlConfigurationLoader loader = YamlConfigurationLoader.builder()
39+
.nodeStyle(NodeStyle.BLOCK)
40+
.path(configFile)
41+
.build();
42+
3843
// Create or update config
39-
VelocityConfigurationAdapter.createDummyInstance().saveDefaultConfig(configFile.getParent().toFile(), configFile.toFile(), logger);
44+
VelocityConfigurationAdapter.createMinimalInstance(loader).saveDefaultConfig(configFile.getParent().toFile(), logger);
4045

4146
// Load the file as a yaml node
4247
ConfigurationNode configYAML;
4348
try {
44-
YamlConfigurationLoader loader = YamlConfigurationLoader.builder()
45-
.nodeStyle(NodeStyle.BLOCK)
46-
.path(configFile)
47-
.build();
4849
configYAML = loader.load();
4950
} catch (IOException e) {
5051
throw new RuntimeException(e);

0 commit comments

Comments
 (0)
0