feat(config): DSL-only Config migrations

This commit is contained in:
Johannes Frohnmeyer 2023-07-18 19:15:47 +02:00
parent 5fc774c53c
commit 3901078c52
Signed by: Johannes
GPG Key ID: E76429612C2929F4
6 changed files with 59 additions and 7 deletions

View File

@ -1,7 +1,9 @@
package io.gitlab.jfronny.libjf.config.api.v1.dsl;
import io.gitlab.jfronny.gson.JsonElement;
import io.gitlab.jfronny.libjf.config.api.v1.*;
import io.gitlab.jfronny.libjf.config.api.v1.type.Type;
import org.jetbrains.annotations.ApiStatus;
import java.util.List;
import java.util.function.Consumer;
@ -36,6 +38,8 @@ public interface CategoryBuilder<Builder extends CategoryBuilder<Builder>> {
<T> Builder value(String id, T def, double min, double max, Type type, int width, Supplier<T> get, Consumer<T> set);
<T> Builder value(EntryInfo<T> entry);
@ApiStatus.Experimental Builder addMigration(String element, Consumer<JsonElement> apply);
String getId();
ConfigCategory build(Supplier<ConfigInstance> root);

View File

@ -1,5 +1,7 @@
package io.gitlab.jfronny.libjf.config.impl.dsl;
import io.gitlab.jfronny.gson.JsonElement;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.config.api.v1.*;
import io.gitlab.jfronny.libjf.config.api.v1.dsl.CategoryBuilder;
import io.gitlab.jfronny.libjf.config.api.v1.type.Type;
@ -17,6 +19,7 @@ public class CategoryBuilderImpl<Builder extends CategoryBuilderImpl<Builder>> i
public final Map<String, Consumer<ConfigCategory>> presets = new LinkedHashMap<>();
public final List<Supplier<List<ConfigInstance>>> referencedConfigs = new LinkedList<>();
public final List<Consumer<ConfigCategory>> verifiers = new LinkedList<>();
public final Map<String, Consumer<JsonElement>> migrations = new LinkedHashMap<>();
private boolean built = false;
public CategoryBuilderImpl(String id, String categoryPath) {
@ -42,6 +45,7 @@ public class CategoryBuilderImpl<Builder extends CategoryBuilderImpl<Builder>> i
@Override
public Builder addPreset(String id, Consumer<ConfigCategory> action) {
checkBuilt();
if (presets.containsKey(id)) LibJf.LOGGER.warn("Duplicate preset registered for " + categoryPath + this.id + ": " + id + ", overriding");
presets.put(id, action);
return asBuilder();
}
@ -164,6 +168,14 @@ public class CategoryBuilderImpl<Builder extends CategoryBuilderImpl<Builder>> i
return asBuilder();
}
@Override
public Builder addMigration(String element, Consumer<JsonElement> apply) {
checkBuilt();
if (migrations.containsKey(element)) LibJf.LOGGER.warn("Duplicate migration registered for " + categoryPath + id + ": " + element + ", overriding");
migrations.put(element, apply);
return asBuilder();
}
@Override
public String getId() {
return id;
@ -186,7 +198,22 @@ public class CategoryBuilderImpl<Builder extends CategoryBuilderImpl<Builder>> i
@Override
public DslConfigCategory build(Supplier<ConfigInstance> root) {
markBuilt();
return new DslConfigCategory(id,
Set<String> migrationNames = migrations.keySet();
Set<String> entryNames = new HashSet<>();
for (EntryInfo<?> entry : entries) {
String name = entry.getName();
if (migrationNames.contains(name)) LibJf.LOGGER.warn("Entry conflict: " + categoryPath + id + " contains both a migration and an entry for " + name);
if (!entryNames.add(name)) LibJf.LOGGER.warn("Entry conflict: " + categoryPath + id + " contains two entries for " + name);
}
Set<String> categoryNames = new HashSet<>();
for (CategoryBuilder<?> category : categories) {
String name = category.getId();
if (migrationNames.contains(name)) LibJf.LOGGER.warn("Entry conflict: " + categoryPath + id + " contains both a migration and a category for " + name);
if (entryNames.contains(name)) LibJf.LOGGER.warn("Entry conflict: " + categoryPath + id + " contains both an entry and a category for " + name);
if (!categoryNames.add(name)) LibJf.LOGGER.warn("Entry conflict: " + categoryPath + id + " contains two categories for " + name);
}
return new DslConfigCategory(
id,
categoryPath,
translationPrefix,
entries,
@ -194,6 +221,8 @@ public class CategoryBuilderImpl<Builder extends CategoryBuilderImpl<Builder>> i
referencedConfigs,
categories,
root,
verifiers);
verifiers,
migrations
);
}
}

View File

@ -74,6 +74,13 @@ public class ConfigBuilderImpl extends CategoryBuilderImpl<ConfigBuilderImpl> im
else LibJf.LOGGER.error("Config category is not a JSON object, skipping");
} else LibJf.LOGGER.error("Config does not contain entry for subcategory " + entry.getKey());
}
if (category instanceof DslConfigCategory cat) {
for (Map.Entry<String, Consumer<JsonElement>> entry : cat.migrations.entrySet()) {
if (source.has(entry.getKey())) {
entry.getValue().accept(source.get(entry.getKey()));
}
}
}
}
private static void writeTo(JsonWriter writer, ConfigCategory category) throws IOException {
@ -125,7 +132,8 @@ public class ConfigBuilderImpl extends CategoryBuilderImpl<ConfigBuilderImpl> im
@Override
public DslConfigInstance build() {
markBuilt();
built = new DslConfigInstance(id,
built = new DslConfigInstance(
id,
translationPrefix,
entries,
presets,
@ -133,9 +141,11 @@ public class ConfigBuilderImpl extends CategoryBuilderImpl<ConfigBuilderImpl> im
categories,
() -> built,
verifiers,
migrations,
load,
write,
path);
path
);
built.load();
return built;
}

View File

@ -1,7 +1,9 @@
package io.gitlab.jfronny.libjf.config.impl.dsl;
import io.gitlab.jfronny.gson.JsonElement;
import io.gitlab.jfronny.libjf.config.api.v1.*;
import io.gitlab.jfronny.libjf.config.api.v1.dsl.CategoryBuilder;
import org.jetbrains.annotations.ApiStatus;
import java.util.*;
import java.util.function.Consumer;
@ -15,6 +17,7 @@ public class DslConfigCategory implements ConfigCategory {
private final List<EntryInfo<?>> entries;
private final Map<String, Runnable> presets;
private final List<Supplier<List<ConfigInstance>>> referencedConfigs;
@ApiStatus.Internal public final Map<String, Consumer<JsonElement>> migrations;
private final Map<String, ConfigCategory> categories;
private final Supplier<ConfigInstance> root;
private final List<Consumer<ConfigCategory>> verifiers;
@ -27,7 +30,8 @@ public class DslConfigCategory implements ConfigCategory {
List<Supplier<List<ConfigInstance>>> referencedConfigs,
List<CategoryBuilder<?>> categories,
Supplier<ConfigInstance> root,
List<Consumer<ConfigCategory>> verifiers) {
List<Consumer<ConfigCategory>> verifiers,
Map<String, Consumer<JsonElement>> migrations) {
this.id = id;
this.categoryPath = categoryPath;
this.translationPrefix = translationPrefix;
@ -39,6 +43,7 @@ public class DslConfigCategory implements ConfigCategory {
LinkedHashMap::new
));
this.referencedConfigs = referencedConfigs;
this.migrations = migrations;
this.categories = categories.stream().collect(Collectors.toMap(
CategoryBuilder::getId,
b -> b.build(root),

View File

@ -1,5 +1,6 @@
package io.gitlab.jfronny.libjf.config.impl.dsl;
import io.gitlab.jfronny.gson.JsonElement;
import io.gitlab.jfronny.libjf.config.api.v1.*;
import io.gitlab.jfronny.libjf.config.api.v1.dsl.CategoryBuilder;
import org.jetbrains.annotations.Nullable;
@ -22,10 +23,11 @@ public class DslConfigInstance extends DslConfigCategory implements ConfigInstan
List<CategoryBuilder<?>> categories,
Supplier<ConfigInstance> root,
List<Consumer<ConfigCategory>> verifiers,
Map<String, Consumer<JsonElement>> migrations,
Consumer<ConfigInstance> load,
Consumer<ConfigInstance> write,
@Nullable Path path) {
super(id, "", translationPrefix, entries, presets, referencedConfigs, categories, root, verifiers);
super(id, "", translationPrefix, entries, presets, referencedConfigs, categories, root, verifiers, migrations);
this.load = load;
this.write = write;
this.path = path;

View File

@ -9,6 +9,8 @@ public class TestConfigTweaker {
public static ConfigBuilder<?> tweak(ConfigBuilder<?> builder) {
if (!Objects.equals("libjf-config-reflect-v1-testmod", builder.getId())) throw new IllegalStateException("No!");
LibJf.LOGGER.info("Called config tweaker");
return builder;
return builder.addMigration("joe", jsonElement -> {
TestConfig.disablePacks = jsonElement.getAsJsonPrimitive().getAsBoolean();
});
}
}