From 3d12fa65fa37fd8044c7798946cdfced6d5f9843 Mon Sep 17 00:00:00 2001 From: Gijs de Jong <14833076+oxkitsune@users.noreply.github.com> Date: Sat, 25 Nov 2023 23:57:12 +0100 Subject: [PATCH] Fix plugin bootstrap dependency tree population (#9963) This patch fixes a bug where the dependency tree used for classpath joining, wasn't built using the bootstrap dependencies, for plugin bootstrappers. --- patches/server/Paper-Plugins.patch | 179 ++++++++++++++++++++++------- 1 file changed, 140 insertions(+), 39 deletions(-) diff --git a/patches/server/Paper-Plugins.patch b/patches/server/Paper-Plugins.patch index e5dcd572f6..92800ea8b7 100644 --- a/patches/server/Paper-Plugins.patch +++ b/patches/server/Paper-Plugins.patch @@ -272,7 +272,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import io.papermc.paper.plugin.entrypoint.classloader.group.SpigotPluginClassLoaderGroup; +import io.papermc.paper.plugin.entrypoint.classloader.group.StaticPluginClassLoaderGroup; +import io.papermc.paper.plugin.entrypoint.dependency.GraphDependencyContext; -+import io.papermc.paper.plugin.entrypoint.dependency.MetaDependencyTree; ++import io.papermc.paper.plugin.entrypoint.dependency.SimpleMetaDependencyTree; +import io.papermc.paper.plugin.provider.entrypoint.DependencyContext; +import io.papermc.paper.plugin.entrypoint.strategy.modern.ModernPluginLoadingStrategy; +import io.papermc.paper.plugin.entrypoint.strategy.ProviderConfiguration; @@ -397,7 +397,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return false; + } + }); -+ modernPluginLoadingStrategy.loadProviders(pluginProviders, new MetaDependencyTree(GraphBuilder.directed().build())); ++ modernPluginLoadingStrategy.loadProviders(pluginProviders, new SimpleMetaDependencyTree(GraphBuilder.directed().build())); + + rootProviders.add(entry.getKey().getDebugName(), entrypoint); + } @@ -1714,6 +1714,56 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + '}'; + } +} +diff --git a/src/main/java/io/papermc/paper/plugin/entrypoint/dependency/BootstrapMetaDependencyTree.java b/src/main/java/io/papermc/paper/plugin/entrypoint/dependency/BootstrapMetaDependencyTree.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/entrypoint/dependency/BootstrapMetaDependencyTree.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.plugin.entrypoint.dependency; ++ ++import com.google.common.graph.GraphBuilder; ++import com.google.common.graph.MutableGraph; ++import io.papermc.paper.plugin.configuration.PluginMeta; ++import io.papermc.paper.plugin.provider.configuration.PaperPluginMeta; ++ ++public class BootstrapMetaDependencyTree extends MetaDependencyTree { ++ public BootstrapMetaDependencyTree() { ++ this(GraphBuilder.directed().build()); ++ } ++ ++ public BootstrapMetaDependencyTree(MutableGraph graph) { ++ super(graph); ++ } ++ ++ @Override ++ protected void registerDependencies(final String identifier, final PluginMeta meta) { ++ if (!(meta instanceof PaperPluginMeta paperPluginMeta)) { ++ throw new IllegalStateException("Only paper plugins can have a bootstrapper!"); ++ } ++ // Build a validated provider's dependencies into the graph ++ for (String dependency : paperPluginMeta.getBoostrapDependencies().keySet()) { ++ this.graph.putEdge(identifier, dependency); ++ } ++ } ++ ++ @Override ++ protected void unregisterDependencies(final String identifier, final PluginMeta meta) { ++ if (!(meta instanceof PaperPluginMeta paperPluginMeta)) { ++ throw new IllegalStateException("PluginMeta must be a PaperPluginMeta"); ++ } ++ ++ // Build a validated provider's dependencies into the graph ++ for (String dependency : paperPluginMeta.getBoostrapDependencies().keySet()) { ++ this.graph.removeEdge(identifier, dependency); ++ } ++ } ++ ++ @Override ++ public String toString() { ++ return "BootstrapDependencyTree{" + "graph=" + this.graph + '}'; ++ } ++} diff --git a/src/main/java/io/papermc/paper/plugin/entrypoint/dependency/DependencyContextHolder.java b/src/main/java/io/papermc/paper/plugin/entrypoint/dependency/DependencyContextHolder.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 @@ -1804,17 +1854,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import io.papermc.paper.plugin.provider.PluginProvider; +import io.papermc.paper.plugin.provider.entrypoint.DependencyContext; +import org.jetbrains.annotations.NotNull; -+ +import java.util.HashSet; +import java.util.Set; + -+public class MetaDependencyTree implements DependencyContext { ++public abstract class MetaDependencyTree implements DependencyContext { + -+ private final MutableGraph graph; ++ protected final MutableGraph graph; + + // We need to upkeep a separate collection since when populating + // a graph it adds nodes even if they are not present -+ private final Set dependencies = new HashSet<>(); ++ protected final Set dependencies = new HashSet<>(); + + public MetaDependencyTree() { + this(GraphBuilder.directed().build()); @@ -1824,23 +1873,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.graph = graph; + } + -+ public void add(PluginProvider provider) { -+ add(provider.getMeta()); -+ } -+ -+ public void remove(PluginProvider provider) { -+ remove(provider.getMeta()); -+ } -+ + public void add(PluginMeta configuration) { + String identifier = configuration.getName(); + // Build a validated provider's dependencies into the graph -+ for (String dependency : configuration.getPluginDependencies()) { -+ this.graph.putEdge(identifier, dependency); -+ } -+ for (String dependency : configuration.getPluginSoftDependencies()) { -+ this.graph.putEdge(identifier, dependency); -+ } ++ this.registerDependencies(identifier, configuration); + + this.graph.addNode(identifier); // Make sure dependencies at least have a node + @@ -1852,15 +1888,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.dependencies.add(identifier); + } + ++ protected abstract void registerDependencies(String identifier, PluginMeta meta); ++ + public void remove(PluginMeta configuration) { + String identifier = configuration.getName(); + // Remove a validated provider's dependencies into the graph -+ for (String dependency : configuration.getPluginDependencies()) { -+ this.graph.removeEdge(identifier, dependency); -+ } -+ for (String dependency : configuration.getPluginSoftDependencies()) { -+ this.graph.removeEdge(identifier, dependency); -+ } ++ this.unregisterDependencies(identifier, configuration); + + this.graph.removeNode(identifier); // Remove root node + @@ -1872,6 +1905,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.dependencies.remove(identifier); + } + ++ protected abstract void unregisterDependencies(String identifier, PluginMeta meta); ++ + @Override + public boolean isTransitiveDependency(@NotNull PluginMeta plugin, @NotNull PluginMeta depend) { + String pluginIdentifier = plugin.getName(); @@ -1896,14 +1931,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return this.dependencies.contains(pluginIdentifier); + } + -+ // Used by the legacy loader -- this isn't recommended + public void addDirectDependency(String dependency) { + this.dependencies.add(dependency); + } + + @Override + public String toString() { -+ return "ProviderDependencyTree{" + ++ return "SimpleDependencyTree{" + + "graph=" + this.graph + + '}'; + } @@ -1911,6 +1945,61 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public MutableGraph getGraph() { + return graph; + } ++ ++ public void add(PluginProvider provider) { ++ this.add(provider.getMeta()); ++ } ++ ++ public void remove(PluginProvider provider) { ++ this.remove(provider.getMeta()); ++ } ++ ++} +diff --git a/src/main/java/io/papermc/paper/plugin/entrypoint/dependency/SimpleMetaDependencyTree.java b/src/main/java/io/papermc/paper/plugin/entrypoint/dependency/SimpleMetaDependencyTree.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/plugin/entrypoint/dependency/SimpleMetaDependencyTree.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.plugin.entrypoint.dependency; ++ ++import com.google.common.graph.GraphBuilder; ++import com.google.common.graph.Graphs; ++import com.google.common.graph.MutableGraph; ++import io.papermc.paper.plugin.configuration.PluginMeta; ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.HashSet; ++import java.util.Set; ++ ++public class SimpleMetaDependencyTree extends MetaDependencyTree { ++ ++ public SimpleMetaDependencyTree() { ++ } ++ ++ public SimpleMetaDependencyTree(final MutableGraph graph) { ++ super(graph); ++ } ++ ++ @Override ++ protected void registerDependencies(final String identifier, final PluginMeta meta) { ++ for (String dependency : meta.getPluginDependencies()) { ++ this.graph.putEdge(identifier, dependency); ++ } ++ for (String dependency : meta.getPluginSoftDependencies()) { ++ this.graph.putEdge(identifier, dependency); ++ } ++ } ++ ++ @Override ++ protected void unregisterDependencies(final String identifier, final PluginMeta meta) { ++ for (String dependency : meta.getPluginDependencies()) { ++ this.graph.removeEdge(identifier, dependency); ++ } ++ for (String dependency : meta.getPluginSoftDependencies()) { ++ this.graph.removeEdge(identifier, dependency); ++ } ++ } +} diff --git a/src/main/java/io/papermc/paper/plugin/entrypoint/strategy/JohnsonSimpleCycles.java b/src/main/java/io/papermc/paper/plugin/entrypoint/strategy/JohnsonSimpleCycles.java new file mode 100644 @@ -3216,7 +3305,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + @Override -+ public MetaDependencyTree getDependencyTree() { ++ public MetaDependencyTree createDependencyTree() { + return this.dependencyTree; + } +} @@ -3690,6 +3779,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import io.papermc.paper.plugin.configuration.PluginMeta; +import io.papermc.paper.plugin.entrypoint.Entrypoint; +import io.papermc.paper.plugin.entrypoint.dependency.MetaDependencyTree; ++import io.papermc.paper.plugin.entrypoint.dependency.SimpleMetaDependencyTree; +import io.papermc.paper.plugin.entrypoint.strategy.PluginGraphCycleException; +import io.papermc.paper.plugin.provider.classloader.ConfiguredPluginClassLoader; +import io.papermc.paper.plugin.provider.classloader.PaperClassLoaderStorage; @@ -3739,7 +3829,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + private final CommandMap commandMap; + private final Server server; + -+ private final MetaDependencyTree dependencyTree = new MetaDependencyTree(GraphBuilder.directed().build()); ++ private final MetaDependencyTree dependencyTree = new SimpleMetaDependencyTree(GraphBuilder.directed().build()); + + public PaperPluginInstanceManager(PluginManager pluginManager, CommandMap commandMap, Server server) { + this.commandMap = commandMap; @@ -4364,7 +4454,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + @Override -+ public MetaDependencyTree getDependencyTree() { ++ public MetaDependencyTree createDependencyTree() { + return this.dependencyTree; + } +} @@ -6556,7 +6646,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import io.papermc.paper.plugin.bootstrap.BootstrapContext; +import io.papermc.paper.plugin.bootstrap.PluginBootstrap; +import io.papermc.paper.plugin.bootstrap.PluginBootstrapContextImpl; ++import io.papermc.paper.plugin.entrypoint.dependency.BootstrapMetaDependencyTree; +import io.papermc.paper.plugin.entrypoint.dependency.DependencyContextHolder; ++import io.papermc.paper.plugin.entrypoint.dependency.MetaDependencyTree; +import io.papermc.paper.plugin.entrypoint.strategy.ProviderConfiguration; +import io.papermc.paper.plugin.entrypoint.strategy.modern.ModernPluginLoadingStrategy; +import io.papermc.paper.plugin.provider.PluginProvider; @@ -6603,6 +6695,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + @Override ++ public MetaDependencyTree createDependencyTree() { ++ return new BootstrapMetaDependencyTree(); ++ } ++ ++ @Override + public String toString() { + return "BOOTSTRAP:" + super.toString(); + } @@ -6638,6 +6735,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ +package io.papermc.paper.plugin.storage; + ++import io.papermc.paper.plugin.entrypoint.dependency.MetaDependencyTree; +import io.papermc.paper.plugin.provider.PluginProvider; + +/** @@ -6649,6 +6747,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + void register(PluginProvider provider); + ++ MetaDependencyTree createDependencyTree(); ++ + void enter(); + + Iterable> getRegisteredProviders(); @@ -6739,10 +6839,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +package io.papermc.paper.plugin.storage; + +import com.google.common.graph.GraphBuilder; -+import com.google.common.graph.MutableGraph; +import com.mojang.logging.LogUtils; -+import io.papermc.paper.plugin.entrypoint.dependency.GraphDependencyContext; +import io.papermc.paper.plugin.entrypoint.dependency.MetaDependencyTree; ++import io.papermc.paper.plugin.entrypoint.dependency.SimpleMetaDependencyTree; +import io.papermc.paper.plugin.entrypoint.strategy.PluginGraphCycleException; +import io.papermc.paper.plugin.entrypoint.strategy.ProviderLoadingStrategy; +import io.papermc.paper.plugin.provider.PluginProvider; @@ -6774,7 +6873,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.filterLoadingProviders(providerList); + + try { -+ for (ProviderLoadingStrategy.ProviderPair providerPair : this.strategy.loadProviders(providerList, this.getDependencyTree())) { ++ for (ProviderLoadingStrategy.ProviderPair providerPair : this.strategy.loadProviders(providerList, this.createDependencyTree())) { + this.processProvided(providerPair.provider(), providerPair.provided()); + } + } catch (PluginGraphCycleException exception) { @@ -6782,8 +6881,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } + -+ public MetaDependencyTree getDependencyTree() { -+ return new MetaDependencyTree(GraphBuilder.directed().build()); ++ @Override ++ public MetaDependencyTree createDependencyTree() { ++ return new SimpleMetaDependencyTree(GraphBuilder.directed().build()); + } + + @Override @@ -7281,6 +7381,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +package io.papermc.paper.plugin; + +import io.papermc.paper.plugin.entrypoint.dependency.MetaDependencyTree; ++import io.papermc.paper.plugin.entrypoint.dependency.SimpleMetaDependencyTree; +import org.junit.jupiter.api.Test; + +import java.util.List; @@ -7311,7 +7412,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + @Test + public void testDependencyTree() { -+ MetaDependencyTree tree = new MetaDependencyTree(); ++ MetaDependencyTree tree = new SimpleMetaDependencyTree(); + tree.add(MAIN); + tree.add(HARD_DEPENDENCY_1); + tree.add(SOFT_DEPENDENCY_1); @@ -7346,7 +7447,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +package io.papermc.paper.plugin; + +import com.google.common.graph.GraphBuilder; -+import io.papermc.paper.plugin.entrypoint.dependency.MetaDependencyTree; ++import io.papermc.paper.plugin.entrypoint.dependency.SimpleMetaDependencyTree; +import io.papermc.paper.plugin.provider.entrypoint.DependencyContext; +import io.papermc.paper.plugin.entrypoint.strategy.modern.ModernPluginLoadingStrategy; +import io.papermc.paper.plugin.entrypoint.strategy.ProviderConfiguration; @@ -7450,7 +7551,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + }); + -+ modernPluginLoadingStrategy.loadProviders(REGISTERED_PROVIDERS, new MetaDependencyTree(GraphBuilder.directed().build())); ++ modernPluginLoadingStrategy.loadProviders(REGISTERED_PROVIDERS, new SimpleMetaDependencyTree(GraphBuilder.directed().build())); + } + + @Test