mirror of
https://github.com/Minestom/Minestom.git
synced 2024-12-27 19:47:44 +01:00
Load extension dependencies
This commit is contained in:
parent
e474640687
commit
6df285723a
@ -1 +1 @@
|
||||
Subproject commit 08dfbb32bdb0c0f6ee2c5229f92fef3132668405
|
||||
Subproject commit 472b3c041c58bd0a4397fb9144b1035682022cbe
|
@ -4,6 +4,9 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j(topic = "minestom-extensions")
|
||||
final class DiscoveredExtension {
|
||||
@ -16,7 +19,7 @@ final class DiscoveredExtension {
|
||||
private String[] codeModifiers;
|
||||
private String[] dependencies;
|
||||
private ExternalDependencies externalDependencies;
|
||||
transient File[] files = new File[0];
|
||||
transient List<URL> files = new LinkedList<>();
|
||||
transient LoadStatus loadStatus = LoadStatus.LOAD_SUCCESS;
|
||||
|
||||
@NotNull
|
||||
@ -65,8 +68,8 @@ final class DiscoveredExtension {
|
||||
static void verifyIntegrity(@NotNull DiscoveredExtension extension) {
|
||||
if (extension.name == null) {
|
||||
StringBuilder fileList = new StringBuilder();
|
||||
for (File f : extension.files) {
|
||||
fileList.append(f.getAbsolutePath()).append(", ");
|
||||
for (URL f : extension.files) {
|
||||
fileList.append(f.toExternalForm()).append(", ");
|
||||
}
|
||||
log.error("Extension with no name. (at {}})", fileList);
|
||||
log.error("Extension at ({}) will not be loaded.", fileList);
|
||||
|
@ -0,0 +1,49 @@
|
||||
package net.minestom.server.extensions;
|
||||
|
||||
import net.minestom.dependencies.DependencyResolver;
|
||||
import net.minestom.dependencies.ResolvedDependency;
|
||||
import net.minestom.dependencies.UnresolvedDependencyException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Does NOT relocate extensions
|
||||
*/
|
||||
public class ExtensionDependencyResolver implements DependencyResolver {
|
||||
|
||||
private Map<String, DiscoveredExtension> extensionMap = new HashMap<>();
|
||||
|
||||
public ExtensionDependencyResolver(List<DiscoveredExtension> extensions) {
|
||||
for(DiscoveredExtension ext : extensions) {
|
||||
extensionMap.put(ext.getName(), ext);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ResolvedDependency resolve(@NotNull String extensionName, @NotNull File file) throws UnresolvedDependencyException {
|
||||
if(extensionMap.containsKey(extensionName)) {
|
||||
DiscoveredExtension ext = extensionMap.get(extensionName);
|
||||
// convert extension URLs to subdependencies
|
||||
List<ResolvedDependency> deps = new LinkedList<>();
|
||||
for(URL u : ext.files) {
|
||||
deps.add(new ResolvedDependency(u.toExternalForm(), u.toExternalForm(), "", u, new LinkedList<>()));
|
||||
}
|
||||
return new ResolvedDependency(ext.getName(), ext.getName(), ext.getVersion(), ext.files.get(0), deps);
|
||||
}
|
||||
throw new UnresolvedDependencyException("No extension named "+extensionName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String list = extensionMap.values().stream().map(entry -> entry.getName()).collect(Collectors.joining(", "));
|
||||
return "ExtensionDependencyResolver[" + list + "]";
|
||||
}
|
||||
}
|
@ -74,16 +74,8 @@ public class ExtensionManager {
|
||||
|
||||
for (DiscoveredExtension discoveredExtension : discoveredExtensions) {
|
||||
URLClassLoader loader;
|
||||
URL[] urls = new URL[discoveredExtension.files.length];
|
||||
try {
|
||||
for (int i = 0; i < urls.length; i++) {
|
||||
urls[i] = discoveredExtension.files[i].toURI().toURL();
|
||||
}
|
||||
loader = newClassLoader(urls);
|
||||
} catch (MalformedURLException e) {
|
||||
log.error("Failed to get URL.", e);
|
||||
continue;
|
||||
}
|
||||
URL[] urls = discoveredExtension.files.toArray(new URL[0]);
|
||||
loader = newClassLoader(urls);
|
||||
|
||||
// Create ExtensionDescription (authors, version etc.)
|
||||
String extensionName = discoveredExtension.getName();
|
||||
@ -187,7 +179,7 @@ public class ExtensionManager {
|
||||
InputStreamReader reader = new InputStreamReader(f.getInputStream(f.getEntry("extension.json")))) {
|
||||
|
||||
DiscoveredExtension extension = GSON.fromJson(reader, DiscoveredExtension.class);
|
||||
extension.files = new File[]{file};
|
||||
extension.files.add(file.toURI().toURL());
|
||||
|
||||
// Verify integrity and ensure defaults
|
||||
DiscoveredExtension.verifyIntegrity(extension);
|
||||
@ -207,7 +199,8 @@ public class ExtensionManager {
|
||||
final String extensionResources = System.getProperty(INDEV_RESOURCES_FOLDER);
|
||||
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(new File(extensionResources, "extension.json")))) {
|
||||
DiscoveredExtension extension = GSON.fromJson(reader, DiscoveredExtension.class);
|
||||
extension.files = new File[]{new File(extensionClasses), new File(extensionResources)};
|
||||
extension.files.add(new File(extensionClasses).toURI().toURL());
|
||||
extension.files.add(new File(extensionResources).toURI().toURL());
|
||||
|
||||
// Verify integrity and ensure defaults
|
||||
DiscoveredExtension.verifyIntegrity(extension);
|
||||
@ -293,6 +286,7 @@ public class ExtensionManager {
|
||||
}
|
||||
|
||||
private void loadDependencies(List<DiscoveredExtension> extensions) {
|
||||
ExtensionDependencyResolver extensionDependencyResolver = new ExtensionDependencyResolver(extensions);
|
||||
for (DiscoveredExtension ext : extensions) {
|
||||
try {
|
||||
DependencyGetter getter = new DependencyGetter();
|
||||
@ -314,12 +308,19 @@ public class ExtensionManager {
|
||||
repoList.add(new MavenRepository(repository.name, repository.url));
|
||||
}
|
||||
getter.addMavenResolver(repoList);
|
||||
getter.addResolver(extensionDependencyResolver);
|
||||
|
||||
for (var artifact : externalDependencies.artifacts) {
|
||||
var resolved = getter.get(artifact, dependenciesFolder);
|
||||
injectIntoClasspath(resolved.getContentsLocation(), ext);
|
||||
log.trace("Dependency of extension {}: {}", ext.getName(), resolved);
|
||||
}
|
||||
|
||||
for (var dependencyName : ext.getDependencies()) {
|
||||
var resolved = getter.get(dependencyName, dependenciesFolder);
|
||||
injectIntoClasspath(resolved.getContentsLocation(), ext);
|
||||
log.trace("Dependency of extension {}: {}", ext.getName(), resolved);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ext.loadStatus = DiscoveredExtension.LoadStatus.MISSING_DEPENDENCIES;
|
||||
log.error("Failed to load dependencies for extension {}", ext.getName());
|
||||
@ -330,17 +331,23 @@ public class ExtensionManager {
|
||||
}
|
||||
|
||||
private void injectIntoClasspath(URL dependency, DiscoveredExtension extension) {
|
||||
final ClassLoader cl = getClass().getClassLoader();
|
||||
extension.files.add(dependency);
|
||||
log.trace("Added dependency {} to extension {} classpath", dependency.toExternalForm(), extension.getName());
|
||||
/*final ClassLoader cl = getClass().getClassLoader();
|
||||
if (!(cl instanceof URLClassLoader)) {
|
||||
throw new IllegalStateException("Current class loader is not a URLClassLoader, but " + cl + ". This prevents adding URLs into the classpath at runtime.");
|
||||
}
|
||||
try {
|
||||
Method addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
||||
addURL.setAccessible(true);
|
||||
addURL.invoke(cl, dependency);
|
||||
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
||||
throw new RuntimeException("Failed to inject URL " + dependency + " into classpath. From extension " + extension.getName(), e);
|
||||
}
|
||||
if(cl instanceof MinestomOverwriteClassLoader) {
|
||||
((MinestomOverwriteClassLoader) cl).addURL(dependency); // no reflection warnings for us!
|
||||
} else {
|
||||
try {
|
||||
Method addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
||||
addURL.setAccessible(true);
|
||||
addURL.invoke(cl, dependency);
|
||||
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
||||
throw new RuntimeException("Failed to inject URL " + dependency + " into classpath. From extension " + extension.getName(), e);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/**
|
||||
@ -387,7 +394,7 @@ public class ExtensionManager {
|
||||
for (DiscoveredExtension extension : extensions) {
|
||||
try {
|
||||
for (String codeModifierClass : extension.getCodeModifiers()) {
|
||||
modifiableClassLoader.loadModifier(extension.files, codeModifierClass);
|
||||
modifiableClassLoader.loadModifier(extension.files.toArray(new File[0]), codeModifierClass);
|
||||
}
|
||||
if (!extension.getMixinConfig().isEmpty()) {
|
||||
final String mixinConfigFile = extension.getMixinConfig();
|
||||
@ -396,7 +403,7 @@ public class ExtensionManager {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("Failed to load code modifier for extension in files: " + Arrays.toString(extension.files), e);
|
||||
log.error("Failed to load code modifier for extension in files: " + extension.files.stream().map(u -> u.toExternalForm()).collect(Collectors.joining(", ")), e);
|
||||
}
|
||||
}
|
||||
log.info("Done loading code modifiers.");
|
||||
|
@ -8,6 +8,7 @@ import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
@ -158,7 +159,11 @@ public class MinestomOverwriteClassLoader extends URLClassLoader {
|
||||
if (name == null)
|
||||
throw new ClassNotFoundException();
|
||||
String path = name.replace(".", "/") + ".class";
|
||||
byte[] bytes = getResourceAsStream(path).readAllBytes();
|
||||
InputStream input = getResourceAsStream(path);
|
||||
if(input == null) {
|
||||
throw new ClassNotFoundException("Could not find resource "+path);
|
||||
}
|
||||
byte[] bytes = input.readAllBytes();
|
||||
if (transform && !isProtected(name)) {
|
||||
ClassReader reader = new ClassReader(bytes);
|
||||
ClassNode node = new ClassNode();
|
||||
|
Loading…
Reference in New Issue
Block a user