From 1cdeef88c5f06d0c1736677eb8c52a50f92d7888 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <nassim@njahnke.dev>
Date: Thu, 1 Feb 2024 10:51:29 +0100
Subject: [PATCH] Small refactor of Paper plugin context preparation

---
 patches/server/Paper-Plugins.patch | 108 +++++++++++++++++++----------
 1 file changed, 71 insertions(+), 37 deletions(-)

diff --git a/patches/server/Paper-Plugins.patch b/patches/server/Paper-Plugins.patch
index d9059bfa72..9d50e6a278 100644
--- a/patches/server/Paper-Plugins.patch
+++ b/patches/server/Paper-Plugins.patch
@@ -561,11 +561,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    public static void load(OptionSet optionSet) throws Exception {
 +        // We have to load the bukkit configuration inorder to get the update folder location.
 +        io.papermc.paper.plugin.PluginInitializerManager pluginSystem = io.papermc.paper.plugin.PluginInitializerManager.init(optionSet);
++
 +        // Register the default plugin directory
 +        io.papermc.paper.plugin.util.EntrypointUtil.registerProvidersFromSource(io.papermc.paper.plugin.provider.source.DirectoryProviderSource.INSTANCE, pluginSystem.pluginDirectoryPath());
-+        @SuppressWarnings("unchecked")
-+        java.util.List<File> files = (java.util.List<File>) optionSet.valuesOf("add-plugin");
++
 +        // Register plugins from the flag
++        @SuppressWarnings("unchecked")
++        java.util.List<Path> files = ((java.util.List<File>) optionSet.valuesOf("add-plugin")).stream().map(File::toPath).toList();
 +        io.papermc.paper.plugin.util.EntrypointUtil.registerProvidersFromSource(io.papermc.paper.plugin.provider.source.PluginFlagProviderSource.INSTANCE, files);
 +    }
 +
@@ -3876,14 +3878,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        RuntimePluginEntrypointHandler<SingularRuntimePluginProviderStorage> runtimePluginEntrypointHandler = new RuntimePluginEntrypointHandler<>(new SingularRuntimePluginProviderStorage(this.dependencyTree));
 +
 +        try {
++            path = FILE_PROVIDER_SOURCE.prepareContext(path);
 +            FILE_PROVIDER_SOURCE.registerProviders(runtimePluginEntrypointHandler, path);
 +        } catch (IllegalArgumentException exception) {
 +            return null; // Return null when the plugin file is not valid / plugin type is unknown
 +        } catch (PluginGraphCycleException exception) {
 +            throw new InvalidPluginException("Cannot import plugin that causes cyclic dependencies!");
-+        } catch (SerializationException |
-+                 InvalidDescriptionException ex) { // The spigot implementation wraps it in an invalid plugin exception
-+            throw new InvalidPluginException(ex);
 +        } catch (Exception e) {
 +            throw new InvalidPluginException(e);
 +        }
@@ -3904,6 +3904,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +        RuntimePluginEntrypointHandler<MultiRuntimePluginProviderStorage> runtimePluginEntrypointHandler = new RuntimePluginEntrypointHandler<>(new MultiRuntimePluginProviderStorage(this.dependencyTree));
 +        try {
++            directory = DIRECTORY_PROVIDER_SOURCE.prepareContext(directory);
 +            DIRECTORY_PROVIDER_SOURCE.registerProviders(runtimePluginEntrypointHandler, directory);
 +            runtimePluginEntrypointHandler.enter(Entrypoint.PLUGIN);
 +        } catch (Exception e) {
@@ -5487,6 +5488,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +import com.mojang.logging.LogUtils;
 +import io.papermc.paper.plugin.entrypoint.EntrypointHandler;
++import java.io.IOException;
++import java.util.function.Consumer;
 +import org.slf4j.Logger;
 +
 +import java.nio.file.FileVisitOption;
@@ -5506,23 +5509,39 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    }
 +
 +    @Override
