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.
This commit is contained in:
Gijs de Jong 2023-11-25 23:57:12 +01:00
parent a3ef5fd4dd
commit 3d12fa65fa

View File

@ -272,7 +272,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import io.papermc.paper.plugin.entrypoint.classloader.group.SpigotPluginClassLoaderGroup; +import io.papermc.paper.plugin.entrypoint.classloader.group.SpigotPluginClassLoaderGroup;
+import io.papermc.paper.plugin.entrypoint.classloader.group.StaticPluginClassLoaderGroup; +import io.papermc.paper.plugin.entrypoint.classloader.group.StaticPluginClassLoaderGroup;
+import io.papermc.paper.plugin.entrypoint.dependency.GraphDependencyContext; +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.provider.entrypoint.DependencyContext;
+import io.papermc.paper.plugin.entrypoint.strategy.modern.ModernPluginLoadingStrategy; +import io.papermc.paper.plugin.entrypoint.strategy.modern.ModernPluginLoadingStrategy;
+import io.papermc.paper.plugin.entrypoint.strategy.ProviderConfiguration; +import io.papermc.paper.plugin.entrypoint.strategy.ProviderConfiguration;
@ -397,7 +397,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return false; + return false;
+ } + }
+ }); + });
+ modernPluginLoadingStrategy.loadProviders(pluginProviders, new MetaDependencyTree(GraphBuilder.directed().build())); + modernPluginLoadingStrategy.loadProviders(pluginProviders, new SimpleMetaDependencyTree(GraphBuilder.directed().build()));
+ +
+ rootProviders.add(entry.getKey().getDebugName(), entrypoint); + 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<String> 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 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 new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
@ -1804,17 +1854,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import io.papermc.paper.plugin.provider.PluginProvider; +import io.papermc.paper.plugin.provider.PluginProvider;
+import io.papermc.paper.plugin.provider.entrypoint.DependencyContext; +import io.papermc.paper.plugin.provider.entrypoint.DependencyContext;
+import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.NotNull;
+
+import java.util.HashSet; +import java.util.HashSet;
+import java.util.Set; +import java.util.Set;
+ +
+public class MetaDependencyTree implements DependencyContext { +public abstract class MetaDependencyTree implements DependencyContext {
+ +
+ private final MutableGraph<String> graph; + protected final MutableGraph<String> graph;
+ +
+ // We need to upkeep a separate collection since when populating + // We need to upkeep a separate collection since when populating
+ // a graph it adds nodes even if they are not present + // a graph it adds nodes even if they are not present
+ private final Set<String> dependencies = new HashSet<>(); + protected final Set<String> dependencies = new HashSet<>();
+ +
+ public MetaDependencyTree() { + public MetaDependencyTree() {
+ this(GraphBuilder.directed().build()); + this(GraphBuilder.directed().build());
@ -1824,23 +1873,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ this.graph = graph; + this.graph = graph;
+ } + }
+ +
+ public void add(PluginProvider<?> provider) {
+ add(provider.getMeta());
+ }
+
+ public void remove(PluginProvider<?> provider) {
+ remove(provider.getMeta());
+ }
+
+ public void add(PluginMeta configuration) { + public void add(PluginMeta configuration) {
+ String identifier = configuration.getName(); + String identifier = configuration.getName();
+ // Build a validated provider's dependencies into the graph + // Build a validated provider's dependencies into the graph
+ for (String dependency : configuration.getPluginDependencies()) { + this.registerDependencies(identifier, configuration);
+ this.graph.putEdge(identifier, dependency);
+ }
+ for (String dependency : configuration.getPluginSoftDependencies()) {
+ this.graph.putEdge(identifier, dependency);
+ }
+ +
+ this.graph.addNode(identifier); // Make sure dependencies at least have a node + this.graph.addNode(identifier); // Make sure dependencies at least have a node
+ +
@ -1852,15 +1888,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ this.dependencies.add(identifier); + this.dependencies.add(identifier);
+ } + }
+ +
+ protected abstract void registerDependencies(String identifier, PluginMeta meta);
+
+ public void remove(PluginMeta configuration) { + public void remove(PluginMeta configuration) {
+ String identifier = configuration.getName(); + String identifier = configuration.getName();
+ // Remove a validated provider's dependencies into the graph + // Remove a validated provider's dependencies into the graph
+ for (String dependency : configuration.getPluginDependencies()) { + this.unregisterDependencies(identifier, configuration);
+ this.graph.removeEdge(identifier, dependency);
+ }
+ for (String dependency : configuration.getPluginSoftDependencies()) {
+ this.graph.removeEdge(identifier, dependency);
+ }
+ +
+ this.graph.removeNode(identifier); // Remove root node + this.graph.removeNode(identifier); // Remove root node
+ +
@ -1872,6 +1905,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ this.dependencies.remove(identifier); + this.dependencies.remove(identifier);
+ } + }
+ +
+ protected abstract void unregisterDependencies(String identifier, PluginMeta meta);
+
+ @Override + @Override
+ public boolean isTransitiveDependency(@NotNull PluginMeta plugin, @NotNull PluginMeta depend) { + public boolean isTransitiveDependency(@NotNull PluginMeta plugin, @NotNull PluginMeta depend) {
+ String pluginIdentifier = plugin.getName(); + String pluginIdentifier = plugin.getName();
@ -1896,14 +1931,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return this.dependencies.contains(pluginIdentifier); + return this.dependencies.contains(pluginIdentifier);
+ } + }
+ +
+ // Used by the legacy loader -- this isn't recommended
+ public void addDirectDependency(String dependency) { + public void addDirectDependency(String dependency) {
+ this.dependencies.add(dependency); + this.dependencies.add(dependency);
+ } + }
+ +
+ @Override + @Override
+ public String toString() { + public String toString() {
+ return "ProviderDependencyTree{" + + return "SimpleDependencyTree{" +
+ "graph=" + this.graph + + "graph=" + this.graph +
+ '}'; + '}';
+ } + }
@ -1911,6 +1945,61 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ public MutableGraph<String> getGraph() { + public MutableGraph<String> getGraph() {
+ return graph; + 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<String> 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 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 new file mode 100644
@ -3216,7 +3305,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ +
+ @Override + @Override
+ public MetaDependencyTree getDependencyTree() { + public MetaDependencyTree createDependencyTree() {
+ return this.dependencyTree; + return this.dependencyTree;
+ } + }
+} +}
@ -3690,6 +3779,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import io.papermc.paper.plugin.configuration.PluginMeta; +import io.papermc.paper.plugin.configuration.PluginMeta;
+import io.papermc.paper.plugin.entrypoint.Entrypoint; +import io.papermc.paper.plugin.entrypoint.Entrypoint;
+import io.papermc.paper.plugin.entrypoint.dependency.MetaDependencyTree; +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.PluginGraphCycleException;
+import io.papermc.paper.plugin.provider.classloader.ConfiguredPluginClassLoader; +import io.papermc.paper.plugin.provider.classloader.ConfiguredPluginClassLoader;
+import io.papermc.paper.plugin.provider.classloader.PaperClassLoaderStorage; +import io.papermc.paper.plugin.provider.classloader.PaperClassLoaderStorage;
@ -3739,7 +3829,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ private final CommandMap commandMap; + private final CommandMap commandMap;
+ private final Server server; + 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) { + public PaperPluginInstanceManager(PluginManager pluginManager, CommandMap commandMap, Server server) {
+ this.commandMap = commandMap; + this.commandMap = commandMap;
@ -4364,7 +4454,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ +
+ @Override + @Override
+ public MetaDependencyTree getDependencyTree() { + public MetaDependencyTree createDependencyTree() {
+ return this.dependencyTree; + return this.dependencyTree;
+ } + }
+} +}
@ -6556,7 +6646,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import io.papermc.paper.plugin.bootstrap.BootstrapContext; +import io.papermc.paper.plugin.bootstrap.BootstrapContext;
+import io.papermc.paper.plugin.bootstrap.PluginBootstrap; +import io.papermc.paper.plugin.bootstrap.PluginBootstrap;
+import io.papermc.paper.plugin.bootstrap.PluginBootstrapContextImpl; +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.DependencyContextHolder;
+import io.papermc.paper.plugin.entrypoint.dependency.MetaDependencyTree;
+import io.papermc.paper.plugin.entrypoint.strategy.ProviderConfiguration; +import io.papermc.paper.plugin.entrypoint.strategy.ProviderConfiguration;
+import io.papermc.paper.plugin.entrypoint.strategy.modern.ModernPluginLoadingStrategy; +import io.papermc.paper.plugin.entrypoint.strategy.modern.ModernPluginLoadingStrategy;
+import io.papermc.paper.plugin.provider.PluginProvider; +import io.papermc.paper.plugin.provider.PluginProvider;
@ -6603,6 +6695,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ +
+ @Override + @Override
+ public MetaDependencyTree createDependencyTree() {
+ return new BootstrapMetaDependencyTree();
+ }
+
+ @Override
+ public String toString() { + public String toString() {
+ return "BOOTSTRAP:" + super.toString(); + return "BOOTSTRAP:" + super.toString();
+ } + }
@ -6638,6 +6735,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ @@ -0,0 +0,0 @@
+package io.papermc.paper.plugin.storage; +package io.papermc.paper.plugin.storage;
+ +
+import io.papermc.paper.plugin.entrypoint.dependency.MetaDependencyTree;
+import io.papermc.paper.plugin.provider.PluginProvider; +import io.papermc.paper.plugin.provider.PluginProvider;
+ +
+/** +/**
@ -6649,6 +6747,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+ void register(PluginProvider<T> provider); + void register(PluginProvider<T> provider);
+ +
+ MetaDependencyTree createDependencyTree();
+
+ void enter(); + void enter();
+ +
+ Iterable<PluginProvider<T>> getRegisteredProviders(); + Iterable<PluginProvider<T>> getRegisteredProviders();
@ -6739,10 +6839,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+package io.papermc.paper.plugin.storage; +package io.papermc.paper.plugin.storage;
+ +
+import com.google.common.graph.GraphBuilder; +import com.google.common.graph.GraphBuilder;
+import com.google.common.graph.MutableGraph;
+import com.mojang.logging.LogUtils; +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.MetaDependencyTree;
+import io.papermc.paper.plugin.entrypoint.dependency.SimpleMetaDependencyTree;
+import io.papermc.paper.plugin.entrypoint.strategy.PluginGraphCycleException; +import io.papermc.paper.plugin.entrypoint.strategy.PluginGraphCycleException;
+import io.papermc.paper.plugin.entrypoint.strategy.ProviderLoadingStrategy; +import io.papermc.paper.plugin.entrypoint.strategy.ProviderLoadingStrategy;
+import io.papermc.paper.plugin.provider.PluginProvider; +import io.papermc.paper.plugin.provider.PluginProvider;
@ -6774,7 +6873,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ this.filterLoadingProviders(providerList); + this.filterLoadingProviders(providerList);
+ +
+ try { + try {
+ for (ProviderLoadingStrategy.ProviderPair<T> providerPair : this.strategy.loadProviders(providerList, this.getDependencyTree())) { + for (ProviderLoadingStrategy.ProviderPair<T> providerPair : this.strategy.loadProviders(providerList, this.createDependencyTree())) {
+ this.processProvided(providerPair.provider(), providerPair.provided()); + this.processProvided(providerPair.provider(), providerPair.provided());
+ } + }
+ } catch (PluginGraphCycleException exception) { + } catch (PluginGraphCycleException exception) {
@ -6782,8 +6881,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ } + }
+ +
+ public MetaDependencyTree getDependencyTree() { + @Override
+ return new MetaDependencyTree(GraphBuilder.directed().build()); + public MetaDependencyTree createDependencyTree() {
+ return new SimpleMetaDependencyTree(GraphBuilder.directed().build());
+ } + }
+ +
+ @Override + @Override
@ -7281,6 +7381,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+package io.papermc.paper.plugin; +package io.papermc.paper.plugin;
+ +
+import io.papermc.paper.plugin.entrypoint.dependency.MetaDependencyTree; +import io.papermc.paper.plugin.entrypoint.dependency.MetaDependencyTree;
+import io.papermc.paper.plugin.entrypoint.dependency.SimpleMetaDependencyTree;
+import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Test;
+ +
+import java.util.List; +import java.util.List;
@ -7311,7 +7412,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+ @Test + @Test
+ public void testDependencyTree() { + public void testDependencyTree() {
+ MetaDependencyTree tree = new MetaDependencyTree(); + MetaDependencyTree tree = new SimpleMetaDependencyTree();
+ tree.add(MAIN); + tree.add(MAIN);
+ tree.add(HARD_DEPENDENCY_1); + tree.add(HARD_DEPENDENCY_1);
+ tree.add(SOFT_DEPENDENCY_1); + tree.add(SOFT_DEPENDENCY_1);
@ -7346,7 +7447,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+package io.papermc.paper.plugin; +package io.papermc.paper.plugin;
+ +
+import com.google.common.graph.GraphBuilder; +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.provider.entrypoint.DependencyContext;
+import io.papermc.paper.plugin.entrypoint.strategy.modern.ModernPluginLoadingStrategy; +import io.papermc.paper.plugin.entrypoint.strategy.modern.ModernPluginLoadingStrategy;
+import io.papermc.paper.plugin.entrypoint.strategy.ProviderConfiguration; +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 + @Test