Skip to content

Commit bd6129a

Browse files
committed
Major overhaul, to attempt better loading support.
1 parent 0155d06 commit bd6129a

11 files changed

Lines changed: 222 additions & 110 deletions

File tree

build.gradle

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ buildscript {
22
repositories {
33
mavenCentral()
44
mavenLocal()
5+
gradlePluginPortal()
56
maven {
67
url = uri("https://plugins.gradle.org/m2/")
78
}
@@ -14,7 +15,7 @@ buildscript {
1415
}
1516

1617
dependencies {
17-
classpath 'gradle.plugin.com.github.johnrengelman:shadow:7.1.2'
18+
classpath 'com.gradleup.shadow:shadow-gradle-plugin:+'
1819
}
1920
}
2021

@@ -23,6 +24,8 @@ plugins {
2324
}
2425

2526
apply plugin: 'maven-publish'
27+
apply plugin: 'com.gradleup.shadow'
28+
2629

2730
group = 'org.mangorage'
2831
version = getLatestGitTag() + "." + getLatestGitVersion()
@@ -55,6 +58,9 @@ repositories {
5558
dependencies {
5659
testImplementation platform('org.junit:junit-bom:5.10.0')
5760
testImplementation 'org.junit.jupiter:junit-jupiter'
61+
62+
implementation("com.google.code.gson:gson:2.10.1")
63+
shadow('com.google.code.gson:gson:2.10.1')
5864
}
5965

6066
test {
@@ -75,6 +81,15 @@ jar {
7581
}
7682
}
7783

84+
shadowJar {
85+
group "main tasks"
86+
archiveClassifier.set('')
87+
88+
excludes.remove('module-info.class')
89+
relocate('com.google.gson', 'mangobot.bootstrap.internal.shaded.com.google.gson')
90+
relocate('joptsimple', 'mangobot.bootstrap.internal.shaded.joptsimple')
91+
}
92+
7893
tasks.register('runMain', JavaExec) {
7994
group = 'application'
8095
description = 'Runs the main class.'
@@ -86,7 +101,7 @@ tasks.register('runMain', JavaExec) {
86101
publishing {
87102
publications.register("mangobotaddon", MavenPublication) {
88103
artifactId = 'mangobotbootstrap'
89-
artifact jar
104+
artifact shadowJar
90105
artifact sourcesJar
91106

92107
pom {

src/main/java/module-info.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module org.mangorage.bootstrap {
2-
requires jdk.unsupported;
32
requires java.scripting;
3+
requires static com.google.gson;
4+
requires static java.sql;
45

56
exports org.mangorage.bootstrap.api.transformer;
67
exports org.mangorage.bootstrap.api.module;

src/main/java/org/mangorage/bootstrap/Bootstrap.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.mangorage.bootstrap;
22

3+
import com.google.gson.Gson;
34
import org.mangorage.bootstrap.api.launch.ILaunchTarget;
45
import org.mangorage.bootstrap.internal.Util;
56
import org.mangorage.bootstrap.internal.MangoBotLaunchTarget;
@@ -15,6 +16,8 @@
1516

1617
public final class Bootstrap {
1718

19+
private static final Gson GSON = new Gson();
20+
1821
public static void main(String[] args) throws Throwable {
1922
if (!(args.length >= 2)) {
2023
throw new IllegalStateException("Need to define a launchTarget, --launchTarget mangobot");
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package org.mangorage.bootstrap.internal;
2+
3+
import com.google.gson.Gson;
4+
import com.google.gson.GsonBuilder;
5+
import org.mangorage.bootstrap.internal.util.Dependencies;
6+
import org.mangorage.bootstrap.internal.util.Result;
7+
8+
import java.io.FileNotFoundException;
9+
import java.io.IOException;
10+
import java.io.InputStream;
11+
import java.nio.charset.StandardCharsets;
12+
import java.nio.file.DirectoryStream;
13+
import java.nio.file.Files;
14+
import java.nio.file.Path;
15+
import java.util.ArrayList;
16+
import java.util.HashMap;
17+
import java.util.List;
18+
import java.util.Map;
19+
import java.util.jar.JarEntry;
20+
import java.util.jar.JarFile;
21+
22+
public final class DependencyHandler {
23+
private static final Gson GSON = new GsonBuilder().create();
24+
25+
public static Map<String, List<Result>> scanPackages(Path packagesPath, Path librariesPath) throws IOException {
26+
27+
final Map<String, List<Result>> results = new HashMap<>();
28+
29+
try (DirectoryStream<Path> stream = Files.newDirectoryStream(packagesPath)) {
30+
for (Path entry : stream) {
31+
final Dependencies dependenciesList = GSON.fromJson(
32+
readFileFromJar(entry, "installer-data/dependencies.json"),
33+
Dependencies.class
34+
);
35+
36+
dependenciesList.dependencies().forEach(dependency -> {
37+
final var result = JarHandler.resolveModuleName(
38+
librariesPath.resolve(dependency.output())
39+
);
40+
results.computeIfAbsent(result.name(), k -> new ArrayList<>()).add(result);
41+
});
42+
}
43+
}
44+
45+
return results;
46+
}
47+
48+
49+
public static String readFileFromJar(Path jarPath, String entryPath) throws IOException {
50+
try (JarFile jar = new JarFile(jarPath.toFile())) {
51+
JarEntry entry = jar.getJarEntry(entryPath);
52+
53+
if (entry == null) {
54+
throw new FileNotFoundException("Entry not found in jar: " + entryPath);
55+
}
56+
57+
try (InputStream in = jar.getInputStream(entry)) {
58+
return new String(in.readAllBytes(), StandardCharsets.UTF_8);
59+
}
60+
}
61+
}
62+
}

src/main/java/org/mangorage/bootstrap/internal/JarHandler.java

Lines changed: 4 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,18 @@
11
package org.mangorage.bootstrap.internal;
22

3-
import java.io.File;
3+
import org.mangorage.bootstrap.internal.util.ModuleNameOrigin;
4+
import org.mangorage.bootstrap.internal.util.Result;
5+
46
import java.io.IOException;
57
import java.io.UncheckedIOException;
68
import java.lang.module.ModuleFinder;
7-
import java.nio.file.DirectoryStream;
8-
import java.nio.file.Files;
99
import java.nio.file.Path;
10-
import java.nio.file.StandardCopyOption;
11-
import java.util.Comparator;
12-
import java.util.HashMap;
13-
import java.util.Map;
14-
import java.util.concurrent.atomic.AtomicReference;
1510
import java.util.jar.JarFile;
1611
import java.util.jar.Manifest;
1712

1813
public final class JarHandler {
1914

20-
interface UnsafeRunnable {
21-
void run() throws Exception;
22-
}
23-
24-
enum ModuleNameOrigin {
25-
MODULE_INFO, // Takes Highest priority
26-
MANIFEST,
27-
MANIFEST_BUNDLE_SYMBOLIC_NAME,
28-
MULTI_RELEASE,
29-
GUESSED // Takes lowest
30-
}
31-
32-
record Result(String name, ModuleNameOrigin origin, Path jar, AtomicReference<UnsafeRunnable> task) {
33-
public Result(String name, ModuleNameOrigin origin, Path jar) {
34-
this(name, origin, jar, new AtomicReference<>());
35-
}
36-
}
37-
38-
static void safeHandle(final Path source, final Path target) {
39-
try {
40-
handle(source, target);
41-
} catch (IOException e) {
42-
throw new RuntimeException(e);
43-
}
44-
}
45-
46-
static void handle(final Path source, final Path target) throws IOException {
47-
48-
if (Files.exists(target)) {
49-
deleteDirectory(target);
50-
}
51-
52-
Files.createDirectories(target);
53-
54-
Map<String, Result> seenModules = new HashMap<>();
55-
56-
try (DirectoryStream<Path> stream = Files.newDirectoryStream(source, "*.jar")) {
57-
for (Path jar : stream) {
58-
var module = resolveModuleName(jar);
59-
if (module == null) {
60-
System.out.println("Skipping non-module JAR: " + jar);
61-
continue;
62-
}
63-
64-
if (!seenModules.containsKey(module.name())) {
65-
Path dest = target.resolve(jar.getFileName());
66-
module.task().set(() -> Files.copy(jar, dest, StandardCopyOption.REPLACE_EXISTING));
67-
seenModules.put(module.name(), module);
68-
System.out.println("Added module: " + module.name() + " from " + jar + " Search Origin: " + module.origin());
69-
} else {
70-
if (seenModules.get(module.name()).origin() == ModuleNameOrigin.GUESSED && module.origin() != ModuleNameOrigin.GUESSED) {
71-
var oldModule = seenModules.get(module.name());
72-
Path dest = target.resolve(jar.getFileName());
73-
module.task().set(() -> Files.copy(jar, dest, StandardCopyOption.REPLACE_EXISTING));
74-
seenModules.put(module.name(), module);
75-
System.out.println("Swapped module: " + module.name() + " jar to " + jar + " from" + oldModule.jar() + " Search Origin: " + module.origin());
76-
continue;
77-
}
78-
79-
System.out.println("Duplicate module ignored: " + module.name() + " from " + jar + " Search Origin: " + module.origin());
80-
}
81-
}
82-
}
83-
84-
seenModules.forEach((string, result) -> {
85-
final var runnable = result.task().get();
86-
if (runnable != null)
87-
try {
88-
runnable.run();
89-
} catch (Exception e) {
90-
e.printStackTrace();
91-
}
92-
});
93-
94-
System.out.println("Finished deduplicating modules. Result at: " + target);
95-
}
96-
97-
static boolean check(Path path) {
98-
return path.toString().contains("okio") && !path.toString().contains("jvm");
99-
}
100-
101-
private static void deleteDirectory(Path dir) throws IOException {
102-
Files.walk(dir)
103-
.sorted(Comparator.reverseOrder())
104-
.map(Path::toFile)
105-
.forEach(File::delete);
106-
}
107-
108-
private static Result resolveModuleName(Path jarPath) {
15+
public static Result resolveModuleName(Path jarPath) {
10916
try (JarFile jarFile = new JarFile(jarPath.toFile())) {
11017

11118
String moduleName = null;

src/main/java/org/mangorage/bootstrap/internal/MangoBotLaunchTarget.java

Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,64 @@
11
package org.mangorage.bootstrap.internal;
22

33
import org.mangorage.bootstrap.api.launch.ILaunchTarget;
4+
import org.mangorage.bootstrap.internal.util.Result;
45

6+
import java.io.IOException;
57
import java.lang.module.Configuration;
68
import java.lang.module.ModuleFinder;
79
import java.nio.file.Files;
810
import java.nio.file.Path;
11+
import java.nio.file.StandardCopyOption;
12+
import java.util.Comparator;
13+
import java.util.HashMap;
914
import java.util.HashSet;
1015
import java.util.List;
16+
import java.util.Map;
1117
import java.util.Set;
1218

1319
import static org.mangorage.bootstrap.internal.Util.callMain;
1420

1521
public final class MangoBotLaunchTarget implements ILaunchTarget {
22+
23+
/**
24+
* Deletes the target directory if it exists, then copies all files from the list into it.
25+
*
26+
* @param files List of files to copy
27+
* @param targetDir Directory to copy files into
28+
* @throws IOException if anything goes wrong
29+
*/
30+
public static void copyFilesToDirectory(List<Path> files, Path targetDir) throws IOException {
31+
// Delete directory if it exists
32+
if (Files.exists(targetDir)) {
33+
deleteDirectoryRecursively(targetDir);
34+
}
35+
36+
// Recreate the empty directory
37+
Files.createDirectories(targetDir);
38+
39+
// Copy each file
40+
for (Path file : files) {
41+
if (!Files.isRegularFile(file)) continue; // skip garbage
42+
Path dest = targetDir.resolve(file.getFileName());
43+
Files.copy(file, dest, StandardCopyOption.REPLACE_EXISTING);
44+
}
45+
}
46+
47+
private static void deleteDirectoryRecursively(Path dir) throws IOException {
48+
if (!Files.exists(dir)) return;
49+
50+
// Walk the directory bottom-up and delete everything
51+
Files.walk(dir)
52+
.sorted((a, b) -> b.compareTo(a)) // delete children first
53+
.forEach(path -> {
54+
try {
55+
Files.delete(path);
56+
} catch (IOException e) {
57+
throw new RuntimeException("Failed to delete " + path, e);
58+
}
59+
});
60+
}
61+
1662
@Override
1763
public String getId() {
1864
return "mangobot";
@@ -21,26 +67,39 @@ public String getId() {
2167
@Override
2268
public void launch(ModuleLayer parent, String[] args) throws Throwable {
2369
final var librariesPath = Path.of("libraries");
24-
final var sortedLibrariesPath = Path.of("sorted-libraries");
2570
final var pluginsPath = Path.of("plugins");
2671

27-
JarHandler.safeHandle(librariesPath, sortedLibrariesPath);
2872

29-
List<Path> deleteFiles = List.of(
30-
sortedLibrariesPath.resolve("okio-3.6.0.jar")
31-
);
73+
final Map<String, List<Result>> dependencies = DependencyHandler.scanPackages(pluginsPath.toAbsolutePath(), librariesPath.toAbsolutePath());
74+
final Map<String, Result> finalDependencies = new HashMap<>();
3275

33-
for (Path deleteFile : deleteFiles) {
34-
Files.deleteIfExists(deleteFile);
35-
}
76+
dependencies.forEach((id, results) -> {
77+
final Result bestResult = results.stream()
78+
.min(Comparator.comparingInt(r -> r.origin().ordinal()))
79+
.get();
80+
finalDependencies.put(bestResult.name(), bestResult);
81+
});
82+
83+
Path sortedLibraries = Path.of("sorted-libraries").toAbsolutePath();
84+
final var list = dependencies.entrySet()
85+
.stream()
86+
.map(set -> set.getValue().getFirst().jar())
87+
.toList();
88+
89+
copyFilesToDirectory(list, sortedLibraries);
3690

3791
Set<String> moduleNames = new HashSet<>();
3892
moduleNames.addAll(Util.getModuleNames(pluginsPath));
39-
moduleNames.addAll(Util.getModuleNames(sortedLibrariesPath));
93+
moduleNames.addAll(Util.getModuleNames(sortedLibraries));
94+
95+
moduleNames.remove("kotlin-stdlib-common");
96+
97+
98+
4099

41100
final var moduleCfg = Configuration.resolve(
42101
ModuleFinder.of(
43-
sortedLibrariesPath
102+
sortedLibraries
44103
),
45104
List.of(
46105
parent.configuration()
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package org.mangorage.bootstrap.internal.util;
2+
3+
import java.util.List;
4+
5+
public record Dependencies(List<Dependency> dependencies) {}

0 commit comments

Comments
 (0)