-+    public void registerProviders(EntrypointHandler entrypointHandler, Path context) throws Exception {
-+        // Sym link happy, create file if missing.
++    public Path prepareContext(Path context) throws IOException {
++        // Symlink happy, create file if missing.
 +        if (!Files.isDirectory(context)) {
 +            Files.createDirectories(context);
 +        }
 +
++        this.walkFiles(context, path -> {
++            try {
++                super.prepareContext(path);
++            } catch (IOException e) {
++                throw new RuntimeException(e);
++            }
++        });
++        return context;
++    }
++
++    @Override
++    public void registerProviders(EntrypointHandler entrypointHandler, Path context) throws IOException {
++        this.walkFiles(context, path -> {
++            try {
++                super.registerProviders(entrypointHandler, path);
++            } catch (IllegalArgumentException ignored) {
++                // Ignore initial argument exceptions
++            } catch (Exception e) {
++                LOGGER.error("Error loading plugin: " + e.getMessage(), e);
++            }
++        });
++    }
++
++    private void walkFiles(Path context, Consumer<Path> consumer) throws IOException {
 +        Files.walk(context, 1, FileVisitOption.FOLLOW_LINKS)
 +            .filter(this::isValidFile)
-+            .forEach((path) -> {
-+                try {
-+                    super.registerProviders(entrypointHandler, path);
-+                } catch (IllegalArgumentException ignored) {
-+                    // Ignore initial argument exceptions
-+                } catch (Exception e) {
-+                    LOGGER.error("Error loading plugin: " + e.getMessage(), e);
-+                }
-+            });
++            .forEach(consumer);
 +    }
 +
 +    public boolean isValidFile(Path path) {
@@ -5568,7 +5587,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    }
 +
 +    @Override
-+    public void registerProviders(EntrypointHandler entrypointHandler, Path context) throws Exception {
++    public Path prepareContext(Path context) throws IOException {
 +        String source = this.contextChecker.apply(context);
 +
 +        if (Files.notExists(context)) {
@@ -5585,17 +5604,23 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +        try {
 +            context = this.checkUpdate(context);
-+
-+            JarFile file = new JarFile(context.toFile(), true, JarFile.OPEN_READ, JarFile.runtimeVersion());
-+            PluginFileType<?, ?> type = PluginFileType.guessType(file);
-+            if (type == null) {
-+                throw new IllegalArgumentException(source + " does not contain a " + String.join(" or ", PluginFileType.getConfigTypes()) + "! Could not determine plugin type, cannot load a plugin from it!");
-+            }
-+
-+            type.register(entrypointHandler, file, context);
 +        } catch (Exception exception) {
-+            throw new RuntimeException(source + " failed to load!", exception);
++            throw new RuntimeException(source + " failed to update!", exception);
 +        }
++        return context;
++    }
++
++    @Override
++    public void registerProviders(EntrypointHandler entrypointHandler, Path context) throws Exception {
++        String source = this.contextChecker.apply(context);
++
++        JarFile file = new JarFile(context.toFile(), true, JarFile.OPEN_READ, JarFile.runtimeVersion());
++        PluginFileType<?, ?> type = PluginFileType.guessType(file);
++        if (type == null) {
++            throw new IllegalArgumentException(source + " does not contain a " + String.join(" or ", PluginFileType.getConfigTypes()) + "! Could not determine plugin type, cannot load a plugin from it!");
++        }
++
++        type.register(entrypointHandler, file, context);
 +    }
 +
 +    /**
@@ -5603,7 +5628,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +     *
 +     * @param file
 +     */
-+    private Path checkUpdate(Path file) throws Exception {
++    private Path checkUpdate(Path file) throws InvalidPluginException {
 +        PluginInitializerManager pluginSystem = PluginInitializerManager.instance();
 +        Path updateDirectory = pluginSystem.pluginUpdatePath();
 +        if (updateDirectory == null || !Files.isDirectory(updateDirectory)) {
@@ -5703,25 +5728,30 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +import com.mojang.logging.LogUtils;
 +import io.papermc.paper.plugin.entrypoint.EntrypointHandler;
++import java.nio.file.Path;
 +import org.slf4j.Logger;
 +
-+import java.io.File;
 +import java.util.List;
 +
 +/**
 + * Registers providers at the provided files in the add-plugin argument.
 + */
-+public class PluginFlagProviderSource implements ProviderSource<List<File>> {
++public class PluginFlagProviderSource implements ProviderSource<List<Path>> {
 +
 +    public static final PluginFlagProviderSource INSTANCE = new PluginFlagProviderSource();
 +    private static final Logger LOGGER = LogUtils.getClassLogger();
 +    private final FileProviderSource providerSource = new FileProviderSource("File '%s' specified through 'add-plugin' argument"::formatted);
 +
 +    @Override
-+    public void registerProviders(EntrypointHandler entrypointHandler, List<File> context) {
-+        for (File file : context) {
++    public List<Path> prepareContext(List<Path> context) {
++        return context;
++    }
++
++    @Override
++    public void registerProviders(EntrypointHandler entrypointHandler, List<Path> context) {
++        for (Path path : context) {
 +            try {
-+                this.providerSource.registerProviders(entrypointHandler, file.toPath());
++                this.providerSource.registerProviders(entrypointHandler, path);
 +            } catch (Exception e) {
 +                LOGGER.error("Error loading plugin: " + e.getMessage(), e);
 +            }
@@ -5737,6 +5767,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +package io.papermc.paper.plugin.provider.source;
 +
 +import io.papermc.paper.plugin.entrypoint.EntrypointHandler;
++import java.io.IOException;
 +
 +/**
 + * A provider source is responsible for giving PluginTypes an EntrypointHandler for
@@ -5746,6 +5777,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 + */
 +public interface ProviderSource<C> {
 +
++    C prepareContext(C context) throws IOException;
++
 +    void registerProviders(EntrypointHandler entrypointHandler, C context) throws Throwable;
 +}
 diff --git a/src/main/java/io/papermc/paper/plugin/provider/type/PluginFileType.java b/src/main/java/io/papermc/paper/plugin/provider/type/PluginFileType.java
@@ -6273,7 +6306,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +class PaperPluginProviderFactory implements PluginTypeFactory<PaperPluginParent, PaperPluginMeta> {
 +
 +    @Override
-+    public PaperPluginParent build(JarFile file, PaperPluginMeta configuration, Path source) throws Exception {
++    public PaperPluginParent build(JarFile file, PaperPluginMeta configuration, Path source) {
 +        Logger jul = PaperPluginLogger.getLogger(configuration);
 +        ComponentLogger logger = ComponentLogger.logger(jul.getName());
 +        PluginProviderContext context = PluginProviderContextImpl.create(configuration, logger, source);
@@ -6296,7 +6329,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    }
 +
 +    @Override
-+    public PaperPluginMeta create(JarFile file, JarEntry config) throws Exception {
++    public PaperPluginMeta create(JarFile file, JarEntry config) throws IOException {
 +        PaperPluginMeta configuration;
 +        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(file.getInputStream(config)))) {
 +            configuration = PaperPluginMeta.create(bufferedReader);
@@ -6609,7 +6642,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +class SpigotPluginProviderFactory implements PluginTypeFactory<SpigotPluginProvider, PluginDescriptionFile> {
 +
 +    @Override
-+    public SpigotPluginProvider build(JarFile file, PluginDescriptionFile configuration, Path source) throws Exception {
++    public SpigotPluginProvider build(JarFile file, PluginDescriptionFile configuration, Path source) throws InvalidDescriptionException {
 +        // Copied from SimplePluginManager#loadPlugins
 +        // Spigot doesn't validate the name when the config is created, and instead when the plugin is loaded.
 +        // Paper plugin configuration will do these checks in config serializer instead of when this is created.
@@ -6624,7 +6657,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    }
 +
 +    @Override
-+    public PluginDescriptionFile create(JarFile file, JarEntry config) throws Exception {
++    public PluginDescriptionFile create(JarFile file, JarEntry config) throws InvalidDescriptionException {
 +        PluginDescriptionFile descriptionFile;
 +        try (InputStream inputStream = file.getInputStream(config)) {
 +            descriptionFile = new PluginDescriptionFile(inputStream);
@@ -6956,12 +6989,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import io.papermc.paper.plugin.provider.source.ProviderSource;
 +import org.slf4j.Logger;
 +
-+public class EntrypointUtil {
++public final class EntrypointUtil {
 +
 +    private static final Logger LOGGER = LogUtils.getClassLogger();
 +
 +    public static <C> void registerProvidersFromSource(ProviderSource<C> source, C context) {
 +        try {
++            context = source.prepareContext(context);
 +            source.registerProviders(LaunchEntryPointHandler.INSTANCE, context);
 +        } catch (Throwable e) {
 +            LOGGER.error(e.getMessage(), e);