From f92365ff831c9cccf562d9cb7c30e82c9997ce75 Mon Sep 17 00:00:00 2001 From: 0x189D7997 <199489335+0x189D7997@users.noreply.github.com> Date: Thu, 18 Dec 2025 19:48:08 +0000 Subject: [PATCH 1/3] Add getVersionsAssumeLoaded method and null-check executor when loading versions [no ci] --- .../manifest/BaseMetadataProvider.java | 18 +++++++++++++++++- .../gitcraft/manifest/MetadataProvider.java | 7 +++++++ ...HistoricMojangLauncherMetadataProvider.java | 7 ++----- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/main/groovy/com/github/winplay02/gitcraft/manifest/BaseMetadataProvider.java b/src/main/groovy/com/github/winplay02/gitcraft/manifest/BaseMetadataProvider.java index 25211acd..fdc6a927 100644 --- a/src/main/groovy/com/github/winplay02/gitcraft/manifest/BaseMetadataProvider.java +++ b/src/main/groovy/com/github/winplay02/gitcraft/manifest/BaseMetadataProvider.java @@ -93,6 +93,7 @@ protected final void writeSemverCache() { } /** + * Loads versions using given executor if they were not already loaded. Executor must be not null. * @return A map containing all available versions, keyed by a unique name (see {@linkplain VersionInfo#id()}). */ @Override @@ -101,12 +102,28 @@ public final Map getVersions(Executor executor) throws I return Collections.unmodifiableMap(this.versionsById); } + /** + * When calling the versions must be already loaded. Crashes if not. + * @return A map containing all available versions, keyed by a unique name (see {@linkplain VersionInfo#id()}). + */ + @Override + public final Map getVersionsAssumeLoaded() { + if (!this.versionsLoaded) { + MiscHelper.panic("getVersionsAssumeLoaded() called but the versions are not loaded"); + } + return Collections.unmodifiableMap(this.versionsById); + } + public final void initializeAndLoadVersions(Executor executor) throws IOException { synchronized (this) { if (!this.versionsLoaded) { + if (executor == null) { + MiscHelper.panic("Cannot load versions because provided executor is null"); + } this.loadVersions(executor); this.postLoadVersions(); this.writeSemverCache(); + this.versionsLoaded = true; } } } @@ -163,7 +180,6 @@ protected void loadVersions(Executor executor) throws IOException { } }); } - this.versionsLoaded = true; } protected void postLoadVersions() { diff --git a/src/main/groovy/com/github/winplay02/gitcraft/manifest/MetadataProvider.java b/src/main/groovy/com/github/winplay02/gitcraft/manifest/MetadataProvider.java index feb2f770..8c0ff0a6 100644 --- a/src/main/groovy/com/github/winplay02/gitcraft/manifest/MetadataProvider.java +++ b/src/main/groovy/com/github/winplay02/gitcraft/manifest/MetadataProvider.java @@ -25,10 +25,17 @@ public interface MetadataProvider> { String getInternalName(); /** + * Loads versions using given executor if they were not already loaded. Executor must be not null. * @return A map containing all available versions, keyed by a unique name (see {@linkplain VersionInfo#id VersionInfo.id}). */ Map getVersions(Executor executor) throws IOException; + /** + * When calling the versions must be already loaded. Crashes if not. + * @return A map containing all available versions, keyed by a unique name (see {@linkplain VersionInfo#id VersionInfo.id}). + */ + Map getVersionsAssumeLoaded(); + /** * Finds parent nodes to the provided version. Used to construct the {@link com.github.winplay02.gitcraft.graph.AbstractVersionGraph}. * diff --git a/src/main/groovy/com/github/winplay02/gitcraft/manifest/historic/HistoricMojangLauncherMetadataProvider.java b/src/main/groovy/com/github/winplay02/gitcraft/manifest/historic/HistoricMojangLauncherMetadataProvider.java index a28c65cb..a24700c1 100644 --- a/src/main/groovy/com/github/winplay02/gitcraft/manifest/historic/HistoricMojangLauncherMetadataProvider.java +++ b/src/main/groovy/com/github/winplay02/gitcraft/manifest/historic/HistoricMojangLauncherMetadataProvider.java @@ -191,10 +191,8 @@ private CompletableFuture constructMostHistoricallyTruthfulVersi @Override protected void loadVersions(Executor executor) throws IOException { this.versionsById.clear(); - this.mojangLauncherMetadataProvider.initializeAndLoadVersions(executor); - this.skyrisingMetadataProvider.initializeAndLoadVersions(executor); - Set mojangVersionIds = this.mojangLauncherMetadataProvider.getVersions(null).keySet(); - Set skyrisingVersionIds = this.skyrisingMetadataProvider.getVersions(null).keySet(); + Set mojangVersionIds = this.mojangLauncherMetadataProvider.getVersions(executor).keySet(); + Set skyrisingVersionIds = this.skyrisingMetadataProvider.getVersions(executor).keySet(); Set transformedSkyrisingVersionIds = MiscHelper.concatStreams( skyrisingVersionIds.stream().filter(SKYRISING_MOJANG_VERSION_ID_MAPPING::containsKey).map(SKYRISING_MOJANG_VERSION_ID_MAPPING::get), skyrisingVersionIds.stream().filter(Predicate.not(SKYRISING_MOJANG_VERSION_ID_MAPPING::containsKey)) @@ -232,7 +230,6 @@ protected void loadVersions(Executor executor) throws IOException { for (Map.Entry> futureEntry : futureVersionsMap.entrySet()) { this.versionsById.put(futureEntry.getKey(), futureEntry.getValue().join()); } - this.versionsLoaded = true; } @Override From 54807fc4f86e3d6a80e5a097367fb9172db93884 Mon Sep 17 00:00:00 2001 From: 0x189D7997 <199489335+0x189D7997@users.noreply.github.com> Date: Thu, 18 Dec 2025 21:10:55 +0000 Subject: [PATCH 2/3] Use new method in getVersionByVersionID [no ci] --- .../winplay02/gitcraft/manifest/BaseMetadataProvider.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/groovy/com/github/winplay02/gitcraft/manifest/BaseMetadataProvider.java b/src/main/groovy/com/github/winplay02/gitcraft/manifest/BaseMetadataProvider.java index fdc6a927..76ffae20 100644 --- a/src/main/groovy/com/github/winplay02/gitcraft/manifest/BaseMetadataProvider.java +++ b/src/main/groovy/com/github/winplay02/gitcraft/manifest/BaseMetadataProvider.java @@ -290,12 +290,7 @@ protected final boolean isExistingVersionMetadataValid(String id, String url, St @Override public final OrderedVersion getVersionByVersionID(String versionId) { - try { - return this.getVersions(null).get(versionId); - } catch (Exception e) { - MiscHelper.panicBecause(e, "Could not fetch version information by id '%s'", versionId); - return null; - } + return this.getVersionsAssumeLoaded().get(versionId); } @Override From ac3d73d87c139bb76ae992e07320592c202ef7de Mon Sep 17 00:00:00 2001 From: WinPlay02 Date: Sun, 21 Dec 2025 03:01:46 +0100 Subject: [PATCH 3/3] FIXED: Test --- .../winplay02/gitcraft/GitCraftTest.java | 86 ++++++++++++++++--- 1 file changed, 74 insertions(+), 12 deletions(-) diff --git a/src/test/groovy/com/github/winplay02/gitcraft/GitCraftTest.java b/src/test/groovy/com/github/winplay02/gitcraft/GitCraftTest.java index e60b24c2..f87b6f96 100644 --- a/src/test/groovy/com/github/winplay02/gitcraft/GitCraftTest.java +++ b/src/test/groovy/com/github/winplay02/gitcraft/GitCraftTest.java @@ -1,7 +1,9 @@ package com.github.winplay02.gitcraft; +import com.github.winplay02.gitcraft.config.ApplicationConfiguration; import com.github.winplay02.gitcraft.config.Configuration; import com.github.winplay02.gitcraft.exceptions.ExceptionsFlavour; +import com.github.winplay02.gitcraft.manifest.ManifestSource; import com.github.winplay02.gitcraft.manifest.skyrising.SkyrisingMetadataProvider; import com.github.winplay02.gitcraft.manifest.vanilla.MojangLauncherMetadataProvider; import com.github.winplay02.gitcraft.mappings.MappingFlavour; @@ -122,12 +124,32 @@ public void mappingsMojang() throws IOException, URISyntaxException, Interrupted @Test public void mappingsParchment() throws IOException, URISyntaxException, InterruptedException { - MojangLauncherMetadataProvider metadataBootstrap = new MojangLauncherMetadataProvider(); - Files.copy(LibraryPaths.lookupCurrentWorkingDirectory().resolve(String.format("semver-cache-%s.json", metadataBootstrap.getInternalName())), LibraryPaths.CURRENT_WORKING_DIRECTORY.resolve(String.format("semver-cache-%s.json", metadataBootstrap.getInternalName())), StandardCopyOption.REPLACE_EXISTING); - metadataBootstrap = new MojangLauncherMetadataProvider(); + MojangLauncherMetadataProvider metadataBootstrap1 = new MojangLauncherMetadataProvider(); + Files.copy(LibraryPaths.lookupCurrentWorkingDirectory().resolve(String.format("semver-cache-%s.json", metadataBootstrap1.getInternalName())), LibraryPaths.CURRENT_WORKING_DIRECTORY.resolve(String.format("semver-cache-%s.json", metadataBootstrap1.getInternalName())), StandardCopyOption.REPLACE_EXISTING); + Configuration.editConfiguration(ApplicationConfiguration.class, (original) -> new ApplicationConfiguration( + ManifestSource.MOJANG, + original.usedMapping(), + original.fallbackMappings(), + original.usedUnpickFlavour(), + original.fallbackUnpickFlavours(), + original.singleSideVersionsOnMainBranch(), + original.onlyStableReleases(), + original.onlySnapshots(), + original.skipNonLinear(), + original.onlyVersion(), + original.minVersion(), + original.maxVersion(), + original.excludedVersion(), + original.ornitheIntermediaryGeneration(), + original.patchLvt(), + original.usedExceptions(), + original.usedSignatures(), + original.usedNests(), + original.enablePreening() + )); MinecraftVersionGraph versionGraph; try (ExecutorService executor = Executors.newThreadPerTaskExecutor(Thread.ofVirtual().name("Testing-Executor").factory())) { - versionGraph = MinecraftVersionGraph.createFromMetadata(executor, metadataBootstrap); + versionGraph = MinecraftVersionGraph.createFromMetadata(executor, GitCraftApplication.getApplicationConfiguration().manifestSource().getMetadataProvider()); // Path mappingsPath = MappingFlavour.MOJMAP_PARCHMENT.getPath(versionGraph.getMinecraftVersionByName("1.20.1"), MinecraftJar.MERGED).orElse(null); assertNotNull(mappingsPath); @@ -148,12 +170,32 @@ public void mappingsParchment() throws IOException, URISyntaxException, Interrup @Test public void mappingsFabricIntermediary() throws IOException, URISyntaxException, InterruptedException { - MojangLauncherMetadataProvider metadataBootstrap = new MojangLauncherMetadataProvider(); - Files.copy(LibraryPaths.lookupCurrentWorkingDirectory().resolve(String.format("semver-cache-%s.json", metadataBootstrap.getInternalName())), LibraryPaths.CURRENT_WORKING_DIRECTORY.resolve(String.format("semver-cache-%s.json", metadataBootstrap.getInternalName())), StandardCopyOption.REPLACE_EXISTING); - metadataBootstrap = new MojangLauncherMetadataProvider(); + MojangLauncherMetadataProvider metadataBootstrap1 = new MojangLauncherMetadataProvider(); + Files.copy(LibraryPaths.lookupCurrentWorkingDirectory().resolve(String.format("semver-cache-%s.json", metadataBootstrap1.getInternalName())), LibraryPaths.CURRENT_WORKING_DIRECTORY.resolve(String.format("semver-cache-%s.json", metadataBootstrap1.getInternalName())), StandardCopyOption.REPLACE_EXISTING); + Configuration.editConfiguration(ApplicationConfiguration.class, (original) -> new ApplicationConfiguration( + ManifestSource.MOJANG, + original.usedMapping(), + original.fallbackMappings(), + original.usedUnpickFlavour(), + original.fallbackUnpickFlavours(), + original.singleSideVersionsOnMainBranch(), + original.onlyStableReleases(), + original.onlySnapshots(), + original.skipNonLinear(), + original.onlyVersion(), + original.minVersion(), + original.maxVersion(), + original.excludedVersion(), + original.ornitheIntermediaryGeneration(), + original.patchLvt(), + original.usedExceptions(), + original.usedSignatures(), + original.usedNests(), + original.enablePreening() + )); MinecraftVersionGraph versionGraph; try (ExecutorService executor = Executors.newThreadPerTaskExecutor(Thread.ofVirtual().name("Testing-Executor").factory())) { - versionGraph = MinecraftVersionGraph.createFromMetadata(executor, metadataBootstrap); + versionGraph = MinecraftVersionGraph.createFromMetadata(executor, GitCraftApplication.getApplicationConfiguration().manifestSource().getMetadataProvider()); // Path mappingsPath = MappingFlavour.FABRIC_INTERMEDIARY.getPath(versionGraph.getMinecraftVersionByName("1.20"), MinecraftJar.MERGED).orElse(null); assertNotNull(mappingsPath); @@ -174,12 +216,32 @@ public void mappingsFabricIntermediary() throws IOException, URISyntaxException, @Test public void mappingsYarn() throws IOException, URISyntaxException, InterruptedException { - MojangLauncherMetadataProvider metadataBootstrap = new MojangLauncherMetadataProvider(); - Files.copy(LibraryPaths.lookupCurrentWorkingDirectory().resolve(String.format("semver-cache-%s.json", metadataBootstrap.getInternalName())), LibraryPaths.CURRENT_WORKING_DIRECTORY.resolve(String.format("semver-cache-%s.json", metadataBootstrap.getInternalName())), StandardCopyOption.REPLACE_EXISTING); - metadataBootstrap = new MojangLauncherMetadataProvider(); + MojangLauncherMetadataProvider metadataBootstrap1 = new MojangLauncherMetadataProvider(); + Files.copy(LibraryPaths.lookupCurrentWorkingDirectory().resolve(String.format("semver-cache-%s.json", metadataBootstrap1.getInternalName())), LibraryPaths.CURRENT_WORKING_DIRECTORY.resolve(String.format("semver-cache-%s.json", metadataBootstrap1.getInternalName())), StandardCopyOption.REPLACE_EXISTING); + Configuration.editConfiguration(ApplicationConfiguration.class, (original) -> new ApplicationConfiguration( + ManifestSource.MOJANG, + original.usedMapping(), + original.fallbackMappings(), + original.usedUnpickFlavour(), + original.fallbackUnpickFlavours(), + original.singleSideVersionsOnMainBranch(), + original.onlyStableReleases(), + original.onlySnapshots(), + original.skipNonLinear(), + original.onlyVersion(), + original.minVersion(), + original.maxVersion(), + original.excludedVersion(), + original.ornitheIntermediaryGeneration(), + original.patchLvt(), + original.usedExceptions(), + original.usedSignatures(), + original.usedNests(), + original.enablePreening() + )); MinecraftVersionGraph versionGraph; try (ExecutorService executor = Executors.newThreadPerTaskExecutor(Thread.ofVirtual().name("Testing-Executor").factory())) { - versionGraph = MinecraftVersionGraph.createFromMetadata(executor, metadataBootstrap); + versionGraph = MinecraftVersionGraph.createFromMetadata(executor, GitCraftApplication.getApplicationConfiguration().manifestSource().getMetadataProvider()); // Path mappingsPath = MappingFlavour.YARN.getPath(versionGraph.getMinecraftVersionByName("1.20"), MinecraftJar.MERGED).orElse(null); assertNotNull(mappingsPath);