Skip to content

Commit eee4a80

Browse files
committed
Make the launcher self update
1 parent 8bd3d1a commit eee4a80

File tree

13 files changed

+366
-20
lines changed

13 files changed

+366
-20
lines changed

build.gradle

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ configurations {
3535
agentCompileOnly.extendsFrom(globalCompileOnly)
3636
launcherCompileOnly.extendsFrom(globalCompileOnly)
3737
compileOnly.extendsFrom(globalCompileOnly)
38+
39+
logback
40+
launcherRuntimeOnly.extendsFrom(logback)
3841
}
3942

4043
def agentClass = "com.mcmoddev.relauncher.agent.Agent"
@@ -72,17 +75,25 @@ dependencies {
7275
implementation sourceSets.api.output
7376
api sourceSets.api.output
7477

75-
agentImplementation libs.jda // This is just a compat layer for jda mentionables. DO NOT USE FOR ANYTHING ELSE as the agent will not have it shaded
76-
agentImplementation libs.logback
78+
agentCompileOnly libs.jda // This is just a compat layer for jda mentionables. DO NOT USE FOR ANYTHING ELSE as the agent will not have it shaded
79+
agentCompileOnly libs.logback
7780
agentImplementation sourceSets.api.output
7881

7982
launcherImplementation sourceSets.main.output
8083

8184
shade sourceSets.api.output
8285
shade libs.gson
83-
shade libs.logback
8486
shade libs.configurate.hocon
8587

88+
def slf4j = "org.slf4j:slf4j-api:1.7.36"
89+
90+
launcherCompileOnly slf4j
91+
runtimeElements slf4j
92+
logback(libs.logback) {
93+
exclude module: 'logback-classic'
94+
}
95+
logback slf4j
96+
8697
// Discord stuff
8798
shade libs.jda
8899
shade libs.chewtils.command
@@ -138,12 +149,34 @@ tasks.create("copyAgentJar", Copy) {
138149
mustRunAfter(tasks.getByName("processLauncherResources"))
139150
from "$buildDir/libs/$archivesBaseName-$version-agent.jar"
140151
into "$buildDir/resources/launcher/"
141-
rename "$archivesBaseName-$version-agent.jar", "agent.zip"
152+
rename "$archivesBaseName-$version-agent.jar", "relauncher-agent.zip"
153+
}
154+
155+
tasks.create("selfUpdateJar", Jar).configure {
156+
from(sourceSets.launcher.output) {
157+
include "com/mcmoddev/relauncher/selfupdate/**/*.class"
158+
}
159+
classifier("selfupdate")
160+
group("build")
161+
description("Builds the selfupdate JAR")
162+
manifest.attributes(makeManifestAttributes('Main-Class', 'com.mcmoddev.relauncher.selfupdate.SelfUpdate'))
163+
}
164+
165+
tasks.create("copySelfUpdateJar", Copy) {
166+
dependsOn("selfUpdateJar")
167+
mustRunAfter(tasks.getByName("processLauncherResources"))
168+
from "$buildDir/libs/$archivesBaseName-$version-selfupdate.jar"
169+
into "$buildDir/resources/launcher/"
170+
rename "$archivesBaseName-$version-selfupdate.jar", "relauncher-selfupdate.zip"
142171
}
143172

144173
tasks.getByName('launcherClasses').configure {
145174
dependsOn("copyAgentJar")
146175
mustRunAfter(tasks.getByName("copyAgentJar"))
176+
doLast {
177+
tasks.getByName('selfUpdateJar').copy()
178+
tasks.getByName('copySelfUpdateJar').copy()
179+
}
147180
}
148181

149182
tasks.named('build').configure {
@@ -153,8 +186,13 @@ tasks.named('build').configure {
153186
tasks.named('shadowJar', ShadowJar).configure {
154187
dependsOn("copyAgentJar")
155188
from sourceSets.main.output // The logback file
156-
from sourceSets.launcher.output
157-
configurations = [project.configurations.shade]
189+
from(sourceSets.launcher.output) {
190+
exclude "com/mcmoddev/relauncher/selfupdate/**/*.class"
191+
}
192+
configurations = [
193+
project.configurations.shade,
194+
project.configurations.logback
195+
]
158196
classifier("all")
159197
group("build")
160198
description("Builds the whole project with its dependencies.")
@@ -163,7 +201,9 @@ tasks.named('shadowJar', ShadowJar).configure {
163201
tasks.named(JavaPlugin.JAR_TASK_NAME, Jar).configure {
164202
dependsOn("generatePomFileForMavenPublication")
165203
from sourceSets.api.output
166-
from sourceSets.launcher.output
204+
from(sourceSets.launcher.output) {
205+
exclude "com/mcmoddev/relauncher/selfupdate/**.class"
206+
}
167207

168208
exclude "logback.xml"
169209
into("META-INF/maven/${project.group}/${project.name}") {
@@ -188,7 +228,9 @@ tasks.create("apiJar", Jar).configure {
188228
tasks.create("sourcesJar", Jar) {
189229
dependsOn("launcherClasses")
190230
from sourceSets.api.allSource
191-
from sourceSets.launcher.allSource
231+
from(sourceSets.launcher.allSource) {
232+
exclude "com/mcmoddev/relauncher/selfupdate/**.java"
233+
}
192234
classifier("sources")
193235
group("build")
194236
description("Builds the sources jar")

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
name = "ReLauncher"
2-
version = 1.0.0
2+
version = 1.1.0

gradle/libs.versions.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ gson = "2.9.0"
1010
logback = "1.2.11"
1111
annotations = "23.0.0"
1212
configurate = "4.1.2"
13-
slf4j = "1.7.36"
1413

1514
[libraries]
1615
# jda = { module = "net.dv8tion:JDA", version.ref = "jda" }
@@ -22,4 +21,3 @@ gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
2221
logback = { module = "ch.qos.logback:logback-classic", version.ref = "logback" }
2322
configurate-hocon = {module = "org.spongepowered:configurate-hocon", version.ref = "configurate"}
2423
annotations = { module = "org.jetbrains:annotations", version.ref = "annotations" }
25-
slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }

src/api/java/com/mcmoddev/relauncher/api/JarUpdater.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,10 @@ default Optional<String> getJarVersion() {
9292
*/
9393
@NotNull
9494
default InputStream getAgentResource() {
95-
var agent = getClass().getResourceAsStream("/agent.jar");
95+
var agent = getClass().getResourceAsStream("/relauncher-agent.jar");
9696
if (agent == null) {
9797
// If we can't find it as a .jar, try a .zip
98-
agent = getClass().getResourceAsStream("/agent.zip");
98+
agent = getClass().getResourceAsStream("/relauncher-agent.zip");
9999
}
100100
return Objects.requireNonNull(agent);
101101
}

src/api/java/com/mcmoddev/relauncher/api/LauncherConfig.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,12 @@ default boolean throwIfNew() {
5151
return true;
5252
}
5353

54+
/**
55+
* @return if the launcher should be able to update itself
56+
*/
57+
default boolean allowSelfUpdate() {
58+
return true;
59+
}
60+
5461
record CheckingRate(long amount, TimeUnit unit) {}
5562
}

src/api/java/com/mcmoddev/relauncher/api/LauncherFactory.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,13 @@
2323
import org.jetbrains.annotations.NotNull;
2424
import org.jetbrains.annotations.Nullable;
2525

26+
import java.io.IOException;
27+
import java.net.URI;
28+
import java.net.http.HttpClient;
29+
import java.net.http.HttpRequest;
30+
import java.net.http.HttpResponse;
2631
import java.nio.file.Path;
32+
import java.util.concurrent.ForkJoinPool;
2733

2834
/**
2935
* A factory for ReLauncher. <br>
@@ -74,4 +80,22 @@ default Path getConfigPath(Path launcherDirectory) {
7480
@Nullable
7581
DiscordIntegration createDiscordIntegration(T config, JarUpdater updater);
7682

83+
/**
84+
* @return the GitHub repository of the launcher
85+
*/
86+
@Nullable
87+
default RepoInfo getLauncherRepo() {
88+
return new RepoInfo("MinecraftModDevelopment", "ReLauncher");
89+
}
90+
91+
/**
92+
* Gets the self update url for a tag name.
93+
*
94+
* @param tagName the tag to update to
95+
* @return the download url, or {@code null}
96+
*/
97+
@Nullable
98+
String getSelfUpdateUrl(String tagName) throws IOException, InterruptedException;
99+
100+
record RepoInfo(String owner, String repo) {}
77101
}

src/launcher/java/com/mcmoddev/relauncher/DefaultJarUpdater.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
*/
2121
package com.mcmoddev.relauncher;
2222

23+
import static com.mcmoddev.relauncher.Main.findJavaBinary;
2324
import com.mcmoddev.relauncher.api.DiscordIntegration;
2425
import com.mcmoddev.relauncher.api.JarUpdater;
2526
import com.mcmoddev.relauncher.api.ProcessInfo;
@@ -189,10 +190,6 @@ private List<String> getStartCommand() {
189190
return command;
190191
}
191192

192-
private static String findJavaBinary() {
193-
return ProcessHandle.current().info().command().orElse("java");
194-
}
195-
196193
@Override
197194
public void startProcess() {
198195
process = new ProcessInfoImpl(createProcess(), updateChecker.getLatestFound());

src/launcher/java/com/mcmoddev/relauncher/DefaultLauncherFactory.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,24 @@
2424
import com.mcmoddev.relauncher.api.JarUpdater;
2525
import com.mcmoddev.relauncher.api.LauncherFactory;
2626
import com.mcmoddev.relauncher.discord.DefaultDiscordIntegration;
27+
import com.mcmoddev.relauncher.github.GithubRelease;
2728
import com.mcmoddev.relauncher.github.GithubUpdateChecker;
2829
import org.jetbrains.annotations.NotNull;
2930
import org.jetbrains.annotations.Nullable;
3031
import org.spongepowered.configurate.ConfigurateException;
3132

33+
import java.io.IOException;
34+
import java.net.URI;
3235
import java.net.http.HttpClient;
36+
import java.net.http.HttpRequest;
37+
import java.net.http.HttpResponse;
3338
import java.nio.file.Path;
3439
import java.util.regex.Pattern;
3540

3641
public class DefaultLauncherFactory implements LauncherFactory<Config> {
3742

43+
public static final Pattern SELF_UPDATE_PATTERN = Pattern.compile("ReLauncher-.*-all\\.jar", Pattern.CASE_INSENSITIVE);
44+
3845
@Override
3946
public @NotNull Config getConfig(final Path path) {
4047
try {
@@ -57,4 +64,28 @@ public class DefaultLauncherFactory implements LauncherFactory<Config> {
5764
public @Nullable DiscordIntegration createDiscordIntegration(final Config config, final JarUpdater updater) {
5865
return new DefaultDiscordIntegration(Path.of(""), config.discord, () -> updater);
5966
}
67+
68+
@Override
69+
public @Nullable String getSelfUpdateUrl(final String tagName) throws IOException, InterruptedException {
70+
final var repo = getLauncherRepo();
71+
if (repo == null) {
72+
return null;
73+
}
74+
final var url = "https://api.github.com/repos/%s/%s/releases/tags/%s".formatted(repo.owner(), repo.repo(), tagName);
75+
final var response = HttpClient.newBuilder()
76+
.executor(Main.HTTP_CLIENT_EXECUTOR)
77+
.build()
78+
.send(HttpRequest.newBuilder(URI.create(url))
79+
.GET()
80+
.build(), HttpResponse.BodyHandlers.ofString());
81+
if (response.statusCode() == 404) {
82+
return null;
83+
}
84+
final var release = Constants.GSON.fromJson(response.body(), GithubRelease.class);
85+
return release.assets.stream()
86+
.filter(a -> SELF_UPDATE_PATTERN.matcher(a.name).find())
87+
.map(a -> a.browserDownloadUrl)
88+
.findFirst()
89+
.orElse(null);
90+
}
6091
}

0 commit comments

Comments
 (0)