208 lines
9.8 KiB
Java
208 lines
9.8 KiB
Java
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.*;
|
|
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 {
|
|
|
|
public static UpdateMetadata getUpdate() {
|
|
return Updater.check(InceptumConfig.channel, BuildMetadata.VERSION, channel -> {
|
|
Utils.LOGGER.error("No stable version was found, switching to experimental channel");
|
|
InceptumConfig.channel = channel;
|
|
InceptumConfig.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 LinkedHashSet<>();
|
|
config.repositories = new LinkedHashSet<>(source.repositories);
|
|
source.natives.forEach((k, v) -> config.natives.put(k, new LinkedHashSet<>(v)));
|
|
|
|
DependencyNode node = downloadLibrary(source.repositories, "io.gitlab.jfronny.inceptum:launcher-dist:" + source.version, config.libraries);
|
|
Utils.LOGGER.info("Downloaded Dependencies:\n" + node);
|
|
|
|
List<String> currentLibraries = new LinkedList<>(config.libraries);
|
|
if (source.natives.containsKey(Utils.getCurrentFlavor())) {
|
|
Set<String> natives = new LinkedHashSet<>();
|
|
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 {
|
|
Set<String> natives = wrapperConfig.natives.get(Utils.getCurrentFlavor());
|
|
if (natives == null) natives = new LinkedHashSet<>();
|
|
Set<String> libs = wrapperConfig.libraries;
|
|
if (libs == null) libs = new LinkedHashSet<>();
|
|
|
|
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 DependencyNode downloadLibrary(Set<String> repositories, final String artifact, Set<String> libraries) throws IOException, URISyntaxException {
|
|
List<Exception> exceptions = new LinkedList<>();
|
|
for (String repository : Stream.concat(Stream.of(GitlabApi.PROJECT_MAVEN), repositories.stream()).toList()) {
|
|
Pom pom;
|
|
try {
|
|
pom = MavenApi.getPom(repository, artifact);
|
|
} catch (IOException | URISyntaxException | XMLStreamException | SAXException e) {
|
|
exceptions.add(new Exception("Could not download artifact from " + repository, e));
|
|
continue;
|
|
}
|
|
Set<DependencyNode> dependencies = new LinkedHashSet<>();
|
|
if (pom.dependencies != null) {
|
|
for (MavenDependency dependency : pom.dependencies) {
|
|
String mvnName = dependency.groupId + ":" + dependency.artifactId + ":" + dependency.version;
|
|
dependencies.add(downloadLibrary(repositories, mvnName, libraries));
|
|
}
|
|
}
|
|
MavenApi.downloadLibrary(repository, artifact);
|
|
libraries.add(artifact);
|
|
return new DependencyNode(pom, dependencies);
|
|
}
|
|
IOException exception = new IOException("Could not find any repository containing the artifact " + artifact + " (searched: " + String.join(", ", repositories) + ")");
|
|
for (Exception e : exceptions) {
|
|
exception.addSuppressed(e);
|
|
}
|
|
throw exception;
|
|
}
|
|
|
|
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(GitlabApi.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 GitlabApi.PROJECT_MAVEN + "io/gitlab/jfronny/inceptum/Inceptum/" + metadata.version + "/Inceptum-" + metadata.version + "-" + Utils.getCurrentFlavor() + ".jar";
|
|
}
|
|
}
|