Experiment with reworking wrapper
This commit is contained in:
parent
d777b9f39d
commit
63bf7df080
|
@ -15,11 +15,11 @@ build_test:
|
|||
stage: build
|
||||
script:
|
||||
- TIMESTAMP=$(date +%s)
|
||||
- gradle --build-cache build publish -Pflavor=nogui -Ppublic -Ptimestamp=$TIMESTAMP
|
||||
- gradle --build-cache build :Inceptum:publish -Pflavor=fat -Ppublic -Ptimestamp=$TIMESTAMP
|
||||
- gradle --build-cache build :Inceptum:publish -Pflavor=windows -Ppublic -Ptimestamp=$TIMESTAMP
|
||||
- gradle --build-cache build :Inceptum:publish -Pflavor=linux -Ppublic -Ptimestamp=$TIMESTAMP
|
||||
- gradle --build-cache build :Inceptum:publish -Pflavor=macos -Ppublic -Ptimestamp=$TIMESTAMP
|
||||
- gradle --build-cache build publish -Pflavor=maven -Ppublic -Ptimestamp=$TIMESTAMP
|
||||
- gradle --build-cache build :launcher-dist:publish -Pflavor=fat -Pdist.platformOnly -Ppublic -Ptimestamp=$TIMESTAMP
|
||||
- gradle --build-cache build :launcher-dist:publish -Pflavor=windows -Pdist.platformOnly -Ppublic -Ptimestamp=$TIMESTAMP
|
||||
- gradle --build-cache build :launcher-dist:publish -Pflavor=linux -Pdist.platformOnly -Ppublic -Ptimestamp=$TIMESTAMP
|
||||
- gradle --build-cache build :launcher-dist:publish -Pflavor=macos -Pdist.platformOnly -Ppublic -Ptimestamp=$TIMESTAMP
|
||||
- gradle --build-cache :exportMetadata -Ppublic -Ptimestamp=$TIMESTAMP
|
||||
- mkdir -p build/libs
|
||||
- cp launcher-shadowed/build/libs/* build/libs/
|
||||
|
@ -75,11 +75,11 @@ deploy:
|
|||
- if: $CI_COMMIT_TAG && '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /^master/'
|
||||
stage: deploy
|
||||
script:
|
||||
- gradle --build-cache build publish -Pflavor=nogui -Ppublic -Prelease
|
||||
- gradle --build-cache build :Inceptum:publish -Pflavor=fat -Ppublic -Prelease
|
||||
- gradle --build-cache build :Inceptum:publish -Pflavor=windows -Ppublic -Prelease
|
||||
- gradle --build-cache build :Inceptum:publish -Pflavor=linux -Ppublic -Prelease
|
||||
- gradle --build-cache build :Inceptum:publish -Pflavor=macos -Ppublic -Prelease
|
||||
- gradle --build-cache build publish -Pflavor=maven -Ppublic -Prelease
|
||||
- gradle --build-cache build :launcher-dist:publish -Pflavor=fat -Pdist.platformOnly -Ppublic -Prelease
|
||||
- gradle --build-cache build :launcher-dist:publish -Pflavor=windows -Pdist.platformOnly -Ppublic -Prelease
|
||||
- gradle --build-cache build :launcher-dist:publish -Pflavor=linux -Pdist.platformOnly -Ppublic -Prelease
|
||||
- gradle --build-cache build :launcher-dist:publish -Pflavor=macos -Pdist.platformOnly -Ppublic -Prelease
|
||||
|
||||
pages:
|
||||
image: python:3.8-buster
|
||||
|
|
|
@ -18,8 +18,8 @@ if (File(".git").exists()) {
|
|||
|
||||
println("Building Inceptum $currentVer")
|
||||
|
||||
val timestamp: Long =
|
||||
if (project.hasProperty("timestamp")) "${project.property("timestamp")}".toLong() else (System.currentTimeMillis() / 1000L)
|
||||
val timestamp: Long = if (project.hasProperty("timestamp")) "${project.property("timestamp")}".toLong()
|
||||
else (System.currentTimeMillis() / 1000L)
|
||||
|
||||
allprojects {
|
||||
version = currentVer + if (project.hasProperty("release")) "" else "-$timestamp"
|
||||
|
@ -32,28 +32,60 @@ val logbackVersion by extra("1.3.0-alpha15")
|
|||
val jfCommonsVersion by extra("2022.9.4+14-8-34")
|
||||
val jgitVersion by extra("6.2.0.202206071550-r")
|
||||
val flavorProp: String by extra(if (project.hasProperty("flavor")) "${project.property("flavor")}" else "custom")
|
||||
if (flavorProp != "custom" && flavorProp != "maven" && flavorProp != "fat" && flavorProp != "windows" && flavorProp != "linux" && flavorProp != "macos")
|
||||
throw IllegalStateException("Unsupported flavor: $flavorProp")
|
||||
val flavor: String by extra(
|
||||
if (flavorProp != "custom") flavorProp else when (OperatingSystem.current()) {
|
||||
OperatingSystem.WINDOWS -> "windows"
|
||||
OperatingSystem.LINUX -> "linux"
|
||||
OperatingSystem.MAC_OS -> "macos"
|
||||
else -> throw IllegalStateException()
|
||||
else -> throw IllegalStateException("Unsupported OS: ${OperatingSystem.current()}")
|
||||
}
|
||||
)
|
||||
val isPublic by extra(project.hasProperty("public"))
|
||||
val isRelease by extra(project.hasProperty("release"))
|
||||
|
||||
val wrapperVersion by extra(1)
|
||||
|
||||
tasks.register("exportMetadata") {
|
||||
doLast {
|
||||
projectDir.resolve("version.json").writeText(
|
||||
"""
|
||||
{
|
||||
"wrapperVersion": $wrapperVersion,
|
||||
"version": "$version",
|
||||
"isPublic": $isPublic,
|
||||
"isRelease": $isRelease,
|
||||
"jvm": ${project(":common").extra["javaVersion"]}
|
||||
"jvm": ${project(":common").extra["javaVersion"]},
|
||||
"repositories": [
|
||||
"https://repo.maven.apache.org/maven2/",
|
||||
"https://gitlab.com/api/v4/projects/35745143/packages/maven"
|
||||
],
|
||||
"natives": {
|
||||
"windows": [
|
||||
"org.lwjgl:lwjgl:$lwjglVersion:natives-windows",
|
||||
"org.lwjgl:lwjgl-opengl:$lwjglVersion:natives-windows",
|
||||
"org.lwjgl:lwjgl-glfw:$lwjglVersion:natives-windows",
|
||||
"org.lwjgl:lwjgl-tinyfd:$lwjglVersion:natives-windows",
|
||||
"io.github.spair:imgui-java-natives-windows:$imguiVersion"
|
||||
],
|
||||
"linux": [
|
||||
"org.lwjgl:lwjgl:$lwjglVersion:natives-linux",
|
||||
"org.lwjgl:lwjgl-opengl:$lwjglVersion:natives-linux",
|
||||
"org.lwjgl:lwjgl-glfw:$lwjglVersion:natives-linux",
|
||||
"org.lwjgl:lwjgl-tinyfd:$lwjglVersion:natives-linux",
|
||||
"io.github.spair:imgui-java-natives-linux:$imguiVersion"
|
||||
],
|
||||
"macos": [
|
||||
"org.lwjgl:lwjgl:$lwjglVersion:natives-macos",
|
||||
"org.lwjgl:lwjgl-opengl:$lwjglVersion:natives-macos",
|
||||
"org.lwjgl:lwjgl-glfw:$lwjglVersion:natives-macos",
|
||||
"org.lwjgl:lwjgl-tinyfd:$lwjglVersion:natives-macos",
|
||||
"io.github.spair:imgui-java-natives-macos:$imguiVersion"
|
||||
]
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -43,14 +43,4 @@ val nativeExe by tasks.registering(FileOutput::class) {
|
|||
|
||||
if (rootProject.extra["flavor"] == "windows") {
|
||||
tasks.build.get().dependsOn(nativeExe)
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("mavenJava") {
|
||||
artifact(tasks.shadowJar) {
|
||||
builtBy(tasks.shadowJar)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,5 +22,6 @@ projectDir.resolve("src/main/java/io/gitlab/jfronny/inceptum/common/BuildMetadat
|
|||
public static final boolean IS_PUBLIC = ${rootProject.extra["isPublic"]};
|
||||
public static final boolean IS_RELEASE = ${rootProject.extra["isRelease"]};
|
||||
public static final int VM_VERSION = $javaVersion;
|
||||
public static final int WRAPPER_VERSION = ${rootProject.extra["wrapperVersion"]};
|
||||
}
|
||||
""".trimIndent())
|
||||
""".trimIndent())
|
||||
|
|
|
@ -23,6 +23,7 @@ public class MetaHolder {
|
|||
|
||||
public static final Path ACCOUNTS_PATH = BASE_PATH.resolve("accounts.json");
|
||||
public static final Path CONFIG_PATH = BASE_PATH.resolve("inceptum.json");
|
||||
public static final Path WRAPPER_CONFIG_PATH = BASE_PATH.resolve("wrapper.json");
|
||||
public static final Path NATIVES_DIR = BASE_PATH.resolve("natives");
|
||||
public static final Path FORCE_LOAD_PATH = NATIVES_DIR.resolve("forceload");
|
||||
public static final Path LIBRARIES_DIR = BASE_PATH.resolve("libraries");
|
||||
|
|
|
@ -84,6 +84,10 @@ public class Net {
|
|||
return res.toString();
|
||||
}
|
||||
|
||||
public static String downloadString(String url) throws IOException, URISyntaxException {
|
||||
return HttpUtils.get(url).sendString();
|
||||
}
|
||||
|
||||
public static String downloadString(String url, String sha1) throws IOException, URISyntaxException {
|
||||
return new String(downloadData(url, sha1), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package io.gitlab.jfronny.inceptum.common;
|
||||
|
||||
public class OutdatedException extends RuntimeException {
|
||||
public OutdatedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
package io.gitlab.jfronny.inceptum.common;
|
||||
|
||||
import io.gitlab.jfronny.commons.ComparableVersion;
|
||||
import io.gitlab.jfronny.inceptum.common.api.GitlabApi;
|
||||
import io.gitlab.jfronny.inceptum.common.model.gitlab.*;
|
||||
import io.gitlab.jfronny.inceptum.common.model.inceptum.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class UpdateChecker {
|
||||
private static final long PROJECT_ID = 30862253L;
|
||||
|
||||
public static UpdateInfo check(UpdateChannel channel, ComparableVersion current, String flavor, Consumer<UpdateChannel> channelInvalid) {
|
||||
try {
|
||||
int jvm = Runtime.version().feature();
|
||||
if (flavor.equals("custom")) {
|
||||
Utils.LOGGER.error("Custom build, skipping update check");
|
||||
return null;
|
||||
}
|
||||
GitlabProject project = GitlabApi.getProject(PROJECT_ID);
|
||||
GitlabPackage experimental = null;
|
||||
ComparableVersion experimentalVersion = null;
|
||||
GitlabPackage stable = null;
|
||||
ComparableVersion stableVersion = null;
|
||||
packageLoop:
|
||||
for (GitlabPackage info : GitlabApi.getPackages(project)) {
|
||||
if (info.status.equals("default") && info.name.equals("io/gitlab/jfronny/inceptum/Inceptum")) {
|
||||
for (GitlabPipeline pipeline : info.pipelines) {
|
||||
for (GitlabJob job : GitlabApi.getJobs(project, pipeline.id)) {
|
||||
if (!job.name.equals("build_test")) continue;
|
||||
try {
|
||||
VersionMetadata iv = Net.downloadObject(GitlabApi.PROJECTS + project.id + "/jobs/" + job.id + "/artifacts/version.json", VersionMetadata.class);
|
||||
if (iv.jvm > jvm) {
|
||||
Utils.LOGGER.error("A newer JVM is required to use the latest inceptum version. Please update!");
|
||||
continue packageLoop;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
continue packageLoop;
|
||||
}
|
||||
}
|
||||
if (pipeline.ref.equals("master") && pipeline.status.equals("success")) {
|
||||
ComparableVersion cvNew = new ComparableVersion(info.version);
|
||||
if (experimentalVersion == null || experimentalVersion.compareTo(cvNew) < 0) {
|
||||
experimental = info;
|
||||
experimentalVersion = cvNew;
|
||||
}
|
||||
if (!info.version.contains("-") && (stableVersion == null || stableVersion.compareTo(cvNew) < 0)) {
|
||||
stable = info;
|
||||
stableVersion = cvNew;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (experimental == null) {
|
||||
throw new IOException("No version could be found");
|
||||
} else if (stable == null && channel == UpdateChannel.Stable) {
|
||||
channel = UpdateChannel.CI;
|
||||
channelInvalid.accept(channel);
|
||||
}
|
||||
GitlabPackage info = switch (channel) {
|
||||
case CI -> experimental;
|
||||
case Stable -> stable;
|
||||
};
|
||||
Utils.LOGGER.info("Latest version is " + info.version + ", current is " + current);
|
||||
if (current.compareTo(new ComparableVersion(info.version)) >= 0) {
|
||||
Utils.LOGGER.info("Up-to-date");
|
||||
return null;
|
||||
}
|
||||
GitlabPackageFile file = GitlabApi.getFile(project, info, f -> f.file_name.endsWith('-' + flavor + ".jar"));
|
||||
if (file == null)
|
||||
Utils.LOGGER.error("No valid package was discovered");
|
||||
else
|
||||
return new UpdateInfo("https://gitlab.com/" + project.path_with_namespace + "/-/package_files/" + file.id + "/download", file.file_sha1, new ComparableVersion(info.version));
|
||||
} catch (IOException | URISyntaxException e) {
|
||||
Utils.LOGGER.error("Could not check for updates", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
package io.gitlab.jfronny.inceptum.common;
|
||||
|
||||
import io.gitlab.jfronny.commons.ComparableVersion;
|
||||
import io.gitlab.jfronny.commons.OSUtils;
|
||||
import io.gitlab.jfronny.commons.io.JFiles;
|
||||
import io.gitlab.jfronny.inceptum.common.api.GitlabApi;
|
||||
import io.gitlab.jfronny.inceptum.common.api.MavenApi;
|
||||
import io.gitlab.jfronny.inceptum.common.model.gitlab.*;
|
||||
import io.gitlab.jfronny.inceptum.common.model.inceptum.*;
|
||||
import io.gitlab.jfronny.inceptum.common.model.maven.MavenDependency;
|
||||
import io.gitlab.jfronny.inceptum.common.model.maven.Pom;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Updater {
|
||||
private static final long PROJECT_ID = 30862253L;
|
||||
private static final String PROJECT_MAVEN = "https://gitlab.com/api/v4/projects/" + PROJECT_ID + "/packages/maven/";
|
||||
|
||||
public static UpdateMetadata getUpdate() {
|
||||
return Updater.check(ConfigHolder.CONFIG.channel, BuildMetadata.VERSION, channel -> {
|
||||
Utils.LOGGER.error("No stable version was found, switching to experimental channel");
|
||||
ConfigHolder.CONFIG.channel = channel;
|
||||
ConfigHolder.saveConfig();
|
||||
});
|
||||
}
|
||||
|
||||
public static void update(UpdateMetadata source, boolean relaunch) throws IOException, URISyntaxException {
|
||||
if (Runtime.version().feature() < source.jvm) {
|
||||
throw new OutdatedException("A newer JVM version is required for the current build of Inceptum. Please update!");
|
||||
} else if (source.wrapperVersion > BuildMetadata.WRAPPER_VERSION) {
|
||||
throw new OutdatedException("The current build of Inceptum requires a newer wrapper version. Please update!");
|
||||
} else if (source.wrapperVersion < BuildMetadata.WRAPPER_VERSION) {
|
||||
throw new OutdatedException("The current build of Inceptum requires an older wrapper version. Please update!");
|
||||
}
|
||||
|
||||
Utils.LOGGER.info("Downloading version " + source.version);
|
||||
|
||||
WrapperConfig config = new WrapperConfig();
|
||||
config.natives = new HashMap<>();
|
||||
config.libraries = new LinkedList<>();
|
||||
config.repositories = new LinkedList<>(source.repositories);
|
||||
source.natives.forEach((k, v) -> config.natives.put(k, new LinkedList<>(v)));
|
||||
|
||||
downloadLibrary(source.repositories, "io.gitlab.jfronny.inceptum:launcher-dist:" + source.version, config.libraries);
|
||||
|
||||
List<String> currentLibraries = new LinkedList<>(config.libraries);
|
||||
if (source.natives.containsKey(Utils.getCurrentFlavor())) {
|
||||
List<String> natives = new LinkedList<>();
|
||||
for (String lib : source.natives.get(Utils.getCurrentFlavor())){
|
||||
downloadLibrary(source.repositories, lib, natives);
|
||||
}
|
||||
currentLibraries.addAll(natives);
|
||||
config.natives.put(Utils.getCurrentFlavor(), natives);
|
||||
}
|
||||
|
||||
JFiles.writeObject(MetaHolder.WRAPPER_CONFIG_PATH, config);
|
||||
|
||||
if (relaunch) {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
try {
|
||||
new ProcessBuilder(OSUtils.getJvmBinary(),
|
||||
"-cp",
|
||||
buildClasspath(currentLibraries.stream())
|
||||
.map(Path::toString)
|
||||
.collect(Collectors.joining("" + File.pathSeparatorChar))
|
||||
).inheritIO().start();
|
||||
} catch (IOException e) {
|
||||
Utils.LOGGER.error("Could not relaunch", e);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Path> getLaunchClasspath(WrapperConfig wrapperConfig) throws IOException, URISyntaxException {
|
||||
List<String> natives = wrapperConfig.natives.get(Utils.getCurrentFlavor());
|
||||
if (natives == null) natives = new LinkedList<>();
|
||||
List<String> libs = wrapperConfig.libraries;
|
||||
if (libs == null) libs = new LinkedList<>();
|
||||
|
||||
boolean configChanged = false;
|
||||
|
||||
for (String lib : libs) {
|
||||
Path p = artifactToPath(lib);
|
||||
if (!Files.exists(p)) {
|
||||
configChanged = true;
|
||||
downloadLibrary(wrapperConfig.repositories, lib, libs);
|
||||
}
|
||||
}
|
||||
for (String lib : natives) {
|
||||
Path p = artifactToPath(lib);
|
||||
if (!Files.exists(p)) {
|
||||
configChanged = true;
|
||||
downloadLibrary(wrapperConfig.repositories, lib, natives);
|
||||
}
|
||||
}
|
||||
|
||||
if (configChanged) JFiles.writeObject(MetaHolder.WRAPPER_CONFIG_PATH, wrapperConfig);
|
||||
|
||||
return buildClasspath(Stream.concat(libs.stream(), natives.stream())).toList();
|
||||
}
|
||||
|
||||
private static Stream<Path> buildClasspath(Stream<String> libraries) {
|
||||
return libraries.map(Updater::artifactToPath);
|
||||
}
|
||||
|
||||
private static void downloadLibrary(List<String> repositories, final String artifact, List<String> libraries) throws IOException, URISyntaxException {
|
||||
for (String repository : repositories) {
|
||||
Pom pom;
|
||||
try {
|
||||
pom = MavenApi.getPom(repository, artifact);
|
||||
} catch (IOException | URISyntaxException | XMLStreamException | SAXException ignored) {
|
||||
continue;
|
||||
}
|
||||
for (MavenDependency dependency : pom.dependencies) {
|
||||
String mvnName = dependency.groupId + ":" + dependency.artifactId + ":" + dependency.version;
|
||||
downloadLibrary(repositories, mvnName, libraries);
|
||||
}
|
||||
MavenApi.downloadLibrary(repository, artifact);
|
||||
libraries.add(artifact);
|
||||
return;
|
||||
}
|
||||
throw new IOException("Could not find any repository containing the artifact " + artifact + " (searched: " + String.join(", ", repositories) + ")");
|
||||
}
|
||||
|
||||
private static Path artifactToPath(String artifact) {
|
||||
return MetaHolder.LIBRARIES_DIR.resolve(MavenApi.mavenNotationToJarPath(artifact)).toAbsolutePath();
|
||||
}
|
||||
|
||||
public static @Nullable UpdateMetadata check(UpdateChannel channel, ComparableVersion current, Consumer<UpdateChannel> channelInvalid) {
|
||||
try {
|
||||
int jvm = Runtime.version().feature();
|
||||
GitlabProject project = GitlabApi.getProject(PROJECT_ID);
|
||||
UpdateMetadata experimental = null;
|
||||
UpdateMetadata stable = null;
|
||||
packageLoop:for (GitlabPackage info : GitlabApi.getPackages(project)) {
|
||||
if (info.status.equals("default") && info.name.equals("io/gitlab/jfronny/inceptum/Inceptum")) {
|
||||
pipelineLoop:for (GitlabPipeline pipeline : info.pipelines) {
|
||||
if (!pipeline.ref.equals("master")) continue pipelineLoop;
|
||||
if (!pipeline.status.equals("success")) {
|
||||
Utils.LOGGER.warn("Skipping failed CI build");
|
||||
continue pipelineLoop;
|
||||
}
|
||||
for (GitlabJob job : GitlabApi.getJobs(project, pipeline.id)) {
|
||||
if (!job.name.equals("build_test")) continue;
|
||||
try {
|
||||
UpdateMetadata update = Net.downloadObject(GitlabApi.PROJECTS + project.id + "/jobs/" + job.id + "/artifacts/version.json", UpdateMetadata.class);
|
||||
if (update.jvm > jvm) {
|
||||
Utils.LOGGER.error("A newer JVM is required to use the latest inceptum version. Please update!");
|
||||
continue packageLoop;
|
||||
}
|
||||
if (experimental == null || experimental.version.compareTo(update.version) < 0) {
|
||||
experimental = update;
|
||||
}
|
||||
if (!info.version.contains("-") && (stable == null || stable.version.compareTo(update.version) < 0)) {
|
||||
stable = update;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
continue packageLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (experimental == null) {
|
||||
throw new IOException("No version could be found");
|
||||
} else if (stable == null && channel == UpdateChannel.Stable) {
|
||||
channel = UpdateChannel.CI;
|
||||
channelInvalid.accept(channel);
|
||||
}
|
||||
UpdateMetadata info = switch (channel) {
|
||||
case CI -> experimental;
|
||||
case Stable -> stable;
|
||||
};
|
||||
Utils.LOGGER.info("Latest version is " + info.version + ", current is " + current);
|
||||
if (current.compareTo(info.version) >= 0) {
|
||||
Utils.LOGGER.info("Up-to-date");
|
||||
return null;
|
||||
}
|
||||
return info;
|
||||
} catch (IOException | URISyntaxException e) {
|
||||
Utils.LOGGER.error("Could not check for updates", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getShadowJarUrl(UpdateMetadata metadata) {
|
||||
return PROJECT_MAVEN + "io/gitlab/jfronny/inceptum/Inceptum/" + metadata.version + "/Inceptum-" + metadata.version + "-" + Utils.getCurrentFlavor() + ".jar";
|
||||
}
|
||||
}
|
|
@ -11,7 +11,9 @@ import java.net.URI;
|
|||
import java.net.URISyntaxException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Utils {
|
||||
public static final int CACHE_SIZE = 128;
|
||||
|
@ -50,4 +52,27 @@ public class Utils {
|
|||
public static void setSystemLoader(ClassLoader loader) {
|
||||
SYSTEM_LOADER = loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins strings with the provided separator but removes separators from the start and end of the strings
|
||||
* Example: join('/', "some/path/", "/some/subpath/", "example/") -> "some/path/some/subpath/example
|
||||
* @param separator The separator to join with
|
||||
* @param segments The strings to join
|
||||
* @return The joined string
|
||||
*/
|
||||
public static String join(String separator, String... segments) {
|
||||
return Arrays.stream(segments)
|
||||
.map(s -> s.startsWith(separator) ? s.substring(separator.length()) : s)
|
||||
.map(s -> s.endsWith(separator) ? s.substring(0, s.length() - separator.length()) : s)
|
||||
.filter(s -> !s.isEmpty())
|
||||
.collect(Collectors.joining(separator));
|
||||
}
|
||||
|
||||
public static String getCurrentFlavor() {
|
||||
return switch (OSUtils.TYPE) {
|
||||
case WINDOWS -> "windows";
|
||||
case MAC_OS -> "macos";
|
||||
case LINUX -> "linux";
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
package io.gitlab.jfronny.inceptum.common.api;
|
||||
|
||||
import io.gitlab.jfronny.commons.HttpUtils;
|
||||
import io.gitlab.jfronny.inceptum.common.*;
|
||||
import io.gitlab.jfronny.inceptum.common.model.maven.MavenDependency;
|
||||
import io.gitlab.jfronny.inceptum.common.model.maven.Pom;
|
||||
import org.w3c.dom.*;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.parsers.*;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
public class MavenApi {
|
||||
private static final DocumentBuilder FACTORY;
|
||||
|
||||
static {
|
||||
try {
|
||||
FACTORY = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new RuntimeException("Could not create document builder", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Path downloadLibrary(String repo, String artifact) throws IOException, URISyntaxException {
|
||||
String path = mavenNotationToJarPath(artifact);
|
||||
Path res = MetaHolder.LIBRARIES_DIR.resolve(path);
|
||||
Net.downloadFile(Utils.join("/", repo, path), res);
|
||||
return res;
|
||||
}
|
||||
|
||||
public static Pom getPom(String repo, String artifact) throws IOException, SAXException, URISyntaxException, XMLStreamException {
|
||||
try (InputStream is = HttpUtils.get(Utils.join("/", repo, mavenNotationToPomPath(artifact))).sendInputStream()) {
|
||||
Document doc = FACTORY.parse(is);
|
||||
doc.getDocumentElement().normalize();
|
||||
Pom result = new Pom();
|
||||
if (!"project".equals(doc.getDocumentElement().getNodeName())) throw new IOException("Illegal document name");
|
||||
boolean hasModelVersion = false;
|
||||
boolean hasGroupId = false;
|
||||
boolean hasArtifactId = false;
|
||||
boolean hasVersion = false;
|
||||
for (Node node : iterable(doc.getDocumentElement().getChildNodes())) {
|
||||
switch (node.getNodeName()) {
|
||||
case "modelVersion" -> {
|
||||
hasModelVersion = true;
|
||||
result.modelVersion = node.getTextContent();
|
||||
}
|
||||
case "groupId" -> {
|
||||
hasGroupId = true;
|
||||
result.groupId = node.getTextContent();
|
||||
}
|
||||
case "artifactId" -> {
|
||||
hasArtifactId = true;
|
||||
result.artifactId = node.getTextContent();
|
||||
}
|
||||
case "version" -> {
|
||||
hasVersion = true;
|
||||
result.version = node.getTextContent();
|
||||
}
|
||||
case "packaging" -> result.packaging = node.getTextContent();
|
||||
case "dependencies" -> {
|
||||
result.dependencies = new LinkedList<>();
|
||||
for (Node dep : iterable(node.getChildNodes())) {
|
||||
result.dependencies.add(parseDependency(dep));
|
||||
}
|
||||
}
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
if (!hasModelVersion) throw new IOException("Pom lacks modelVersion");
|
||||
if (!hasGroupId) throw new IOException("Pom lacks groupId");
|
||||
if (!hasArtifactId) throw new IOException("Pom lacks artifactId");
|
||||
if (!hasVersion) throw new IOException("Pom lacks version");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static MavenDependency parseDependency(Node doc) throws IOException {
|
||||
MavenDependency result = new MavenDependency();
|
||||
boolean hasGroupId = false;
|
||||
boolean hasArtifactId = false;
|
||||
boolean hasVersion = false;
|
||||
boolean hasScope = false;
|
||||
for (Node node : iterable(doc.getChildNodes())) {
|
||||
switch (node.getNodeName()) {
|
||||
case "groupId" -> {
|
||||
hasGroupId = true;
|
||||
result.groupId = node.getTextContent();
|
||||
}
|
||||
case "artifactId" -> {
|
||||
hasArtifactId = true;
|
||||
result.artifactId = node.getTextContent();
|
||||
}
|
||||
case "version" -> {
|
||||
hasVersion = true;
|
||||
result.version = node.getTextContent();
|
||||
}
|
||||
case "scope" -> {
|
||||
hasScope = true;
|
||||
result.scope = node.getTextContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasGroupId) throw new IOException("Pom lacks groupId");
|
||||
if (!hasArtifactId) throw new IOException("Pom lacks artifactId");
|
||||
if (!hasVersion) throw new IOException("Pom lacks version");
|
||||
if (!hasScope) throw new IOException("Pom lacks scope");
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Iterable<Node> iterable(NodeList list) {
|
||||
return () -> new Iterator<>() {
|
||||
int index = 0;
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return index < list.getLength() - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node next() {
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
return list.item(index++);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an artifact in maven notation to a jar file path. The following are supported:
|
||||
* - some.base.path:artifact:version -> some/base/path/artifact/version/artifact-version.jar
|
||||
* - some.base.path:artifact:version:classifier -> some/base/path/artifact/version/artifact-version-classifier.jar
|
||||
* @param mavenNotation An artifact in maven notation
|
||||
* @return A file path
|
||||
*/
|
||||
public static String mavenNotationToJarPath(String mavenNotation) {
|
||||
if (Objects.requireNonNull(mavenNotation).isEmpty()) throw new IllegalArgumentException("The notation is empty");
|
||||
String[] lib = mavenNotation.split(":");
|
||||
if (lib.length <= 1) throw new IllegalArgumentException("Not in maven notation");
|
||||
if (lib.length == 2) throw new IllegalArgumentException("Skipping versions is not supported");
|
||||
if (lib.length >= 5) throw new IllegalArgumentException("Unkown elements in maven notation");
|
||||
String path = lib[0].replace('.', '/') + '/'; // Base
|
||||
path += lib[1] + '/'; // Artifact name
|
||||
path += lib[2] + '/'; // Version
|
||||
if (lib.length == 3) { // artifact-version.jar
|
||||
path += lib[1] + '-' + lib[2];
|
||||
} else { // artifact-version-classifier.jar
|
||||
path += lib[1] + '-' + lib[2] + "-" + lib[3];
|
||||
}
|
||||
return path + ".jar";
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an artifact in maven notation to a pom file path. The following are supported:
|
||||
* - some.base.path:artifact:version -> some/base/path/artifact/version/artifact-version.pom
|
||||
* - some.base.path:artifact:version:classifier -> some/base/path/artifact/version/artifact-version.pom
|
||||
* @param mavenNotation An artifact in maven notation
|
||||
* @return A file path
|
||||
*/
|
||||
public static String mavenNotationToPomPath(String mavenNotation) {
|
||||
if (Objects.requireNonNull(mavenNotation).isEmpty()) throw new IllegalArgumentException("The notation is empty");
|
||||
String[] lib = mavenNotation.split(":");
|
||||
if (lib.length <= 1) throw new IllegalArgumentException("Not in maven notation");
|
||||
if (lib.length == 2) throw new IllegalArgumentException("Skipping versions is not supported");
|
||||
if (lib.length >= 5) throw new IllegalArgumentException("Unkown elements in maven notation");
|
||||
String path = lib[0].replace('.', '/') + '/'; // Base
|
||||
path += lib[1] + '/'; // Artifact name
|
||||
path += lib[2] + '/'; // Version
|
||||
if (lib.length == 3) { // artifact-version
|
||||
path += lib[1] + '-' + lib[2];
|
||||
}
|
||||
return path + ".pom";
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package io.gitlab.jfronny.inceptum.common.model.inceptum;
|
||||
|
||||
import io.gitlab.jfronny.commons.ComparableVersion;
|
||||
|
||||
public record UpdateInfo(String url, String sha1, ComparableVersion newVersion) {
|
||||
}
|
|
@ -2,9 +2,15 @@ package io.gitlab.jfronny.inceptum.common.model.inceptum;
|
|||
|
||||
import io.gitlab.jfronny.commons.ComparableVersion;
|
||||
|
||||
public class VersionMetadata {
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class UpdateMetadata {
|
||||
public Integer wrapperVersion;
|
||||
public ComparableVersion version;
|
||||
public Boolean isPublic;
|
||||
public Boolean isRelease;
|
||||
public Integer jvm;
|
||||
public List<String> repositories;
|
||||
public Map<String, List<String>> natives;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package io.gitlab.jfronny.inceptum.common.model.inceptum;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class WrapperConfig {
|
||||
public List<String> libraries;
|
||||
public List<String> repositories;
|
||||
public Map<String, List<String>> natives;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package io.gitlab.jfronny.inceptum.common.model.maven;
|
||||
|
||||
public class MavenDependency {
|
||||
public String groupId;
|
||||
public String artifactId;
|
||||
public String version;
|
||||
public String scope;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package io.gitlab.jfronny.inceptum.common.model.maven;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Pom {
|
||||
public String modelVersion;
|
||||
public String groupId;
|
||||
public String artifactId;
|
||||
public String version;
|
||||
public String packaging;
|
||||
public List<MavenDependency> dependencies;
|
||||
}
|
|
@ -19,10 +19,10 @@ This module contains a dear-imgui-based frontend for Inceptum.
|
|||
Builds of this module are platform-specific and dependents must manually ensure the correct imgui and lwjgl natives are imported.
|
||||
A build without natives can be obtained through the maven and a build with natives through the shadowed Inceptum jar
|
||||
|
||||
## launcher-shadowed/Inceptum
|
||||
## launcher-dist/Inceptum
|
||||
This module builds a shadowed jar of launcher-cli and launcher-imgui to be used by normal users.
|
||||
It also adds additional, platform-specific commands to the CLI.
|
||||
A build can be obtained through the maven (with the correct suffix) or as a jar with shadowed dependencies.
|
||||
A shadowed build can be obtained as "Inceptum" from maven, a build with dependencies as "launcher-dist"
|
||||
Windows users can also obtain a binary built using fabric-installer-native-bootstrap.
|
||||
|
||||
## wrapper
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
plugins {
|
||||
id("inceptum.application-standalone-conventions")
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass.set("io.gitlab.jfronny.inceptum.Inceptum")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":launcher"))
|
||||
implementation(project(":launcher-cli"))
|
||||
implementation(project(":launcher-imgui"))
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
archiveClassifier.set(rootProject.extra["flavorProp"] as String)
|
||||
archiveBaseName.set("Inceptum")
|
||||
exclude("about.html")
|
||||
exclude("plugin.properties")
|
||||
exclude("META-INF/**")
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
if (rootProject.hasProperty("dist.platformOnly")) {
|
||||
create<MavenPublication>("shadowed") {
|
||||
artifact(tasks.shadowJar) {
|
||||
builtBy(tasks.shadowJar)
|
||||
artifactId = "Inceptum"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
create<MavenPublication>("mavenJava") {
|
||||
artifact(tasks.jar) {
|
||||
builtBy(tasks.jar)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,10 +2,8 @@ package io.gitlab.jfronny.inceptum;
|
|||
|
||||
import io.gitlab.jfronny.inceptum.cli.Command;
|
||||
import io.gitlab.jfronny.inceptum.cli.CommandArgs;
|
||||
import io.gitlab.jfronny.inceptum.common.Utils;
|
||||
import io.gitlab.jfronny.inceptum.common.model.inceptum.UpdateInfo;
|
||||
import io.gitlab.jfronny.inceptum.imgui.ImBuildMetadata;
|
||||
import io.gitlab.jfronny.inceptum.launcher.Updater;
|
||||
import io.gitlab.jfronny.inceptum.common.*;
|
||||
import io.gitlab.jfronny.inceptum.common.model.inceptum.UpdateMetadata;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
|
@ -32,7 +30,7 @@ public class UpdateCheckCommand extends Command {
|
|||
Utils.LOGGER.error("Automatic updates are not supported without the wrapper");
|
||||
return;
|
||||
}
|
||||
UpdateInfo updateUrl = Updater.getUpdate(ImBuildMetadata.FLAVOR);
|
||||
UpdateMetadata updateUrl = BuildMetadata.IS_PUBLIC ? Updater.getUpdate() : null;
|
||||
if (updateUrl == null) {
|
||||
Utils.LOGGER.info("No update was found");
|
||||
} else {
|
|
@ -2,38 +2,25 @@ plugins {
|
|||
id("inceptum.application-conventions")
|
||||
}
|
||||
|
||||
group = "io.gitlab.jfronny.inceptum"
|
||||
version = "0.2.0-1662303777"
|
||||
|
||||
dependencies {
|
||||
val flavor: String by rootProject.extra
|
||||
val lwjglVersion: String by rootProject.extra
|
||||
val imguiVersion: String by rootProject.extra
|
||||
|
||||
implementation(project(":launcher"))
|
||||
fun native(name: String) {
|
||||
if (flavor == "windows" || flavor == "fat") implementation(name.replace("@platform", "windows"))
|
||||
if (flavor == "linux" || flavor == "fat") implementation(name.replace("@platform", "linux"))
|
||||
if (flavor == "macos" || flavor == "fat") implementation(name.replace("@platform", "macos"))
|
||||
}
|
||||
|
||||
implementation(platform("org.lwjgl:lwjgl-bom:$lwjglVersion"))
|
||||
implementation(project(":launcher"))
|
||||
|
||||
arrayOf("", "-opengl", "-glfw", "-tinyfd").forEach {
|
||||
implementation("org.lwjgl:lwjgl$it:$lwjglVersion")
|
||||
if (flavor == "windows" || flavor == "fat") implementation("org.lwjgl:lwjgl$it::natives-windows")
|
||||
if (flavor == "linux" || flavor == "fat") implementation("org.lwjgl:lwjgl$it::natives-linux")
|
||||
if (flavor == "macos" || flavor == "fat") implementation("org.lwjgl:lwjgl$it::natives-macos")
|
||||
native("org.lwjgl:lwjgl$it:$lwjglVersion:natives-@platform")
|
||||
}
|
||||
|
||||
implementation("io.github.spair:imgui-java-binding:$imguiVersion") // https://github.com/SpaiR/imgui-java
|
||||
implementation("io.github.spair:imgui-java-lwjgl3:$imguiVersion")
|
||||
|
||||
if (flavor == "windows" || flavor == "fat") implementation("io.github.spair:imgui-java-natives-windows:$imguiVersion")
|
||||
if (flavor == "linux" || flavor == "fat") implementation("io.github.spair:imgui-java-natives-linux:$imguiVersion")
|
||||
if (flavor == "macos" || flavor == "fat") implementation("io.github.spair:imgui-java-natives-macos:$imguiVersion")
|
||||
native("io.github.spair:imgui-java-natives-@platform:$imguiVersion")
|
||||
}
|
||||
|
||||
projectDir.resolve("src/main/java/io/gitlab/jfronny/inceptum/imgui/ImBuildMetadata.java").writeText(
|
||||
"""
|
||||
package io.gitlab.jfronny.inceptum.imgui;
|
||||
|
||||
public class ImBuildMetadata {
|
||||
public static final String FLAVOR = "${rootProject.extra["flavorProp"]}";
|
||||
}
|
||||
""".trimIndent())
|
||||
|
|
|
@ -6,12 +6,11 @@ import imgui.flag.ImGuiConfigFlags;
|
|||
import imgui.gl3.ImGuiImplGl3;
|
||||
import imgui.glfw.ImGuiImplGlfw;
|
||||
import io.gitlab.jfronny.commons.io.JFiles;
|
||||
import io.gitlab.jfronny.inceptum.common.model.inceptum.UpdateInfo;
|
||||
import io.gitlab.jfronny.inceptum.common.model.inceptum.UpdateMetadata;
|
||||
import io.gitlab.jfronny.inceptum.imgui.window.MainWindow;
|
||||
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
|
||||
import io.gitlab.jfronny.inceptum.common.*;
|
||||
import io.gitlab.jfronny.inceptum.imgui.window.Window;
|
||||
import io.gitlab.jfronny.inceptum.launcher.Updater;
|
||||
import io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta;
|
||||
import io.gitlab.jfronny.inceptum.launcher.api.account.AccountManager;
|
||||
import io.gitlab.jfronny.inceptum.launcher.system.mds.ModsDirScanner;
|
||||
|
@ -41,7 +40,7 @@ public class GuiMain {
|
|||
|
||||
public static void main(String[] args) throws IOException {
|
||||
LauncherEnv.checkClassLoaderState();
|
||||
Utils.LOGGER.info("Launching Inceptum v" + BuildMetadata.VERSION + " (" + ImBuildMetadata.FLAVOR + ")");
|
||||
Utils.LOGGER.info("Launching Inceptum v" + BuildMetadata.VERSION);
|
||||
Utils.LOGGER.info("Loading from " + MetaHolder.BASE_PATH);
|
||||
LauncherEnv.initialize(new GuiEnvBackend());
|
||||
try {
|
||||
|
@ -52,7 +51,7 @@ public class GuiMain {
|
|||
}
|
||||
|
||||
public static void main(boolean wrapped) {
|
||||
UpdateInfo update = Updater.getUpdate(ImBuildMetadata.FLAVOR);
|
||||
UpdateMetadata update = BuildMetadata.IS_PUBLIC ? Updater.getUpdate() : null;
|
||||
AccountManager.loadAccounts();
|
||||
Utils.LOGGER.info("Initializing UI");
|
||||
try {
|
||||
|
@ -78,7 +77,7 @@ public class GuiMain {
|
|||
} else {
|
||||
LauncherEnv.showOkCancel("An update was found. Automatic installs are not supported without the wrapper but you can download it nonetheless", "Update found", () -> {
|
||||
try {
|
||||
Utils.openWebBrowser(new URI(update.url()));
|
||||
Utils.openWebBrowser(new URI(Updater.getShadowJarUrl(update)));
|
||||
exit();
|
||||
} catch (URISyntaxException e) {
|
||||
LauncherEnv.showError("Could not download update", e);
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
plugins {
|
||||
id("inceptum.application-standalone-conventions")
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass.set("io.gitlab.jfronny.inceptum.Inceptum")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":launcher"))
|
||||
implementation(project(":launcher-cli"))
|
||||
implementation(project(":launcher-imgui"))
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
archiveClassifier.set(rootProject.extra["flavorProp"] as String)
|
||||
exclude("about.html")
|
||||
exclude("plugin.properties")
|
||||
exclude("META-INF/**")
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package io.gitlab.jfronny.inceptum.launcher;
|
||||
|
||||
import io.gitlab.jfronny.commons.OSUtils;
|
||||
import io.gitlab.jfronny.inceptum.common.*;
|
||||
import io.gitlab.jfronny.inceptum.common.model.inceptum.UpdateInfo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class Updater {
|
||||
public static UpdateInfo getUpdate(String flavor) {
|
||||
return UpdateChecker.check(ConfigHolder.CONFIG.channel, BuildMetadata.VERSION, flavor, channel -> {
|
||||
Utils.LOGGER.error("No stable version was found, switching to experimental channel");
|
||||
ConfigHolder.CONFIG.channel = channel;
|
||||
ConfigHolder.saveConfig();
|
||||
});
|
||||
}
|
||||
|
||||
//TODO (possibly) rework for new structure
|
||||
public static void update(UpdateInfo source, boolean relaunch) throws IOException, URISyntaxException {
|
||||
Utils.LOGGER.info("Downloading " + source.url());
|
||||
Path jarPath = MetaHolder.LIBRARIES_DIR.resolve("io/gitlab/jfronny/inceptum/Inceptum")
|
||||
.resolve(source.newVersion().toString())
|
||||
.resolve("Inceptum-" + source.newVersion() + '-' + OSUtils.TYPE.getMojName() + ".jar")
|
||||
.toAbsolutePath();
|
||||
Files.createDirectories(jarPath.getParent());
|
||||
Net.downloadFile(source.url(), source.sha1(), jarPath);
|
||||
if (relaunch) {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
try {
|
||||
new ProcessBuilder(OSUtils.getJvmBinary(),
|
||||
"-jar",
|
||||
jarPath.toString())
|
||||
.inheritIO()
|
||||
.start();
|
||||
} catch (IOException e) {
|
||||
Utils.LOGGER.error("Could not relaunch", e);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package io.gitlab.jfronny.inceptum.launcher.api;
|
|||
|
||||
import io.gitlab.jfronny.gson.reflect.TypeToken;
|
||||
import io.gitlab.jfronny.inceptum.common.Net;
|
||||
import io.gitlab.jfronny.inceptum.common.api.MavenApi;
|
||||
import io.gitlab.jfronny.inceptum.launcher.model.fabric.FabricVersionLoaderInfo;
|
||||
import io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta;
|
||||
import io.gitlab.jfronny.inceptum.launcher.model.mojang.*;
|
||||
|
@ -64,9 +65,7 @@ public class FabricMetaApi {
|
|||
res.downloads = new VersionInfo.Library.Downloads();
|
||||
res.downloads.classifiers = null;
|
||||
res.downloads.artifact = new VersionInfo.Library.Downloads.Artifact();
|
||||
String[] lib = library.name.split(":");
|
||||
assert lib.length == 3;
|
||||
res.downloads.artifact.path = lib[0].replace('.', '/') + '/' + lib[1] + '/' + lib[2] + '/' + lib[1] + '-' + lib[2] + ".jar";
|
||||
res.downloads.artifact.path = MavenApi.mavenNotationToJarPath(library.name);
|
||||
res.downloads.artifact.size = -1;
|
||||
res.downloads.artifact.sha1 = null;
|
||||
res.downloads.artifact.url = library.url + res.downloads.artifact.path;
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 336e431c44a10036a24a5d4960789e1eedad6c27
|
||||
Subproject commit fe0b2fdc3361a5a085a316b73e25aec635c50863
|
|
@ -5,6 +5,4 @@ include("wrapper")
|
|||
include("launcher")
|
||||
include("launcher-cli")
|
||||
include("launcher-imgui")
|
||||
include("launcher-shadowed")
|
||||
|
||||
project(":launcher-shadowed").name = "Inceptum"
|
||||
include("launcher-dist")
|
|
@ -1,83 +1,44 @@
|
|||
package io.gitlab.jfronny.inceptum;
|
||||
|
||||
import io.gitlab.jfronny.commons.ComparableVersion;
|
||||
import io.gitlab.jfronny.commons.OSUtils;
|
||||
import io.gitlab.jfronny.commons.io.JFiles;
|
||||
import io.gitlab.jfronny.inceptum.common.*;
|
||||
import io.gitlab.jfronny.inceptum.common.model.inceptum.UpdateChannel;
|
||||
import io.gitlab.jfronny.inceptum.common.model.inceptum.UpdateInfo;
|
||||
import io.gitlab.jfronny.inceptum.common.model.inceptum.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.List;
|
||||
|
||||
public class Wrapper {
|
||||
private static final Path INCEPTUM_LIB_DIR = MetaHolder.BASE_PATH.resolve("libraries/io/gitlab/jfronny/inceptum/Inceptum");
|
||||
|
||||
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, URISyntaxException {
|
||||
Utils.setSystemLoader(WrapperStrap.SYSTEM_LOADER);
|
||||
MetaHolder.setWrapperFlag();
|
||||
System.out.println("Inceptum Wrapper v" + BuildMetadata.VERSION);
|
||||
InceptumEnvironmentInitializer.initialize();
|
||||
if (!Files.exists(INCEPTUM_LIB_DIR)) downloadLatest();
|
||||
Optional<Path> localBinary = selectLocalBinary();
|
||||
if (localBinary.isEmpty()) {
|
||||
downloadLatest();
|
||||
localBinary = selectLocalBinary();
|
||||
}
|
||||
if (localBinary.isEmpty()) {
|
||||
throw new FileNotFoundException("Could not identify or download a valid binary");
|
||||
}
|
||||
List<Path> classpath = getClasspath();
|
||||
String[] newArgs = new String[args.length + 1];
|
||||
newArgs[0] = "wrapper";
|
||||
System.arraycopy(args, 0, newArgs, 1, args.length);
|
||||
System.out.println("Starting Inceptum ClassLoader");
|
||||
WrapperStrap.switchEnv(localBinary.get(),
|
||||
WrapperStrap.switchEnv(classpath,
|
||||
"io.gitlab.jfronny.inceptum.Inceptum",
|
||||
newArgs);
|
||||
}
|
||||
|
||||
private static void downloadLatest() throws IOException {
|
||||
System.err.println("No Inceptum jar was identified");
|
||||
UpdateInfo ui = UpdateChecker.check(UpdateChannel.Stable, new ComparableVersion("0"), OSUtils.TYPE.getMojName(), R::nop);
|
||||
if (ui == null) {
|
||||
throw new FileNotFoundException("Could not identify a valid inceptum version. Are you connected to the internet?");
|
||||
}
|
||||
System.err.println("Downloading " + ui.url());
|
||||
Path dir = INCEPTUM_LIB_DIR.resolve(ui.newVersion().toString());
|
||||
Files.createDirectories(dir);
|
||||
try (InputStream is = new URL(ui.url()).openStream()) {
|
||||
Files.write(dir.resolve("Inceptum-" + ui.newVersion() + '-' + OSUtils.TYPE.getMojName() + ".jar"), is.readAllBytes());
|
||||
} catch (Throwable t) {
|
||||
Files.delete(dir);
|
||||
}
|
||||
}
|
||||
|
||||
private static Optional<Path> selectLocalBinary() throws IOException {
|
||||
Path pathChosen = null;
|
||||
ComparableVersion versionChosen = new ComparableVersion("0");
|
||||
try (Stream<Path> inceptumLibVersionDirStream = Files.list(INCEPTUM_LIB_DIR)) {
|
||||
for (Path inceptumVersionPath : inceptumLibVersionDirStream.toList()) {
|
||||
ComparableVersion versionCurrent = new ComparableVersion(inceptumVersionPath.getFileName().toString());
|
||||
if (versionCurrent.compareTo(versionChosen) > 0) {
|
||||
inceptumVersionPath = inceptumVersionPath.resolve("Inceptum-" + versionCurrent + '-' + OSUtils.TYPE.getMojName() + ".jar");
|
||||
if (Files.exists(inceptumVersionPath)) {
|
||||
versionChosen = versionCurrent;
|
||||
pathChosen = inceptumVersionPath;
|
||||
} else {
|
||||
Utils.LOGGER.error("Candidate " + inceptumVersionPath + " failed: doesn't exist");
|
||||
}
|
||||
}
|
||||
private static List<Path> getClasspath() throws IOException, URISyntaxException {
|
||||
if (!Files.exists(MetaHolder.WRAPPER_CONFIG_PATH)) {
|
||||
UpdateMetadata update = Updater.check(UpdateChannel.Stable, new ComparableVersion("0"), R::nop);
|
||||
if (update == null) {
|
||||
throw new FileNotFoundException("Could not identify a valid inceptum version. Are you connected to the internet?");
|
||||
}
|
||||
Updater.update(update, false);
|
||||
if (!Files.exists(MetaHolder.WRAPPER_CONFIG_PATH))
|
||||
throw new FileNotFoundException("Something went wrong while downloading the latest version.");
|
||||
}
|
||||
if (pathChosen == null) {
|
||||
Utils.LOGGER.error("Something went wrong, please try again");
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(pathChosen);
|
||||
return Updater.getLaunchClasspath(JFiles.readObject(MetaHolder.WRAPPER_CONFIG_PATH, WrapperConfig.class));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,35 @@
|
|||
package io.gitlab.jfronny.inceptum;
|
||||
|
||||
import io.gitlab.jfronny.inceptum.common.Utils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
import java.nio.file.*;
|
||||
import java.util.*;
|
||||
|
||||
public class WrapperClassLoader extends ClassLoader implements Closeable {
|
||||
private final Path source;
|
||||
private final FileSystem fs;
|
||||
private final Set<Path> sources = new LinkedHashSet<>();
|
||||
private final Set<Closeable> closeables = new HashSet<>();
|
||||
|
||||
public WrapperClassLoader(Path zipArchive) throws IOException, URISyntaxException {
|
||||
public WrapperClassLoader(Iterable<Path> jars) throws IOException, URISyntaxException {
|
||||
super(null);
|
||||
this.fs = Utils.openZipFile(zipArchive, false);
|
||||
this.source = Files.isDirectory(zipArchive) ? zipArchive : fs.getPath("");
|
||||
for (Path jar : jars) {
|
||||
if (Files.isDirectory(jar)) {
|
||||
sources.add(jar);
|
||||
} else {
|
||||
FileSystem fs = Utils.openZipFile(jar, false);
|
||||
closeables.add(fs);
|
||||
sources.add(fs.getPath(""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
Path path = getPath(name);
|
||||
if (!Files.exists(path)) return WrapperStrap.SYSTEM_LOADER.loadClass(name);
|
||||
Path path = findClassSource(name);
|
||||
if (path == null) return WrapperStrap.SYSTEM_LOADER.loadClass(name);
|
||||
byte[] clazz;
|
||||
try {
|
||||
clazz = Files.readAllBytes(path);
|
||||
|
@ -32,7 +41,7 @@ public class WrapperClassLoader extends ClassLoader implements Closeable {
|
|||
|
||||
@Override
|
||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||
if (!Files.exists(getPath(name)) || name.equals("io.gitlab.jfronny.inceptum.WrapperStrap"))
|
||||
if (findClassSource(name) == null || name.equals("io.gitlab.jfronny.inceptum.WrapperStrap"))
|
||||
return WrapperStrap.SYSTEM_LOADER.loadClass(name);
|
||||
synchronized (this.getClassLoadingLock(name)) {
|
||||
Class<?> c = this.findLoadedClass(name);
|
||||
|
@ -44,8 +53,8 @@ public class WrapperClassLoader extends ClassLoader implements Closeable {
|
|||
|
||||
@Override
|
||||
public URL getResource(String name) {
|
||||
Path p = source.resolve(name);
|
||||
if (!Files.exists(p)) return WrapperStrap.SYSTEM_LOADER.getResource(name);
|
||||
Path p = findSource(name);
|
||||
if (p == null) return WrapperStrap.SYSTEM_LOADER.getResource(name);
|
||||
try {
|
||||
return p.toUri().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
|
@ -53,12 +62,22 @@ public class WrapperClassLoader extends ClassLoader implements Closeable {
|
|||
}
|
||||
}
|
||||
|
||||
private Path getPath(String className) {
|
||||
return source.resolve(className.replace('.', '/') + ".class");
|
||||
private @Nullable Path findClassSource(String className) {
|
||||
return findSource(className.replace('.', '/') + ".class");
|
||||
}
|
||||
|
||||
private @Nullable Path findSource(String path) {
|
||||
for (Path source : sources) {
|
||||
Path p = source.resolve(path);
|
||||
if (Files.exists(p)) return p;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
fs.close();
|
||||
for (Closeable closeable : closeables) {
|
||||
closeable.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,19 +7,20 @@ import java.io.IOException;
|
|||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
public class WrapperStrap {
|
||||
public static final ClassLoader SYSTEM_LOADER = ClassLoader.getSystemClassLoader();
|
||||
|
||||
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException, URISyntaxException {
|
||||
Utils.LOGGER.info("Starting Inceptum Wrapper ClassLoader");
|
||||
switchEnv(new File(WrapperStrap.class.getProtectionDomain().getCodeSource().getLocation().toURI()).toPath(),
|
||||
switchEnv(Set.of(new File(WrapperStrap.class.getProtectionDomain().getCodeSource().getLocation().toURI()).toPath()),
|
||||
"io.gitlab.jfronny.inceptum.Wrapper",
|
||||
args);
|
||||
}
|
||||
|
||||
public static void switchEnv(Path jar, String mainClass, String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException, URISyntaxException {
|
||||
try (WrapperClassLoader loader = new WrapperClassLoader(jar)) {
|
||||
public static void switchEnv(Iterable<Path> jars, String mainClass, String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException, URISyntaxException {
|
||||
try (WrapperClassLoader loader = new WrapperClassLoader(jars)) {
|
||||
Thread.currentThread().setContextClassLoader(loader);
|
||||
loader.loadClass(mainClass)
|
||||
.getDeclaredMethod("main", String[].class)
|
||||
|
|
Loading…
Reference in New Issue