From 60f9ed4c1627f692d4ba7b06359ed29900735840 Mon Sep 17 00:00:00 2001 From: Ennui Langeweile <85590273+EnnuiL@users.noreply.github.com> Date: Tue, 11 Jul 2023 18:54:50 -0300 Subject: [PATCH] Add Loom support for `quilt.mod.json5` (#36) * Add support for `quilt.mod.json5` * Satisfy Checkstyle those switch rules aaaaaaaaaaaaa * Use Quilt Parsers instead of Quilt JSON5 * Polish the diff by removing unnecessary differences --- patches/0007-Add-support-for-QMJ5.patch | 406 ++++++++++++++++++++++++ 1 file changed, 406 insertions(+) create mode 100644 patches/0007-Add-support-for-QMJ5.patch diff --git a/patches/0007-Add-support-for-QMJ5.patch b/patches/0007-Add-support-for-QMJ5.patch new file mode 100644 index 0000000..3ff64c6 --- /dev/null +++ b/patches/0007-Add-support-for-QMJ5.patch @@ -0,0 +1,406 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ennui Langeweile <85590273+EnnuiL@users.noreply.github.com> +Date: Mon, 3 Jul 2023 22:01:25 -0300 +Subject: [PATCH] Add support for QMJ5 + + +diff --git a/build.gradle b/build.gradle +index d9e90d46948d9335225f959e865af681056a3d51..ca4f9fbddf1090a1dbea4121dae1a31dceab9e83 100644 +--- a/build.gradle ++++ b/build.gradle +@@ -107,8 +107,12 @@ dependencies { + // Kapt integration + compileOnly('org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0') // Must match the version included with gradle. + ++ // Dependencies we import ++ implementation('org.quiltmc.parsers:json:0.2.0') ++ implementation('org.quiltmc.parsers:gson:0.2.0') ++ + // Plugins we apply +- implementation("io.github.juuxel:loom-quiltflower:1.10.0") { ++ implementation('io.github.juuxel:loom-quiltflower:1.10.0') { + exclude group: "net.fabricmc", module: "fabric-loom" + } + +diff --git a/src/main/java/net/fabricmc/loom/configuration/metadata/ModMetadataHelper.java b/src/main/java/net/fabricmc/loom/configuration/metadata/ModMetadataHelper.java +index 490240ac688d7fddba464b70005d7c236265c9b2..a2628646b174b630be103433dd1eb415449adced 100644 +--- a/src/main/java/net/fabricmc/loom/configuration/metadata/ModMetadataHelper.java ++++ b/src/main/java/net/fabricmc/loom/configuration/metadata/ModMetadataHelper.java +@@ -46,6 +46,7 @@ import net.fabricmc.loom.util.metadata.ModJsonFactory; + public class ModMetadataHelper { + public static final String FABRIC_MOD_JSON = "fabric.mod.json"; + public static final String QUILT_MOD_JSON = "quilt.mod.json"; ++ public static final String QUILT_MOD_JSON5 = "quilt.mod.json5"; + + // Returns a list of Mods found in the provided project's main or client sourcesets + public static List getModsInProject(Project project) { +@@ -75,18 +76,34 @@ public class ModMetadataHelper { + } + + public static boolean isModJar(Path input) { +- return ZipUtils.contains(input, QUILT_MOD_JSON) || ZipUtils.contains(input, FABRIC_MOD_JSON); ++ return ZipUtils.contains(input, QUILT_MOD_JSON5) ++ || ZipUtils.contains(input, QUILT_MOD_JSON) ++ || ZipUtils.contains(input, FABRIC_MOD_JSON); + } + + public static boolean containsMod(FileSystemUtil.Delegate fs) { +- return Files.exists(fs.getPath(QUILT_MOD_JSON)) || Files.exists(fs.getPath(FABRIC_MOD_JSON)); ++ return Files.exists(fs.getPath(QUILT_MOD_JSON5)) ++ || Files.exists(fs.getPath(QUILT_MOD_JSON)) ++ || Files.exists(fs.getPath(FABRIC_MOD_JSON)); + } + + public static boolean isQuiltMod(Path jar) { + return ZipUtils.contains(jar, QUILT_MOD_JSON); + } + ++ public static boolean isQuiltModWithQMJ5(Path jar) { ++ return ZipUtils.contains(jar, QUILT_MOD_JSON5); ++ } ++ + public static String getMetadataPath(Path jar) { +- return isQuiltMod(jar) ? QUILT_MOD_JSON : FABRIC_MOD_JSON; ++ if (isQuiltModWithQMJ5(jar)) { ++ return QUILT_MOD_JSON5; ++ } ++ ++ if (isQuiltMod(jar)) { ++ return QUILT_MOD_JSON5; ++ } ++ ++ return FABRIC_MOD_JSON; + } + } +diff --git a/src/main/java/net/fabricmc/loom/extension/ModVersionParser.java b/src/main/java/net/fabricmc/loom/extension/ModVersionParser.java +index 6b2099e99f220c336a7c6fa0f229b8ecd474b1fb..b8aacec03c84745d285dda182b2978d1f1ef10dd 100644 +--- a/src/main/java/net/fabricmc/loom/extension/ModVersionParser.java ++++ b/src/main/java/net/fabricmc/loom/extension/ModVersionParser.java +@@ -68,9 +68,12 @@ public class ModVersionParser { + + private File locateModJsonFile() { + var resources = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets().getByName("main").getResources(); ++ var qmj5 = resources.matching(patternFilterable -> patternFilterable.include("quilt.mod.json5")); + var qmj = resources.matching(patternFilterable -> patternFilterable.include("quilt.mod.json")); + +- if (!qmj.isEmpty()) { ++ if (!qmj5.isEmpty()) { ++ return qmj5.getSingleFile(); ++ } else if (!qmj.isEmpty()) { + return qmj.getSingleFile(); + } else { + return resources.matching(patternFilterable -> patternFilterable.include("fabric.mod.json")).getSingleFile(); +diff --git a/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java b/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java +index 3abc7c0a49a1cb1a0f8da48a24e36bc852a4a90a..5c90400e90bf1a01b7cbf595af39c986b8e95c68 100644 +--- a/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java ++++ b/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java +@@ -28,6 +28,7 @@ import java.io.ByteArrayInputStream; + import java.io.ByteArrayOutputStream; + import java.io.File; + import java.io.IOException; ++import java.nio.charset.StandardCharsets; + import java.nio.file.Path; + import java.util.ArrayList; + import java.util.List; +@@ -40,6 +41,7 @@ import java.util.jar.Manifest; + import javax.inject.Inject; + + import com.google.common.base.Preconditions; ++import com.google.gson.JsonElement; + import org.gradle.api.Action; + import org.gradle.api.file.ConfigurableFileCollection; + import org.gradle.api.file.RegularFileProperty; +@@ -60,8 +62,11 @@ import org.gradle.workers.WorkParameters; + import org.gradle.workers.WorkQueue; + import org.gradle.workers.WorkerExecutor; + import org.jetbrains.annotations.ApiStatus; ++import org.quiltmc.parsers.json.JsonReader; ++import org.quiltmc.parsers.json.gson.GsonReader; + + import net.fabricmc.loom.LoomGradleExtension; ++import net.fabricmc.loom.LoomGradlePlugin; + import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; + import net.fabricmc.loom.task.service.JarManifestService; + import net.fabricmc.loom.util.ZipReprocessorUtil; +@@ -75,6 +80,8 @@ public abstract class AbstractRemapJarTask extends Jar { + public static final String MANIFEST_CLIENT_ENTRIES_KEY = "Fabric-Loom-Client-Only-Entries"; + public static final Attributes.Name MANIFEST_SPLIT_ENV_NAME = new Attributes.Name(MANIFEST_SPLIT_ENV_KEY); + public static final Attributes.Name MANIFEST_CLIENT_ENTRIES_NAME = new Attributes.Name(MANIFEST_CLIENT_ENTRIES_KEY); ++ public static final String QUILT_MOD_JSON5_PATH = "quilt.mod.json5"; ++ public static final String QUILT_MOD_JSON_PATH = "quilt.mod.json"; + + @InputFile + public abstract RegularFileProperty getInputFile(); +@@ -184,6 +191,18 @@ public abstract class AbstractRemapJarTask extends Jar { + outputFile = getParameters().getOutputFile().getAsFile().get().toPath(); + } + ++ protected void convertQmj5ToQmj() throws IOException { ++ ZipUtils.transform(outputFile, Map.of(QUILT_MOD_JSON5_PATH, bytes -> { ++ var jsonReader = new GsonReader(JsonReader.json5(new String(bytes, StandardCharsets.UTF_8))); ++ var element = LoomGradlePlugin.GSON.fromJson(jsonReader, JsonElement.class); ++ var convertedElement = LoomGradlePlugin.GSON.toJson(element); ++ ++ return convertedElement.getBytes(); ++ })); ++ ++ ZipUtils.move(outputFile, QUILT_MOD_JSON5_PATH, QUILT_MOD_JSON_PATH); ++ } ++ + protected void modifyJarManifest() throws IOException { + int count = ZipUtils.transform(outputFile, Map.of(MANIFEST_PATH, bytes -> { + var manifest = new Manifest(new ByteArrayInputStream(bytes)); +diff --git a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java +index 319fde2eda353146b917b2cb59149083b7ea5430..04692b0147c6b579a1693349dad131a9f9eb7557 100644 +--- a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java ++++ b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java +@@ -215,6 +215,7 @@ public abstract class RemapJarTask extends AbstractRemapJarTask { + markClientOnlyClasses(); + } + ++ convertQmj5ToQmj(); + remapAccessWidener(); + addRefmaps(); + addNestedJars(); +diff --git a/src/main/java/net/fabricmc/loom/task/RemapSourcesJarTask.java b/src/main/java/net/fabricmc/loom/task/RemapSourcesJarTask.java +index cca9638ed583a3e25e3142f02188293f2c23a6c5..7138ecdddcff8cd9959408c4205552882f014d2e 100644 +--- a/src/main/java/net/fabricmc/loom/task/RemapSourcesJarTask.java ++++ b/src/main/java/net/fabricmc/loom/task/RemapSourcesJarTask.java +@@ -87,6 +87,7 @@ public abstract class RemapSourcesJarTask extends AbstractRemapJarTask { + try { + sourceRemapperService.remapSourcesJar(inputFile, outputFile); + ++ convertQmj5ToQmj(); + modifyJarManifest(); + rewriteJar(); + } catch (Exception e) { +diff --git a/src/main/java/net/fabricmc/loom/util/ZipUtils.java b/src/main/java/net/fabricmc/loom/util/ZipUtils.java +index f6214aed8a99b99af52dcca76d78a36c2cf29213..c7fded73c2da28df3f02dfe54ce2c561b1da22bf 100644 +--- a/src/main/java/net/fabricmc/loom/util/ZipUtils.java ++++ b/src/main/java/net/fabricmc/loom/util/ZipUtils.java +@@ -47,6 +47,8 @@ import org.jetbrains.annotations.Nullable; + import org.objectweb.asm.ClassReader; + import org.objectweb.asm.ClassVisitor; + import org.objectweb.asm.ClassWriter; ++import org.quiltmc.parsers.json.JsonReader; ++import org.quiltmc.parsers.json.gson.GsonReader; + + import net.fabricmc.loom.LoomGradlePlugin; + +@@ -112,6 +114,12 @@ public class ZipUtils { + return LoomGradlePlugin.GSON.fromJson(new String(bytes, StandardCharsets.UTF_8), clazz); + } + ++ public static T unpackGsonWithJson5(Path zip, String path, Class clazz) throws IOException { ++ final byte[] bytes = unpack(zip, path); ++ final var reader = new GsonReader(JsonReader.json5(new String(bytes, StandardCharsets.UTF_8))); ++ return LoomGradlePlugin.GSON.fromJson(reader, clazz); ++ } ++ + @Nullable + public static T unpackGsonNullable(Path zip, String path, Class clazz) throws IOException { + try { +@@ -121,6 +129,15 @@ public class ZipUtils { + } + } + ++ @Nullable ++ public static T unpackGsonWithJson5Nullable(Path zip, String path, Class clazz) throws IOException { ++ try { ++ return unpackGsonWithJson5(zip, path, clazz); ++ } catch (NoSuchFileException e) { ++ return null; ++ } ++ } ++ + public static T unpackJackson(Path zip, String path, Class clazz) throws IOException { + final byte[] bytes = unpack(zip, path); + return LoomGradlePlugin.OBJECT_MAPPER.readValue(new String(bytes, StandardCharsets.UTF_8), clazz); +@@ -184,6 +201,20 @@ public class ZipUtils { + } + } + ++ public static void move(Path zip, String path, String newPath) throws IOException { ++ try (FileSystemUtil.Delegate fs = FileSystemUtil.getJarFileSystem(zip, true)) { ++ Path fsPath = fs.get().getPath(path); ++ Path newFsPath = fs.get().getPath(newPath); ++ ++ if (Files.exists(fsPath)) { ++ Files.write(newFsPath, Files.readAllBytes(fsPath), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); ++ Files.delete(fsPath); ++ } else { ++ throw new NoSuchFileException(fsPath.toString()); ++ } ++ } ++ } ++ + public static int transformString(Path zip, Collection>> transforms) throws IOException { + return transformString(zip, transforms.stream()); + } +diff --git a/src/main/java/net/fabricmc/loom/util/metadata/ModJsonFactory.java b/src/main/java/net/fabricmc/loom/util/metadata/ModJsonFactory.java +index 1af5a154c301b8b18ddef1148b6d05fa1ceddb68..4b26643a6fc9d22071b4c7b34a23c2e034b7e107 100644 +--- a/src/main/java/net/fabricmc/loom/util/metadata/ModJsonFactory.java ++++ b/src/main/java/net/fabricmc/loom/util/metadata/ModJsonFactory.java +@@ -39,25 +39,34 @@ import net.fabricmc.loom.util.gradle.SourceSetHelper; + import net.fabricmc.loom.util.qmj.QuiltModJsonFactory; + + public class ModJsonFactory { ++ public static final String QUILT_MOD_JSON = "quilt.mod.json"; ++ public static final String QUILT_MOD_JSON5 = "quilt.mod.json5"; ++ + public static ModJson createFromZip(Path zipPath) { +- if (ModMetadataHelper.isQuiltMod(zipPath)) { +- return QuiltModJsonFactory.createFromZip(zipPath); ++ if (ModMetadataHelper.isQuiltModWithQMJ5(zipPath)) { ++ return QuiltModJsonFactory.createFromZip(zipPath, QUILT_MOD_JSON5); ++ } else if (ModMetadataHelper.isQuiltMod(zipPath)) { ++ return QuiltModJsonFactory.createFromZip(zipPath, QUILT_MOD_JSON); + } else { + return FabricModJsonFactory.createFromZip(zipPath); + } + } + + public static ModJson createFromZipNullable(Path zipPath) { +- if (ModMetadataHelper.isQuiltMod(zipPath)) { +- return QuiltModJsonFactory.createFromZipNullable(zipPath); ++ if (ModMetadataHelper.isQuiltModWithQMJ5(zipPath)) { ++ return QuiltModJsonFactory.createFromZipNullable(zipPath, QUILT_MOD_JSON5); ++ } else if (ModMetadataHelper.isQuiltMod(zipPath)) { ++ return QuiltModJsonFactory.createFromZipNullable(zipPath, QUILT_MOD_JSON); + } else { + return FabricModJsonFactory.createFromZipNullable(zipPath); + } + } + + public static Optional createFromZipOptional(Path zipPath) { +- if (ModMetadataHelper.isQuiltMod(zipPath)) { +- return QuiltModJsonFactory.createFromZipOptional(zipPath); ++ if (ModMetadataHelper.isQuiltModWithQMJ5(zipPath)) { ++ return QuiltModJsonFactory.createFromZipOptional(zipPath, QUILT_MOD_JSON5); ++ } else if (ModMetadataHelper.isQuiltMod(zipPath)) { ++ return QuiltModJsonFactory.createFromZipOptional(zipPath, QUILT_MOD_JSON); + } else { + return FabricModJsonFactory.createFromZipOptional(zipPath); + } +@@ -65,10 +74,16 @@ public class ModJsonFactory { + + @Nullable + public static ModJson createFromSourceSetsNullable(SourceSet... sourceSets) throws IOException { +- File file = SourceSetHelper.findFirstFileInResource(ModMetadataHelper.QUILT_MOD_JSON, sourceSets); ++ File file = SourceSetHelper.findFirstFileInResource(ModMetadataHelper.QUILT_MOD_JSON5, sourceSets); ++ String qmj = QUILT_MOD_JSON5; ++ ++ if (file == null) { ++ file = SourceSetHelper.findFirstFileInResource(ModMetadataHelper.QUILT_MOD_JSON, sourceSets); ++ qmj = QUILT_MOD_JSON; ++ } + + if (file != null) { +- return QuiltModJsonFactory.createFromSourceSetsNullable(sourceSets); ++ return QuiltModJsonFactory.createFromSourceSetsNullable(qmj, sourceSets); + } else { + return FabricModJsonFactory.createFromSourceSetsNullable(sourceSets); + } +diff --git a/src/main/java/net/fabricmc/loom/util/qmj/QuiltModJsonFactory.java b/src/main/java/net/fabricmc/loom/util/qmj/QuiltModJsonFactory.java +index e179a45578d1ef12c15e06e387886ba32cac0f9f..c32507c09c3cac0c2e691041586f78bc0672d9f8 100644 +--- a/src/main/java/net/fabricmc/loom/util/qmj/QuiltModJsonFactory.java ++++ b/src/main/java/net/fabricmc/loom/util/qmj/QuiltModJsonFactory.java +@@ -39,6 +39,8 @@ import com.google.gson.JsonObject; + import org.gradle.api.tasks.SourceSet; + import org.jetbrains.annotations.Nullable; + import org.jetbrains.annotations.VisibleForTesting; ++import org.quiltmc.parsers.json.JsonReader; ++import org.quiltmc.parsers.json.gson.GsonReader; + + import net.fabricmc.loom.LoomGradlePlugin; + import net.fabricmc.loom.util.ZipUtils; +@@ -47,6 +49,7 @@ import net.fabricmc.loom.util.metadata.ModJsonSource; + + public final class QuiltModJsonFactory { + private static final String QUILT_MOD_JSON = "quilt.mod.json"; ++ private static final String QUILT_MOD_JSON5 = "quilt.mod.json5"; + + private QuiltModJsonFactory() { + } +@@ -66,20 +69,28 @@ public final class QuiltModJsonFactory { + }; + } + +- public static QuiltModJson createFromZip(Path zipPath) { ++ public static QuiltModJson createFromZip(Path zipPath, String qmj) { + try { +- return create(ZipUtils.unpackGson(zipPath, QUILT_MOD_JSON, JsonObject.class), new ModJsonSource.ZipSource(zipPath)); ++ if (qmj.equals(QUILT_MOD_JSON5)) { ++ return create(ZipUtils.unpackGsonWithJson5(zipPath, qmj, JsonObject.class), new ModJsonSource.ZipSource(zipPath)); ++ } ++ ++ return create(ZipUtils.unpackGson(zipPath, qmj, JsonObject.class), new ModJsonSource.ZipSource(zipPath)); + } catch (IOException e) { + throw new UncheckedIOException("Failed to read fabric.mod.json file in zip: " + zipPath, e); + } + } + + @Nullable +- public static QuiltModJson createFromZipNullable(Path zipPath) { ++ public static QuiltModJson createFromZipNullable(Path zipPath, String qmj) { + JsonObject jsonObject; + + try { +- jsonObject = ZipUtils.unpackGsonNullable(zipPath, QUILT_MOD_JSON, JsonObject.class); ++ if (qmj.equals(QUILT_MOD_JSON5)) { ++ jsonObject = ZipUtils.unpackGsonWithJson5Nullable(zipPath, qmj, JsonObject.class); ++ } else { ++ jsonObject = ZipUtils.unpackGsonNullable(zipPath, qmj, JsonObject.class); ++ } + } catch (IOException e) { + throw new UncheckedIOException("Failed to read zip: " + zipPath, e); + } +@@ -91,28 +102,40 @@ public final class QuiltModJsonFactory { + return create(jsonObject, new ModJsonSource.ZipSource(zipPath)); + } + +- public static Optional createFromZipOptional(Path zipPath) { +- return Optional.ofNullable(createFromZipNullable(zipPath)); ++ public static Optional createFromZipOptional(Path zipPath, String qmj) { ++ return Optional.ofNullable(createFromZipNullable(zipPath, qmj)); + } + +- public static QuiltModJson createFromDirectory(Path directory) throws IOException { +- final Path path = directory.resolve(QUILT_MOD_JSON); ++ public static QuiltModJson createFromDirectory(Path directory, String qmj) throws IOException { ++ final Path path = directory.resolve(qmj); + + try (Reader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) { +- return create(LoomGradlePlugin.GSON.fromJson(reader, JsonObject.class), new ModJsonSource.DirectorySource(directory)); ++ var jsonReader = LoomGradlePlugin.GSON.newJsonReader(reader); ++ ++ if (qmj.equals(QUILT_MOD_JSON5)) { ++ jsonReader = new GsonReader(JsonReader.json5(reader)); ++ } ++ ++ return create(LoomGradlePlugin.GSON.fromJson(jsonReader, JsonObject.class), new ModJsonSource.DirectorySource(directory)); + } + } + + @Nullable +- public static QuiltModJson createFromSourceSetsNullable(SourceSet... sourceSets) throws IOException { +- final File file = SourceSetHelper.findFirstFileInResource(QUILT_MOD_JSON, sourceSets); ++ public static QuiltModJson createFromSourceSetsNullable(String qmj, SourceSet... sourceSets) throws IOException { ++ final File file = SourceSetHelper.findFirstFileInResource(qmj, sourceSets); + + if (file == null) { + return null; + } + + try (Reader reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) { +- return create(LoomGradlePlugin.GSON.fromJson(reader, JsonObject.class), new ModJsonSource.SourceSetSource(sourceSets)); ++ var jsonReader = LoomGradlePlugin.GSON.newJsonReader(reader); ++ ++ if (qmj.equals(QUILT_MOD_JSON5)) { ++ jsonReader = new GsonReader(JsonReader.json5(reader)); ++ } ++ ++ return create(LoomGradlePlugin.GSON.fromJson(jsonReader, JsonObject.class), new ModJsonSource.SourceSetSource(sourceSets)); + } + } + }