Use different cache files for custom manifest and metadata jsons (#1077)

* use different cache files for custom manifest and metadata jsons

* add properties for custom manifests to loom extension api

* expand manifests api with a priority queue

* add ApiStatus annotations where needed

* explain sort order in javadoc

* add getVersionMetaFileName function

* merge the two manifests locations together

* convert hash code to hex string

* fix metadata provider tests

* update priorities of built in manifests so they're first by default

* fix VersionsManifestAPI javadoc

* update comment in MinecraftMetadataProvider

* fix ManifestLocation.cacheFile

* deprecate and replace getCustomMinecraftManifest
This commit is contained in:
Space Walker
2024-05-04 19:18:26 +02:00
committed by GitHub
parent 63ebc35e1d
commit c5c52aba65
8 changed files with 257 additions and 64 deletions

View File

@@ -43,6 +43,7 @@ import org.gradle.api.tasks.SourceSet;
import org.jetbrains.annotations.ApiStatus;
import net.fabricmc.loom.api.decompilers.DecompilerOptions;
import net.fabricmc.loom.api.manifest.VersionsManifestsAPI;
import net.fabricmc.loom.api.mappings.intermediate.IntermediateMappingsProvider;
import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder;
import net.fabricmc.loom.api.processor.MinecraftJarProcessor;
@@ -51,6 +52,7 @@ import net.fabricmc.loom.api.remapping.RemapperParameters;
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
import net.fabricmc.loom.configuration.processors.JarProcessor;
import net.fabricmc.loom.configuration.providers.mappings.NoOpIntermediateMappingsProvider;
import net.fabricmc.loom.configuration.providers.minecraft.ManifestLocations;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration;
import net.fabricmc.loom.task.GenerateSourcesTask;
import net.fabricmc.loom.util.DeprecationHelper;
@@ -132,7 +134,23 @@ public interface LoomGradleExtensionAPI {
InterfaceInjectionExtensionAPI getInterfaceInjection();
Property<String> getCustomMinecraftManifest();
@ApiStatus.Experimental
default void versionsManifests(Action<VersionsManifestsAPI> action) {
action.execute(getVersionsManifests());
}
@ApiStatus.Experimental
ManifestLocations getVersionsManifests();
/**
* @deprecated use {@linkplain #getCustomMinecraftMetadata} instead
*/
@Deprecated
default Property<String> getCustomMinecraftManifest() {
return getCustomMinecraftMetadata();
}
Property<String> getCustomMinecraftMetadata();
SetProperty<String> getKnownIndyBsms();

View File

@@ -0,0 +1,46 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2024 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.api.manifest;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Experimental
public interface VersionsManifestsAPI {
/**
* Adds a URL to a versions manifest json with the default priority of {@code 0}.
* @param url the String-representation of the URL to the manifest json
*/
default void add(String url) {
add(url, 0);
}
/**
* Adds a URL to a versions manifest json with the given priority.
* @param url the String-representation of the URL to the manifest json
* @param priority the priority with which this URL gets sorted against other entries
* entries are sorted by priority, from lowest to highest
*/
void add(String url, int priority);
}

View File

@@ -0,0 +1,93 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2024 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.configuration.providers.minecraft;
import java.nio.file.Path;
import java.util.Iterator;
import java.util.PriorityQueue;
import java.util.Queue;
import net.fabricmc.loom.api.manifest.VersionsManifestsAPI;
import net.fabricmc.loom.configuration.providers.minecraft.ManifestLocations.ManifestLocation;
public class ManifestLocations implements VersionsManifestsAPI, Iterable<ManifestLocation> {
private static final String FILE_EXTENSION = ".json";
private final Queue<ManifestLocation> locations = new PriorityQueue<>();
private final String baseFileName;
public ManifestLocations(String baseFileName) {
this.baseFileName = baseFileName;
}
public void addBuiltIn(int priority, String url, String fileName) {
locations.add(new ManifestLocation(priority, url, fileName));
}
@Override
public void add(String url, int priority) {
locations.add(new ManifestLocation(priority, url));
}
@Override
public Iterator<ManifestLocation> iterator() {
return locations.iterator();
}
public class ManifestLocation implements Comparable<ManifestLocation> {
private final int priority;
private final String url;
private final String builtInFileName;
private ManifestLocation(int priority, String url) {
this(priority, url, null);
}
private ManifestLocation(int priority, String url, String builtInFileName) {
this.priority = priority;
this.url = url;
this.builtInFileName = builtInFileName;
}
public boolean isBuiltIn() {
return builtInFileName != null;
}
public String url() {
return url;
}
public Path cacheFile(Path dir) {
String fileName = (builtInFileName != null)
? builtInFileName + FILE_EXTENSION
: baseFileName + "-" + Integer.toHexString(url.hashCode()) + FILE_EXTENSION;
return dir.resolve(fileName);
}
@Override
public int compareTo(ManifestLocation o) {
return Integer.compare(priority, o.priority);
}
}
}

View File

@@ -27,25 +27,27 @@ package net.fabricmc.loom.configuration.providers.minecraft;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import org.gradle.api.Project;
import org.gradle.api.provider.Property;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.LoomGradlePlugin;
import net.fabricmc.loom.configuration.ConfigContext;
import net.fabricmc.loom.configuration.DependencyInfo;
import net.fabricmc.loom.configuration.providers.minecraft.ManifestLocations.ManifestLocation;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.MirrorUtil;
import net.fabricmc.loom.util.download.DownloadBuilder;
public final class MinecraftMetadataProvider {
private final Options options;
private final Function<String, DownloadBuilder> download;
private ManifestVersion.Versions versionEntry;
private ManifestEntryLocation versionEntry;
private MinecraftVersionMeta versionMeta;
private MinecraftMetadataProvider(Options options, Function<String, DownloadBuilder> download) {
@@ -55,13 +57,11 @@ public final class MinecraftMetadataProvider {
public static MinecraftMetadataProvider create(ConfigContext configContext) {
final String minecraftVersion = resolveMinecraftVersion(configContext.project());
final Path workingDir = MinecraftProvider.minecraftWorkingDirectory(configContext.project(), minecraftVersion).toPath();
return new MinecraftMetadataProvider(
MinecraftMetadataProvider.Options.create(
minecraftVersion,
configContext.project(),
workingDir.resolve("minecraft-info.json")
configContext.project()
),
configContext.extension()::download
);
@@ -92,28 +92,29 @@ public final class MinecraftMetadataProvider {
return versionMeta;
}
private ManifestVersion.Versions getVersionEntry() throws IOException {
private ManifestEntryLocation getVersionEntry() throws IOException {
// Custom URL always takes priority
if (options.customManifestUrl() != null) {
ManifestVersion.Versions customVersion = new ManifestVersion.Versions();
VersionsManifest.Version customVersion = new VersionsManifest.Version();
customVersion.id = options.minecraftVersion();
customVersion.url = options.customManifestUrl();
return customVersion;
return new ManifestEntryLocation(null, customVersion);
}
final List<ManifestVersionSupplier> suppliers = List.of(
// First try finding the version with caching
() -> getVersions(false),
// Then try finding the experimental version with caching
() -> getExperimentalVersions(false),
// Then force download Mojang's metadata to find the version
() -> getVersions(true),
// Finally try a force downloaded experimental metadata.
() -> getExperimentalVersions(true)
);
final List<ManifestEntrySupplier> suppliers = new ArrayList<>();
for (ManifestVersionSupplier supplier : suppliers) {
final ManifestVersion.Versions version = supplier.get().getVersion(options.minecraftVersion());
// First try finding the version with caching
for (ManifestLocation location : options.versionsManifests()) {
suppliers.add(() -> getManifestEntry(location, false));
}
// Then force download the manifest to find the version
for (ManifestLocation location : options.versionsManifests()) {
suppliers.add(() -> getManifestEntry(location, true));
}
for (ManifestEntrySupplier supplier : suppliers) {
final ManifestEntryLocation version = supplier.get();
if (version != null) {
return version;
@@ -123,16 +124,8 @@ public final class MinecraftMetadataProvider {
throw new RuntimeException("Failed to find minecraft version: " + options.minecraftVersion());
}
private ManifestVersion getVersions(boolean forceDownload) throws IOException {
return getVersions(options.versionManifestUrl(), options.versionManifestPath(), forceDownload);
}
private ManifestVersion getExperimentalVersions(boolean forceDownload) throws IOException {
return getVersions(options.experimentalVersionManifestUrl(), options.experimentalVersionManifestPath(), forceDownload);
}
private ManifestVersion getVersions(String url, Path cacheFile, boolean forceDownload) throws IOException {
DownloadBuilder builder = download.apply(url);
private ManifestEntryLocation getManifestEntry(ManifestLocation location, boolean forceDownload) throws IOException {
DownloadBuilder builder = download.apply(location.url());
if (forceDownload) {
builder = builder.forceDownload();
@@ -140,48 +133,77 @@ public final class MinecraftMetadataProvider {
builder = builder.defaultCache();
}
final Path cacheFile = location.cacheFile(options.userCache());
final String versionManifest = builder.downloadString(cacheFile);
return LoomGradlePlugin.GSON.fromJson(versionManifest, ManifestVersion.class);
final VersionsManifest manifest = LoomGradlePlugin.GSON.fromJson(versionManifest, VersionsManifest.class);
final VersionsManifest.Version version = manifest.getVersion(options.minecraftVersion());
if (version != null) {
return new ManifestEntryLocation(location, version);
}
return null;
}
private MinecraftVersionMeta readVersionMeta() throws IOException {
final DownloadBuilder builder = download.apply(versionEntry.url);
final DownloadBuilder builder = download.apply(versionEntry.entry.url);
if (versionEntry.sha1 != null) {
builder.sha1(versionEntry.sha1);
if (versionEntry.entry.sha1 != null) {
builder.sha1(versionEntry.entry.sha1);
} else {
builder.defaultCache();
}
final String json = builder.downloadString(options.minecraftMetadataPath());
final String fileName = getVersionMetaFileName();
final Path cacheFile = options.workingDir().resolve(fileName);
final String json = builder.downloadString(cacheFile);
return LoomGradlePlugin.GSON.fromJson(json, MinecraftVersionMeta.class);
}
private String getVersionMetaFileName() {
String base = "minecraft-info";
// custom version metadata
if (versionEntry.manifest == null) {
return base + Integer.toHexString(versionEntry.entry.url.hashCode()) + ".json";
}
// custom versions manifest
if (!versionEntry.manifest.isBuiltIn()) {
return base + Integer.toHexString(versionEntry.manifest.url().hashCode()) + ".json";
}
return base + ".json";
}
public record Options(String minecraftVersion,
String versionManifestUrl,
String experimentalVersionManifestUrl,
ManifestLocations versionsManifests,
@Nullable String customManifestUrl,
Path versionManifestPath,
Path experimentalVersionManifestPath,
Path minecraftMetadataPath) {
public static Options create(String minecraftVersion, Project project, Path minecraftMetadataPath) {
Path userCache,
Path workingDir) {
public static Options create(String minecraftVersion, Project project) {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
final Path userCache = extension.getFiles().getUserCache().toPath();
final Path workingDir = MinecraftProvider.minecraftWorkingDirectory(project, minecraftVersion).toPath();
final ManifestLocations manifestLocations = extension.getVersionsManifests();
final Property<String> customMetaUrl = extension.getCustomMinecraftMetadata();
return new Options(
minecraftVersion,
MirrorUtil.getVersionManifests(project),
MirrorUtil.getExperimentalVersions(project),
extension.getCustomMinecraftManifest().getOrNull(),
userCache.resolve("version_manifest.json"),
userCache.resolve("experimental_version_manifest.json"),
minecraftMetadataPath
manifestLocations,
customMetaUrl.getOrNull(),
userCache,
workingDir
);
}
}
@FunctionalInterface
private interface ManifestVersionSupplier {
ManifestVersion get() throws IOException;
private interface ManifestEntrySupplier {
ManifestEntryLocation get() throws IOException;
}
private record ManifestEntryLocation(ManifestLocation manifest, VersionsManifest.Version entry) {
}
}

View File

@@ -29,13 +29,13 @@ import java.util.Map;
import org.jetbrains.annotations.Nullable;
public record ManifestVersion(List<Versions> versions, Map<String, String> latest) {
public static class Versions {
public record VersionsManifest(List<Version> versions, Map<String, String> latest) {
public static class Version {
public String id, url, sha1;
}
@Nullable
public Versions getVersion(String id) {
public Version getVersion(String id) {
return versions.stream()
.filter(versions -> versions.id.equalsIgnoreCase(id))
.findFirst()

View File

@@ -66,10 +66,12 @@ import net.fabricmc.loom.configuration.processors.JarProcessor;
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpec;
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilderImpl;
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsFactory;
import net.fabricmc.loom.configuration.providers.minecraft.ManifestLocations;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
import net.fabricmc.loom.task.GenerateSourcesTask;
import net.fabricmc.loom.util.DeprecationHelper;
import net.fabricmc.loom.util.MirrorUtil;
import net.fabricmc.loom.util.fmj.FabricModJson;
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
import net.fabricmc.loom.util.gradle.SourceSetHelper;
@@ -83,7 +85,8 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
protected final ListProperty<JarProcessor> jarProcessors;
protected final ConfigurableFileCollection log4jConfigs;
protected final RegularFileProperty accessWidener;
protected final Property<String> customManifest;
protected final ManifestLocations versionsManifests;
protected final Property<String> customMetadata;
protected final SetProperty<String> knownIndyBsms;
protected final Property<Boolean> transitiveAccessWideners;
protected final Property<Boolean> modProvidedJavadoc;
@@ -114,7 +117,10 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
.empty();
this.log4jConfigs = project.files(directories.getDefaultLog4jConfigFile());
this.accessWidener = project.getObjects().fileProperty();
this.customManifest = project.getObjects().property(String.class);
this.versionsManifests = new ManifestLocations("versions_manifest");
this.versionsManifests.addBuiltIn(-2, MirrorUtil.getVersionManifests(project), "versions_manifest");
this.versionsManifests.addBuiltIn(-1, MirrorUtil.getExperimentalVersions(project), "experimental_versions_manifest");
this.customMetadata = project.getObjects().property(String.class);
this.knownIndyBsms = project.getObjects().setProperty(String.class).convention(Set.of(
"java/lang/invoke/StringConcatFactory",
"java/lang/runtime/ObjectMethods",
@@ -254,8 +260,13 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
}
@Override
public Property<String> getCustomMinecraftManifest() {
return customManifest;
public ManifestLocations getVersionsManifests() {
return versionsManifests;
}
@Override
public Property<String> getCustomMinecraftMetadata() {
return customMetadata;
}
@Override

View File

@@ -29,6 +29,7 @@ import java.nio.file.Path
import org.intellij.lang.annotations.Language
import net.fabricmc.loom.configuration.providers.minecraft.ManifestLocations
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMetadataProvider
import net.fabricmc.loom.test.LoomTestConstants
import net.fabricmc.loom.test.unit.download.DownloadTest
@@ -152,14 +153,16 @@ class MinecraftMetadataProviderTest extends DownloadTest {
}
private MinecraftMetadataProvider.Options options(String version, String customUrl) {
ManifestLocations manifests = new ManifestLocations("versions_manifest")
manifests.addBuiltIn(0, "$PATH/versionManifest", "versions_manifest")
manifests.addBuiltIn(1, "$PATH/experimentalVersionManifest", "experimental_versions_manifest")
return new MinecraftMetadataProvider.Options(
version,
"$PATH/versionManifest",
"$PATH/experimentalVersionManifest",
manifests,
customUrl,
testDir.resolve("version_manifest.json"),
testDir.resolve("experimental_version_manifest.json"),
testDir.resolve("${version}.json")
testDir,
testDir
)
}

View File

@@ -29,8 +29,8 @@ import java.time.Duration
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import net.fabricmc.loom.configuration.providers.minecraft.ManifestVersion
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta
import net.fabricmc.loom.configuration.providers.minecraft.VersionsManifest
import net.fabricmc.loom.test.LoomTestConstants
import net.fabricmc.loom.util.Constants
import net.fabricmc.loom.util.download.Download
@@ -41,7 +41,7 @@ class MinecraftTestUtils {
static MinecraftVersionMeta getVersionMeta(String id) {
def versionManifest = download(Constants.VERSION_MANIFESTS, "version_manifest.json")
def manifest = GSON.fromJson(versionManifest, ManifestVersion.class)
def manifest = GSON.fromJson(versionManifest, VersionsManifest.class)
def version = manifest.versions().find { it.id == id }
def metaJson = download(version.url, "${id}.json")