-
Notifications
You must be signed in to change notification settings - Fork 147
feat: add extensible registry interface and integrate into config and meta-config registries #560
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
base: dev/1.21.11
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| * <br> | ||
| * 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. | ||
| * <br> | ||
| * Two system properties are used to define the search path: | ||
| * <br> | ||
| * <code>terra.registry.{searchPathName}.searchPath</code> is a list of "parent folder" paths (like the pack directory) that | ||
| * will be searched for contained files. | ||
| * <br> | ||
| * <code>terra.registry.{searchPathName}.extraPath</code> is a list of files that will be directly evaluated for membership and | ||
| * as such will be directly treated as members of the registry. | ||
| * <br> | ||
| * 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 | ||
| * <br> | ||
| * <code>terra.registry.{searchPathName}.searchPath</code> | ||
| * <br> | ||
| * and | ||
| * <br> | ||
| * <code>terra.registry.{searchPathName}.extraPath</code> | ||
| */ | ||
| @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<Path> getMemberPaths(Path baseSearchPath) { | ||
| String basePropertyName = "terra.registry." + getRegistryName(); | ||
|
|
||
| Stream<Path> searchPath = Stream.concat( | ||
| parseValidPaths(System.getProperty(basePropertyName + ".searchPath")), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. personally I am partial to using kebab case for something like this rather than camel case, but this is a personal nitpick and it's honestly fine either way |
||
| Stream.of(baseSearchPath) | ||
| ); | ||
|
|
||
| Stream<Path> extraPath = parseValidPaths(System.getProperty(basePropertyName + ".extraPath")); | ||
|
Comment on lines
+57
to
+61
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we need both extra path & search path, or would only one be sufficient? |
||
|
|
||
| return Stream.concat( | ||
| searchPath | ||
| .filter(Files::isDirectory) | ||
| .flatMap(CliExtensibleRegistry::listDirectory), | ||
| extraPath | ||
| ) | ||
| .filter(this::validatePathIsMember); | ||
| } | ||
|
|
||
| private static Stream<Path> 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<Path> listDirectory(Path dir) { | ||
| try { | ||
| return Files.list(dir); | ||
| } catch(IOException e) { | ||
| return Stream.empty(); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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<ConfigPack> { | ||
| public class ConfigRegistry extends OpenRegistryImpl<ConfigPack> 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<Exception> failedLoads = new CopyOnWriteArrayList<>(); | ||
| try(Stream<Path> packs = Files.list(packsDirectory)) { | ||
| try(Stream<Path> 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"); | ||
|
Comment on lines
+71
to
+72
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use the NIO |
||
| } | ||
|
|
||
| public static class PackLoadFailuresException extends Exception { | ||
| @Serial | ||
| private static final long serialVersionUID = 538998844645186306L; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,14 +28,15 @@ | |
| 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; | ||
|
|
||
|
|
||
| /** | ||
| * Class to hold config packs | ||
| */ | ||
| public class MetaConfigRegistry extends OpenRegistryImpl<MetaPack> { | ||
| public class MetaConfigRegistry extends OpenRegistryImpl<MetaPack> 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<IOException> failedLoads = new ArrayList<>(); | ||
| try(Stream<Path> packs = Files.list(packsDirectory)) { | ||
| packs.forEach(path -> { | ||
| try(Stream<Path> 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"); | ||
|
Comment on lines
+71
to
+72
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NIO |
||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like the name "cli extensible registry" could definitely be workshopped a bit, but that's a personal nitpick