plugin manager: fix plugins with multiple dependencies
If one plugin has multiple dependencies this would throw a concurrent modification exception due to iterating the successors after removing the edge Fill out javadoc for topologicalSort Co-authored-by: Adam <Adam@sigterm.info>
This commit is contained in:
@@ -631,11 +631,14 @@ public class PluginManager
|
|||||||
/**
|
/**
|
||||||
* Topologically sort a graph. Uses Kahn's algorithm.
|
* Topologically sort a graph. Uses Kahn's algorithm.
|
||||||
*
|
*
|
||||||
* @param graph
|
* @param graph - A directed graph
|
||||||
* @param <T>
|
* @param <T> - The type of the item contained in the nodes of the graph
|
||||||
* @return
|
* @return - A topologically sorted list corresponding to graph.
|
||||||
|
* <p>
|
||||||
|
* Multiple invocations with the same arguments may return lists that are not equal.
|
||||||
*/
|
*/
|
||||||
private <T> List<T> topologicalSort(Graph<T> graph)
|
@VisibleForTesting
|
||||||
|
static <T> List<T> topologicalSort(Graph<T> graph)
|
||||||
{
|
{
|
||||||
MutableGraph<T> graphCopy = Graphs.copyOf(graph);
|
MutableGraph<T> graphCopy = Graphs.copyOf(graph);
|
||||||
List<T> l = new ArrayList<>();
|
List<T> l = new ArrayList<>();
|
||||||
@@ -650,7 +653,7 @@ public class PluginManager
|
|||||||
|
|
||||||
l.add(n);
|
l.add(n);
|
||||||
|
|
||||||
for (T m : graphCopy.successors(n))
|
for (T m : new HashSet<>(graphCopy.successors(n)))
|
||||||
{
|
{
|
||||||
graphCopy.removeEdge(n, m);
|
graphCopy.removeEdge(n, m);
|
||||||
if (graphCopy.inDegree(m) == 0)
|
if (graphCopy.inDegree(m) == 0)
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.client.plugins;
|
package net.runelite.client.plugins;
|
||||||
|
|
||||||
|
import com.google.common.graph.GraphBuilder;
|
||||||
|
import com.google.common.graph.MutableGraph;
|
||||||
import com.google.common.reflect.ClassPath;
|
import com.google.common.reflect.ClassPath;
|
||||||
import com.google.common.reflect.ClassPath.ClassInfo;
|
import com.google.common.reflect.ClassPath.ClassInfo;
|
||||||
import com.google.inject.Guice;
|
import com.google.inject.Guice;
|
||||||
@@ -40,6 +42,7 @@ import java.io.PrintWriter;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
@@ -51,6 +54,7 @@ import net.runelite.client.eventbus.EventBus;
|
|||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -208,4 +212,23 @@ public class PluginManagerTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTopologicalSort()
|
||||||
|
{
|
||||||
|
MutableGraph<Integer> graph = GraphBuilder
|
||||||
|
.directed()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
graph.addNode(1);
|
||||||
|
graph.addNode(2);
|
||||||
|
graph.addNode(3);
|
||||||
|
|
||||||
|
graph.putEdge(1, 2);
|
||||||
|
graph.putEdge(1, 3);
|
||||||
|
|
||||||
|
List<Integer> sorted = PluginManager.topologicalSort(graph);
|
||||||
|
|
||||||
|
assertTrue(sorted.indexOf(1) < sorted.indexOf(2));
|
||||||
|
assertTrue(sorted.indexOf(1) < sorted.indexOf(3));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user