From b49b38f240e36ab495686d388993e9b7fa28d88e Mon Sep 17 00:00:00 2001 From: Christian Bergschneider Date: Tue, 12 May 2026 10:04:19 +0200 Subject: [PATCH 1/4] feat: add extensible registry interface and integrate into config and meta-config registries --- .../terra/registry/CliExtensibleRegistry.java | 93 +++++++++++++++++++ .../terra/registry/master/ConfigRegistry.java | 16 +++- .../registry/master/MetaConfigRegistry.java | 18 +++- 3 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 common/implementation/base/src/main/java/com/dfsek/terra/registry/CliExtensibleRegistry.java diff --git a/common/implementation/base/src/main/java/com/dfsek/terra/registry/CliExtensibleRegistry.java b/common/implementation/base/src/main/java/com/dfsek/terra/registry/CliExtensibleRegistry.java new file mode 100644 index 0000000000..032e11a1a9 --- /dev/null +++ b/common/implementation/base/src/main/java/com/dfsek/terra/registry/CliExtensibleRegistry.java @@ -0,0 +1,93 @@ +package com.dfsek.terra.registry; + +import com.google.errorprone.annotations.MustBeClosed; +import org.intellij.lang.annotations.Pattern; +import org.jspecify.annotations.Nullable; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Objects; +import java.util.stream.Stream; + + +/** + * A file-discoverable registry that can be extended by system properties + *
+ * The main use-case for this is to allow for customized locations of file-system-based key entries, + * such as putting config packs into custom locations. + *
+ * Two system properties are used to define the search path: + *
+ * terra.registry.{searchPathName}.searchPath is a list of "parent folder" paths (like the pack directory) that + * will be searched for contained files. + *
+ * terra.registry.{searchPathName}.extraPath is a list of files that will be directly evaluated for membership and + * as such will be directly treated as members of the registry. + *
+ * These system properties are formatted like UNIX-style paths, with each path separated by a colon (':') character. + */ +public interface CliExtensibleRegistry { + /** + * Get a lowercase search path name for this registry that will get plugged into + *
+ * terra.registry.{searchPathName}.searchPath + *
+ * and + *
+ * terra.registry.{searchPathName}.extraPath + */ + @Pattern("^[a-z._]+$") + String getRegistryName(); + + /** + * Check if a path may be a member of this registry heuristically. + * + * @param path Path to check + * + * @return True if the path is a member of this registry. + */ + boolean validatePathIsMember(Path path); + + default @MustBeClosed Stream getMemberPaths(Path baseSearchPath) { + String basePropertyName = "terra.registry." + getRegistryName(); + + Stream searchPath = Stream.concat( + parseValidPaths(System.getProperty(basePropertyName + ".searchPath")), + Stream.of(baseSearchPath) + ); + + Stream extraPath = parseValidPaths(System.getProperty(basePropertyName + ".extraPath")); + + return Stream.concat( + searchPath + .filter(Files::isDirectory) + .flatMap(CliExtensibleRegistry::listDirectory), + extraPath + ) + .filter(this::validatePathIsMember); + } + + private static Stream parseValidPaths(@Nullable String paths) { + return Stream.ofNullable(paths) + .flatMap(p -> Arrays.stream(p.split(":"))) + .filter(v -> !v.isBlank()) + .map(v -> { + try { + return Path.of(v).toAbsolutePath().normalize(); + } catch (Exception e) { + return null; + } + }) + .filter(Objects::nonNull); + } + + private static Stream listDirectory(Path dir) { + try { + return Files.list(dir); + } catch(IOException e) { + return Stream.empty(); + } + } +} diff --git a/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/ConfigRegistry.java b/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/ConfigRegistry.java index f4b4c9dd1a..831188299b 100644 --- a/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/ConfigRegistry.java +++ b/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/ConfigRegistry.java @@ -29,13 +29,14 @@ import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.config.pack.ConfigPackImpl; +import com.dfsek.terra.registry.CliExtensibleRegistry; import com.dfsek.terra.registry.OpenRegistryImpl; /** * Class to hold config packs */ -public class ConfigRegistry extends OpenRegistryImpl { +public class ConfigRegistry extends OpenRegistryImpl implements CliExtensibleRegistry { public ConfigRegistry() { super(TypeKey.of(ConfigPack.class)); @@ -45,7 +46,7 @@ public synchronized void loadAll(Platform platform) throws IOException, PackLoad Path packsDirectory = platform.getDataFolder().toPath().resolve("packs"); Files.createDirectories(packsDirectory); List failedLoads = new CopyOnWriteArrayList<>(); - try(Stream packs = Files.list(packsDirectory)) { + try(Stream packs = getMemberPaths(packsDirectory)) { packs.parallel().forEach(path -> { try { ConfigPack pack = new ConfigPackImpl(path, platform); @@ -60,6 +61,17 @@ public synchronized void loadAll(Platform platform) throws IOException, PackLoad } } + @Override + public String getRegistryName() { + return "config"; + } + + @Override + public boolean validatePathIsMember(Path path) { + var file = path.toFile(); + return file.isDirectory() || file.getName().endsWith(".zip"); + } + public static class PackLoadFailuresException extends Exception { @Serial private static final long serialVersionUID = 538998844645186306L; diff --git a/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/MetaConfigRegistry.java b/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/MetaConfigRegistry.java index 05539475e5..9adeb0c711 100644 --- a/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/MetaConfigRegistry.java +++ b/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/MetaConfigRegistry.java @@ -28,6 +28,7 @@ import com.dfsek.terra.api.config.MetaPack; import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.config.pack.MetaPackImpl; +import com.dfsek.terra.registry.CliExtensibleRegistry; import com.dfsek.terra.registry.OpenRegistryImpl; import com.dfsek.terra.registry.master.ConfigRegistry.PackLoadFailuresException; @@ -35,7 +36,7 @@ /** * Class to hold config packs */ -public class MetaConfigRegistry extends OpenRegistryImpl { +public class MetaConfigRegistry extends OpenRegistryImpl implements CliExtensibleRegistry { public MetaConfigRegistry() { super(TypeKey.of(MetaPack.class)); @@ -45,8 +46,8 @@ public void loadAll(Platform platform, ConfigRegistry configRegistry) throws IOE Path packsDirectory = platform.getDataFolder().toPath().resolve("metapacks"); Files.createDirectories(packsDirectory); List failedLoads = new ArrayList<>(); - try(Stream packs = Files.list(packsDirectory)) { - packs.forEach(path -> { + try(Stream paths = getMemberPaths(packsDirectory)) { + paths.forEach(path -> { try { MetaPack pack = new MetaPackImpl(path, platform, configRegistry); registerChecked(pack.getRegistryKey(), pack); @@ -59,4 +60,15 @@ public void loadAll(Platform platform, ConfigRegistry configRegistry) throws IOE throw new PackLoadFailuresException(failedLoads); } } + + @Override + public String getRegistryName() { + return "metaconfig"; + } + + @Override + public boolean validatePathIsMember(Path path) { + var file = path.toFile(); + return file.isDirectory() || file.getName().endsWith(".zip"); + } } From 4f59ca4f99d14f17cc96a1955e0f00f41e3d0f7b Mon Sep 17 00:00:00 2001 From: Christian Bergschneider Date: Thu, 28 May 2026 20:54:05 +0200 Subject: [PATCH 2/4] refactor: rename `CliExtensibleRegistry` to `ExtensibleRegistry` for clarity and consistency --- .../{CliExtensibleRegistry.java => ExtensibleRegistry.java} | 4 ++-- .../java/com/dfsek/terra/registry/master/ConfigRegistry.java | 4 ++-- .../com/dfsek/terra/registry/master/MetaConfigRegistry.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) rename common/implementation/base/src/main/java/com/dfsek/terra/registry/{CliExtensibleRegistry.java => ExtensibleRegistry.java} (96%) diff --git a/common/implementation/base/src/main/java/com/dfsek/terra/registry/CliExtensibleRegistry.java b/common/implementation/base/src/main/java/com/dfsek/terra/registry/ExtensibleRegistry.java similarity index 96% rename from common/implementation/base/src/main/java/com/dfsek/terra/registry/CliExtensibleRegistry.java rename to common/implementation/base/src/main/java/com/dfsek/terra/registry/ExtensibleRegistry.java index 032e11a1a9..f1314c6177 100644 --- a/common/implementation/base/src/main/java/com/dfsek/terra/registry/CliExtensibleRegistry.java +++ b/common/implementation/base/src/main/java/com/dfsek/terra/registry/ExtensibleRegistry.java @@ -28,7 +28,7 @@ *
* These system properties are formatted like UNIX-style paths, with each path separated by a colon (':') character. */ -public interface CliExtensibleRegistry { +public interface ExtensibleRegistry { /** * Get a lowercase search path name for this registry that will get plugged into *
@@ -63,7 +63,7 @@ public interface CliExtensibleRegistry { return Stream.concat( searchPath .filter(Files::isDirectory) - .flatMap(CliExtensibleRegistry::listDirectory), + .flatMap(ExtensibleRegistry::listDirectory), extraPath ) .filter(this::validatePathIsMember); diff --git a/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/ConfigRegistry.java b/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/ConfigRegistry.java index 831188299b..234c2f1b03 100644 --- a/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/ConfigRegistry.java +++ b/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/ConfigRegistry.java @@ -29,14 +29,14 @@ import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.config.pack.ConfigPackImpl; -import com.dfsek.terra.registry.CliExtensibleRegistry; +import com.dfsek.terra.registry.ExtensibleRegistry; import com.dfsek.terra.registry.OpenRegistryImpl; /** * Class to hold config packs */ -public class ConfigRegistry extends OpenRegistryImpl implements CliExtensibleRegistry { +public class ConfigRegistry extends OpenRegistryImpl implements ExtensibleRegistry { public ConfigRegistry() { super(TypeKey.of(ConfigPack.class)); diff --git a/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/MetaConfigRegistry.java b/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/MetaConfigRegistry.java index 9adeb0c711..f9e05cb424 100644 --- a/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/MetaConfigRegistry.java +++ b/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/MetaConfigRegistry.java @@ -28,7 +28,7 @@ import com.dfsek.terra.api.config.MetaPack; import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.config.pack.MetaPackImpl; -import com.dfsek.terra.registry.CliExtensibleRegistry; +import com.dfsek.terra.registry.ExtensibleRegistry; import com.dfsek.terra.registry.OpenRegistryImpl; import com.dfsek.terra.registry.master.ConfigRegistry.PackLoadFailuresException; @@ -36,7 +36,7 @@ /** * Class to hold config packs */ -public class MetaConfigRegistry extends OpenRegistryImpl implements CliExtensibleRegistry { +public class MetaConfigRegistry extends OpenRegistryImpl implements ExtensibleRegistry { public MetaConfigRegistry() { super(TypeKey.of(MetaPack.class)); From 8f1a53fc2ac2fc4c79391cf314f3d9da4cdf7957 Mon Sep 17 00:00:00 2001 From: Christian Bergschneider Date: Thu, 28 May 2026 20:57:17 +0200 Subject: [PATCH 3/4] refactor: move validatePathIsMember logic to NIO files API --- .../java/com/dfsek/terra/registry/master/ConfigRegistry.java | 3 +-- .../com/dfsek/terra/registry/master/MetaConfigRegistry.java | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/ConfigRegistry.java b/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/ConfigRegistry.java index 234c2f1b03..08343d59f9 100644 --- a/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/ConfigRegistry.java +++ b/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/ConfigRegistry.java @@ -68,8 +68,7 @@ public String getRegistryName() { @Override public boolean validatePathIsMember(Path path) { - var file = path.toFile(); - return file.isDirectory() || file.getName().endsWith(".zip"); + return Files.isDirectory(path)|| path.getFileName().endsWith(".zip"); } public static class PackLoadFailuresException extends Exception { diff --git a/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/MetaConfigRegistry.java b/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/MetaConfigRegistry.java index f9e05cb424..65a4164001 100644 --- a/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/MetaConfigRegistry.java +++ b/common/implementation/base/src/main/java/com/dfsek/terra/registry/master/MetaConfigRegistry.java @@ -68,7 +68,6 @@ public String getRegistryName() { @Override public boolean validatePathIsMember(Path path) { - var file = path.toFile(); - return file.isDirectory() || file.getName().endsWith(".zip"); + return Files.isDirectory(path) || path.getFileName().endsWith(".zip"); } } From 47b17b1e0f49783945564277ac5d26743397e2d5 Mon Sep 17 00:00:00 2001 From: Christian Bergschneider Date: Thu, 28 May 2026 20:57:51 +0200 Subject: [PATCH 4/4] refactor!: standardize property names to use kebab-case in ExtensibleRegistry --- .../java/com/dfsek/terra/registry/ExtensibleRegistry.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/implementation/base/src/main/java/com/dfsek/terra/registry/ExtensibleRegistry.java b/common/implementation/base/src/main/java/com/dfsek/terra/registry/ExtensibleRegistry.java index f1314c6177..0d6a8e3b88 100644 --- a/common/implementation/base/src/main/java/com/dfsek/terra/registry/ExtensibleRegistry.java +++ b/common/implementation/base/src/main/java/com/dfsek/terra/registry/ExtensibleRegistry.java @@ -54,11 +54,11 @@ public interface ExtensibleRegistry { String basePropertyName = "terra.registry." + getRegistryName(); Stream searchPath = Stream.concat( - parseValidPaths(System.getProperty(basePropertyName + ".searchPath")), + parseValidPaths(System.getProperty(basePropertyName + ".search-path")), Stream.of(baseSearchPath) ); - Stream extraPath = parseValidPaths(System.getProperty(basePropertyName + ".extraPath")); + Stream extraPath = parseValidPaths(System.getProperty(basePropertyName + ".extra-path")); return Stream.concat( searchPath