From 7c691e6015387f10dc08be9a0f4a9c9d7790c19b Mon Sep 17 00:00:00 2001 From: Geoff Bourne Date: Tue, 11 Nov 2025 12:01:48 -0600 Subject: [PATCH] neoforge: skip lookup if exact request matches installed version --- .../curseforge/CurseForgeInstaller.java | 6 ++-- .../helpers/forge/ForgeInstallerResolver.java | 12 ++++++- ...Installer.java => ForgeLikeInstaller.java} | 6 ++-- .../helpers/forge/InstallForgeCommand.java | 3 +- .../helpers/forge/InstallNeoForgeCommand.java | 3 +- .../itzg/helpers/forge/InstallerResolver.java | 2 +- .../forge/NeoForgeInstallerResolver.java | 13 ++++++-- .../forge/ProvidedInstallerResolver.java | 2 +- .../modrinth/ModrinthPackInstaller.java | 6 ++-- .../me/itzg/helpers/mvn/MavenRepoApi.java | 4 +++ ....java => CurseForgeLikeInstallerTest.java} | 2 +- .../forge/NeoForgeInstallerResolverTest.java | 32 ++++++++++++++++++- .../forge/ProvidedInstallerResolverTest.java | 2 +- 13 files changed, 74 insertions(+), 19 deletions(-) rename src/main/java/me/itzg/helpers/forge/{ForgeInstaller.java => ForgeLikeInstaller.java} (98%) rename src/test/java/me/itzg/helpers/curseforge/{CurseForgeInstallerTest.java => CurseForgeLikeInstallerTest.java} (97%) diff --git a/src/main/java/me/itzg/helpers/curseforge/CurseForgeInstaller.java b/src/main/java/me/itzg/helpers/curseforge/CurseForgeInstaller.java index 04726149..2c4a53bb 100644 --- a/src/main/java/me/itzg/helpers/curseforge/CurseForgeInstaller.java +++ b/src/main/java/me/itzg/helpers/curseforge/CurseForgeInstaller.java @@ -52,7 +52,7 @@ import me.itzg.helpers.files.Manifests; import me.itzg.helpers.files.ReactiveFileUtils; import me.itzg.helpers.files.ResultsFileWriter; -import me.itzg.helpers.forge.ForgeInstaller; +import me.itzg.helpers.forge.ForgeLikeInstaller; import me.itzg.helpers.forge.ForgeInstallerResolver; import me.itzg.helpers.forge.ForgeUrlArgs; import me.itzg.helpers.forge.NeoForgeInstallerResolver; @@ -1006,7 +1006,7 @@ private void prepareFabric(String minecraftVersion, String loaderVersion) { } private void prepareForge(SharedFetch sharedFetch, String minecraftVersion, String loaderVersion) { - new ForgeInstaller( + new ForgeLikeInstaller( new ForgeInstallerResolver(sharedFetch, minecraftVersion, loaderVersion, forgeUrlArgs.getPromotionsUrl(), forgeUrlArgs.getMavenRepoUrl() @@ -1016,7 +1016,7 @@ private void prepareForge(SharedFetch sharedFetch, String minecraftVersion, Stri } private void prepareNeoForge(SharedFetch sharedFetch, String minecraftVersion, String loaderVersion) { - new ForgeInstaller( + new ForgeLikeInstaller( new NeoForgeInstallerResolver(sharedFetch, minecraftVersion, loaderVersion ) diff --git a/src/main/java/me/itzg/helpers/forge/ForgeInstallerResolver.java b/src/main/java/me/itzg/helpers/forge/ForgeInstallerResolver.java index fff7cc81..84bdab38 100644 --- a/src/main/java/me/itzg/helpers/forge/ForgeInstallerResolver.java +++ b/src/main/java/me/itzg/helpers/forge/ForgeInstallerResolver.java @@ -43,7 +43,17 @@ public ForgeInstallerResolver(SharedFetch sharedFetch, } @Override - public VersionPair resolve() { + public VersionPair resolve(ForgeManifest prevManifest) { + if (prevManifest != null) { + final String prevMinecraftVersion = prevManifest.getMinecraftVersion(); + final String prevForgeVersion = prevManifest.getForgeVersion(); + if (prevMinecraftVersion.equals(requestedMinecraftVersion) + && prevForgeVersion.equals(requestedForgeVersion)) { + log.debug("Resolved Minecraft {} Forge {} from previous manifest", prevMinecraftVersion, prevForgeVersion); + return new VersionPair(requestedMinecraftVersion, requestedForgeVersion); + } + } + final PromotionsSlim promotionsSlim = loadPromotions(); if (promotionsSlim.getPromos().isEmpty()) { throw new GenericException("No versions were available in Forge promotions"); diff --git a/src/main/java/me/itzg/helpers/forge/ForgeInstaller.java b/src/main/java/me/itzg/helpers/forge/ForgeLikeInstaller.java similarity index 98% rename from src/main/java/me/itzg/helpers/forge/ForgeInstaller.java rename to src/main/java/me/itzg/helpers/forge/ForgeLikeInstaller.java index a64924f7..450dcfa0 100644 --- a/src/main/java/me/itzg/helpers/forge/ForgeInstaller.java +++ b/src/main/java/me/itzg/helpers/forge/ForgeLikeInstaller.java @@ -25,7 +25,7 @@ import org.jetbrains.annotations.Nullable; @Slf4j -public class ForgeInstaller { +public class ForgeLikeInstaller { private static final Pattern RESULT_INFO = Pattern.compile( "Exec:\\s+(?.+)" @@ -33,7 +33,7 @@ public class ForgeInstaller { private final InstallerResolver installerResolver; - public ForgeInstaller(InstallerResolver installerResolver) { + public ForgeLikeInstaller(InstallerResolver installerResolver) { this.installerResolver = installerResolver; } @@ -51,7 +51,7 @@ public void install( throw new GenericException("Failed to load existing forge manifest", e); } - final VersionPair resolved = installerResolver.resolve(); + final VersionPair resolved = installerResolver.resolve(prevManifest); if (resolved == null) { throw new InvalidParameterException("Unable to find suitable version for " + installerResolver.getDescription()); diff --git a/src/main/java/me/itzg/helpers/forge/InstallForgeCommand.java b/src/main/java/me/itzg/helpers/forge/InstallForgeCommand.java index bf8c44bf..c8305815 100644 --- a/src/main/java/me/itzg/helpers/forge/InstallForgeCommand.java +++ b/src/main/java/me/itzg/helpers/forge/InstallForgeCommand.java @@ -22,6 +22,7 @@ public class InstallForgeCommand implements Callable { @Spec CommandLine.Model.CommandSpec spec; + @SuppressWarnings("unused") @Option(names = {"--help", "-h"}, usageHelp = true) boolean help; @@ -96,7 +97,7 @@ public void setVersion(String version) { public Integer call() throws Exception { try (SharedFetch sharedFetch = Fetch.sharedFetch("install-forge", sharedFetchArgs.options())) { - final ForgeInstaller installer = new ForgeInstaller( + final ForgeLikeInstaller installer = new ForgeLikeInstaller( versionOrInstaller.installer != null ? new ProvidedInstallerResolver(versionOrInstaller.installer) : new ForgeInstallerResolver( diff --git a/src/main/java/me/itzg/helpers/forge/InstallNeoForgeCommand.java b/src/main/java/me/itzg/helpers/forge/InstallNeoForgeCommand.java index adae0231..4aee9da8 100644 --- a/src/main/java/me/itzg/helpers/forge/InstallNeoForgeCommand.java +++ b/src/main/java/me/itzg/helpers/forge/InstallNeoForgeCommand.java @@ -22,6 +22,7 @@ public class InstallNeoForgeCommand implements Callable { @Spec CommandLine.Model.CommandSpec spec; + @SuppressWarnings("unused") @Option(names = {"--help", "-h"}, usageHelp = true) boolean help; @@ -81,7 +82,7 @@ public void setVersion(String version) { public Integer call() throws Exception { try (SharedFetch sharedFetch = Fetch.sharedFetch("install-neoforge", sharedFetchArgs.options())) { - new ForgeInstaller( + new ForgeLikeInstaller( new NeoForgeInstallerResolver(sharedFetch, minecraftVersion, neoForgeVersion) ) .install(outputDirectory, resultsFile, forceReinstall, "NeoForge"); diff --git a/src/main/java/me/itzg/helpers/forge/InstallerResolver.java b/src/main/java/me/itzg/helpers/forge/InstallerResolver.java index d63d9186..64e14837 100644 --- a/src/main/java/me/itzg/helpers/forge/InstallerResolver.java +++ b/src/main/java/me/itzg/helpers/forge/InstallerResolver.java @@ -4,7 +4,7 @@ public interface InstallerResolver { - VersionPair resolve(); + VersionPair resolve(ForgeManifest prevManifest); Path download(String minecraftVersion, String forgeVersion, Path outputDir); diff --git a/src/main/java/me/itzg/helpers/forge/NeoForgeInstallerResolver.java b/src/main/java/me/itzg/helpers/forge/NeoForgeInstallerResolver.java index 613cc70e..07808665 100644 --- a/src/main/java/me/itzg/helpers/forge/NeoForgeInstallerResolver.java +++ b/src/main/java/me/itzg/helpers/forge/NeoForgeInstallerResolver.java @@ -25,6 +25,7 @@ public class NeoForgeInstallerResolver implements InstallerResolver { public static final String ARTIFACT_ID_FORGE_LIKE = "forge"; public static final String ARTIFACT_ID = "neoforge"; public static final String FORGE_LIKE_VERSION = "1.20.1"; + public static final String DEFAULT_MVN_URL = "https://maven.neoforged.net/releases"; private final MavenRepoApi mavenRepoApi; private final String requestedMinecraftVersion; @@ -36,7 +37,7 @@ public NeoForgeInstallerResolver(SharedFetch sharedFetch, @Nullable String requestedNeoForgeVersion ) { - this(sharedFetch, requestedMinecraftVersion, requestedNeoForgeVersion, "https://maven.neoforged.net/releases"); + this(sharedFetch, requestedMinecraftVersion, requestedNeoForgeVersion, DEFAULT_MVN_URL); } NeoForgeInstallerResolver(SharedFetch sharedFetch, @@ -60,7 +61,7 @@ enum NeoForgeVersionType { } @Override - public VersionPair resolve() { + public VersionPair resolve(ForgeManifest prevManifest) { if (useForgeArtifactId(requestedMinecraftVersion)) { return resolveForgeLike(); } @@ -84,6 +85,14 @@ else if (requestedNeoForgeVersion == null || requestedNeoForgeVersion.equalsIgno if (neoforgeVersion.length < 3) { throw new InvalidParameterException("Malformed NeoForge version: " + requestedNeoForgeVersion); } + + if (prevManifest != null) { + if (prevManifest.getMinecraftVersion().equals(requestedMinecraftVersion) + && prevManifest.getForgeVersion().equals(requestedNeoForgeVersion)) { + return new VersionPair(requestedMinecraftVersion, requestedNeoForgeVersion); + } + + } } final MavenMetadata metadata = mavenRepoApi.fetchMetadata(GROUP_ID, ARTIFACT_ID) diff --git a/src/main/java/me/itzg/helpers/forge/ProvidedInstallerResolver.java b/src/main/java/me/itzg/helpers/forge/ProvidedInstallerResolver.java index 2c05fc0e..8315bc99 100644 --- a/src/main/java/me/itzg/helpers/forge/ProvidedInstallerResolver.java +++ b/src/main/java/me/itzg/helpers/forge/ProvidedInstallerResolver.java @@ -26,7 +26,7 @@ public ProvidedInstallerResolver(Path forgeInstaller) { } @Override - public VersionPair resolve() { + public VersionPair resolve(ForgeManifest prevManifest) { final VersionPair versions; try { versions = extractVersion(forgeInstaller); diff --git a/src/main/java/me/itzg/helpers/modrinth/ModrinthPackInstaller.java b/src/main/java/me/itzg/helpers/modrinth/ModrinthPackInstaller.java index 68ea880d..fbf11fee 100644 --- a/src/main/java/me/itzg/helpers/modrinth/ModrinthPackInstaller.java +++ b/src/main/java/me/itzg/helpers/modrinth/ModrinthPackInstaller.java @@ -21,7 +21,7 @@ import me.itzg.helpers.fabric.FabricLauncherInstaller; import me.itzg.helpers.files.AntPathMatcher; import me.itzg.helpers.files.IoStreams; -import me.itzg.helpers.forge.ForgeInstaller; +import me.itzg.helpers.forge.ForgeLikeInstaller; import me.itzg.helpers.forge.ForgeInstallerResolver; import me.itzg.helpers.forge.ForgeUrlArgs; import me.itzg.helpers.forge.NeoForgeInstallerResolver; @@ -269,7 +269,7 @@ private void prepareFabric(SharedFetch sharedFetch, String minecraftVersion, Str } private void prepareForge(SharedFetch sharedFetch, String minecraftVersion, String version) { - new ForgeInstaller( + new ForgeLikeInstaller( new ForgeInstallerResolver(sharedFetch, minecraftVersion, version, forgeUrlArgs.getPromotionsUrl(), forgeUrlArgs.getMavenRepoUrl() ) @@ -283,7 +283,7 @@ private void prepareForge(SharedFetch sharedFetch, String minecraftVersion, Stri } private void prepareNeoForge(SharedFetch sharedFetch, String minecraftVersion, String version) { - new ForgeInstaller( + new ForgeLikeInstaller( new NeoForgeInstallerResolver(sharedFetch, minecraftVersion, version) ) .install( diff --git a/src/main/java/me/itzg/helpers/mvn/MavenRepoApi.java b/src/main/java/me/itzg/helpers/mvn/MavenRepoApi.java index 7153a7f0..62c00d7e 100644 --- a/src/main/java/me/itzg/helpers/mvn/MavenRepoApi.java +++ b/src/main/java/me/itzg/helpers/mvn/MavenRepoApi.java @@ -71,6 +71,10 @@ private Mono retrieveMetadata(String groupId, String artifactId) ) .toObject(MavenMetadata.class, xmlMapper) .assemble() + .doOnSubscribe(s -> + log.debug("Fetching maven metadata for {}:{} from {}", + groupId, artifactId, uriBuilder.getBaseUrl()) + ) .checkpoint(String.format("fetching metadata for %s:%s", groupId, artifactId)); } diff --git a/src/test/java/me/itzg/helpers/curseforge/CurseForgeInstallerTest.java b/src/test/java/me/itzg/helpers/curseforge/CurseForgeLikeInstallerTest.java similarity index 97% rename from src/test/java/me/itzg/helpers/curseforge/CurseForgeInstallerTest.java rename to src/test/java/me/itzg/helpers/curseforge/CurseForgeLikeInstallerTest.java index 3c5d41f7..5299db81 100644 --- a/src/test/java/me/itzg/helpers/curseforge/CurseForgeInstallerTest.java +++ b/src/test/java/me/itzg/helpers/curseforge/CurseForgeLikeInstallerTest.java @@ -8,7 +8,7 @@ import org.junit.jupiter.api.condition.EnabledIfSystemProperty; import org.junit.jupiter.api.io.TempDir; -class CurseForgeInstallerTest { +class CurseForgeLikeInstallerTest { @TempDir Path tempDir; diff --git a/src/test/java/me/itzg/helpers/forge/NeoForgeInstallerResolverTest.java b/src/test/java/me/itzg/helpers/forge/NeoForgeInstallerResolverTest.java index 58dae500..b7d19ea3 100644 --- a/src/test/java/me/itzg/helpers/forge/NeoForgeInstallerResolverTest.java +++ b/src/test/java/me/itzg/helpers/forge/NeoForgeInstallerResolverTest.java @@ -4,12 +4,14 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.params.provider.Arguments.arguments; +import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; import com.github.tomakehurst.wiremock.junit5.WireMockTest; import java.util.stream.Stream; import me.itzg.helpers.http.Fetch; import me.itzg.helpers.http.SharedFetch; import me.itzg.helpers.http.SharedFetch.Options; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -57,7 +59,7 @@ void resolve(String minecraftVersion, String neoforgeVersion, ) ); - final VersionPair versionPair = resolver.resolve(); + final VersionPair versionPair = resolver.resolve(null); if (expectedNeoforgeVersion == null) { assertThat(versionPair).isNull(); } @@ -70,4 +72,32 @@ void resolve(String minecraftVersion, String neoforgeVersion, } } + @Test + void resolveSkipsLookupWhenExists(WireMockRuntimeInfo wmInfo) { + final String minecraftVersion = "1.21.1"; + final String neoforgeVersion = "21.1.215"; + + try (SharedFetch sharedFetch = Fetch.sharedFetch("install-neoforge", Options.builder().build())) { + final NeoForgeInstallerResolver resolver = new NeoForgeInstallerResolver( + sharedFetch, + minecraftVersion, neoforgeVersion, + wmInfo.getHttpBaseUrl() + ); + + // purposely no stub of wiremock to verify no network calls are made + + final ForgeManifest manifest = ForgeManifest.builder() + .minecraftVersion(minecraftVersion) + .forgeVersion(neoforgeVersion) + .build(); + + final VersionPair versionPair = resolver.resolve(manifest); + + assertThat(versionPair).isNotNull(); + assertThat(versionPair.minecraft).isEqualTo(minecraftVersion); + assertThat(versionPair.forge).isEqualTo(neoforgeVersion); + + WireMock.verify(0, getRequestedFor(WireMock.anyUrl())); + } + } } \ No newline at end of file diff --git a/src/test/java/me/itzg/helpers/forge/ProvidedInstallerResolverTest.java b/src/test/java/me/itzg/helpers/forge/ProvidedInstallerResolverTest.java index 190f2323..fac457e6 100644 --- a/src/test/java/me/itzg/helpers/forge/ProvidedInstallerResolverTest.java +++ b/src/test/java/me/itzg/helpers/forge/ProvidedInstallerResolverTest.java @@ -23,7 +23,7 @@ void resolvesVersionFromFile() throws URISyntaxException { final ProvidedInstallerResolver resolver = new ProvidedInstallerResolver( Paths.get(installerUrl.toURI())); - final VersionPair versions = resolver.resolve(); + final VersionPair versions = resolver.resolve(null); assertThat(versions.minecraft).isEqualTo("1.20.2"); assertThat(versions.forge).isEqualTo("48.1.0");