mirror of
https://github.com/architectury/architectury-loom.git
synced 2026-03-28 04:07:01 -05:00
Add RemapJarTask.getOptimizeFabricModJson() (#1068)
* Optimise fabric.mod.json files * Fixes * Make opt-in * Revert * Fix
This commit is contained in:
@@ -47,7 +47,7 @@ public record SignatureFixesLayerImpl(Path mappingsFile) implements MappingLayer
|
||||
public Map<String, String> getSignatureFixes() {
|
||||
try {
|
||||
//noinspection unchecked
|
||||
return ZipUtils.unpackJackson(mappingsFile(), SIGNATURE_FIXES_PATH, Map.class);
|
||||
return ZipUtils.unpackJson(mappingsFile(), SIGNATURE_FIXES_PATH, Map.class);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to extract signature fixes", e);
|
||||
}
|
||||
|
||||
@@ -47,6 +47,6 @@ public record ParchmentMappingLayer(Path parchmentFile, boolean removePrefix) im
|
||||
}
|
||||
|
||||
private ParchmentTreeV1 getParchmentData() throws IOException {
|
||||
return ZipUtils.unpackJackson(parchmentFile, PARCHMENT_DATA_FILE_NAME, ParchmentTreeV1.class);
|
||||
return ZipUtils.unpackJson(parchmentFile, PARCHMENT_DATA_FILE_NAME, ParchmentTreeV1.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ import net.fabricmc.loom.util.SidedClassVisitor;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJson;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonUtils;
|
||||
import net.fabricmc.loom.util.service.BuildSharedServiceManager;
|
||||
import net.fabricmc.loom.util.service.UnsafeWorkQueueHelper;
|
||||
import net.fabricmc.tinyremapper.OutputConsumerPath;
|
||||
@@ -87,6 +88,14 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
@Input
|
||||
public abstract Property<Boolean> getAddNestedDependencies();
|
||||
|
||||
/**
|
||||
* Whether to optimize the fabric.mod.json file, by default this is false.
|
||||
*
|
||||
* <p>The schemaVersion entry will be placed first in the json file
|
||||
*/
|
||||
@Input
|
||||
public abstract Property<Boolean> getOptimizeFabricModJson();
|
||||
|
||||
@Input
|
||||
@ApiStatus.Internal
|
||||
public abstract Property<Boolean> getUseMixinAP();
|
||||
@@ -100,6 +109,7 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
final ConfigurationContainer configurations = getProject().getConfigurations();
|
||||
getClasspath().from(configurations.getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME));
|
||||
getAddNestedDependencies().convention(true).finalizeValueOnRead();
|
||||
getOptimizeFabricModJson().convention(false).finalizeValueOnRead();
|
||||
|
||||
Configuration includeConfiguration = configurations.getByName(Constants.Configurations.INCLUDE);
|
||||
getNestedJars().from(new IncludedJarFactory(getProject()).getNestedJars(includeConfiguration));
|
||||
@@ -156,6 +166,8 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
final var refmapRemapType = mixinAp ? ArtifactMetadata.MixinRemapType.MIXIN : ArtifactMetadata.MixinRemapType.STATIC;
|
||||
params.getManifestAttributes().put(Constants.Manifest.MIXIN_REMAP_TYPE, refmapRemapType.manifestValue());
|
||||
}
|
||||
|
||||
params.getOptimizeFmj().set(getOptimizeFabricModJson().get());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -197,6 +209,7 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
|
||||
Property<Boolean> getUseMixinExtension();
|
||||
Property<Boolean> getMultiProjectOptimisation();
|
||||
Property<Boolean> getOptimizeFmj();
|
||||
|
||||
record RefmapData(List<String> mixinConfigs, String refmapName) implements Serializable { }
|
||||
ListProperty<RefmapData> getMixinData();
|
||||
@@ -243,6 +256,10 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
modifyJarManifest();
|
||||
rewriteJar();
|
||||
|
||||
if (getParameters().getOptimizeFmj().get()) {
|
||||
optimizeFMJ();
|
||||
}
|
||||
|
||||
if (tinyRemapperService != null && !getParameters().getMultiProjectOptimisation().get()) {
|
||||
tinyRemapperService.close();
|
||||
}
|
||||
@@ -349,6 +366,14 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void optimizeFMJ() throws IOException {
|
||||
if (!ZipUtils.contains(outputFile, FabricModJsonFactory.FABRIC_MOD_JSON)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ZipUtils.transformJson(JsonObject.class, outputFile, FabricModJsonFactory.FABRIC_MOD_JSON, FabricModJsonUtils::optimizeFmj);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -121,7 +121,7 @@ public class ZipUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T unpackJackson(Path zip, String path, Class<T> clazz) throws IOException {
|
||||
public static <T> T unpackJson(Path zip, String path, Class<T> clazz) throws IOException {
|
||||
final byte[] bytes = unpack(zip, path);
|
||||
return LoomGradlePlugin.GSON.fromJson(new String(bytes, StandardCharsets.UTF_8), clazz);
|
||||
}
|
||||
@@ -209,6 +209,14 @@ public class ZipUtils {
|
||||
s -> LoomGradlePlugin.GSON.toJson(s, typeOfT).getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public static <T> void transformJson(Class<T> typeOfT, Path zip, String path, UnsafeUnaryOperator<T> transformer) throws IOException {
|
||||
int transformed = transformJson(typeOfT, zip, Map.of(path, transformer));
|
||||
|
||||
if (transformed != 1) {
|
||||
throw new IOException("Failed to transform " + path + " in " + zip);
|
||||
}
|
||||
}
|
||||
|
||||
public static int transform(Path zip, Collection<Pair<String, UnsafeUnaryOperator<byte[]>>> transforms) throws IOException {
|
||||
return transform(zip, transforms.stream());
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.gradle.SourceSetHelper;
|
||||
|
||||
public final class FabricModJsonFactory {
|
||||
private static final String FABRIC_MOD_JSON = "fabric.mod.json";
|
||||
public static final String FABRIC_MOD_JSON = "fabric.mod.json";
|
||||
|
||||
private FabricModJsonFactory() {
|
||||
}
|
||||
|
||||
@@ -25,13 +25,14 @@
|
||||
package net.fabricmc.loom.util.fmj;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
final class FabricModJsonUtils {
|
||||
public final class FabricModJsonUtils {
|
||||
private FabricModJsonUtils() {
|
||||
}
|
||||
|
||||
@@ -49,6 +50,30 @@ final class FabricModJsonUtils {
|
||||
return element.getAsInt();
|
||||
}
|
||||
|
||||
// Ensure that the schemaVersion json entry, is first in the json file
|
||||
// This exercises an optimisation here: https://github.com/FabricMC/fabric-loader/blob/d69cb72d26497e3f387cf46f9b24340b402a4644/src/main/java/net/fabricmc/loader/impl/metadata/ModMetadataParser.java#L62
|
||||
public static JsonObject optimizeFmj(JsonObject json) {
|
||||
if (!json.has("schemaVersion")) {
|
||||
// No schemaVersion, something will explode later?!
|
||||
return json;
|
||||
}
|
||||
|
||||
// Create a new json object with the schemaVersion first
|
||||
var out = new JsonObject();
|
||||
out.add("schemaVersion", json.get("schemaVersion"));
|
||||
|
||||
for (Map.Entry<String, JsonElement> entry : json.entrySet()) {
|
||||
if (entry.getKey().equals("schemaVersion")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add all other entries
|
||||
out.add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private static JsonElement getElement(JsonObject jsonObject, String key) {
|
||||
final JsonElement element = jsonObject.get(key);
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.Files
|
||||
import java.time.ZoneId
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import spock.lang.Specification
|
||||
|
||||
import net.fabricmc.loom.util.Checksum
|
||||
@@ -188,4 +189,28 @@ class ZipUtilsTest extends Specification {
|
||||
"Etc/GMT-6" | _
|
||||
"Etc/GMT+9" | _
|
||||
}
|
||||
|
||||
def "transform json"() {
|
||||
given:
|
||||
def dir = File.createTempDir()
|
||||
def zip = File.createTempFile("loom-zip-test", ".zip").toPath()
|
||||
new File(dir, "test.json").text = """
|
||||
{
|
||||
"test": "This is a test of transforming"
|
||||
}
|
||||
"""
|
||||
ZipUtils.pack(dir.toPath(), zip)
|
||||
|
||||
when:
|
||||
ZipUtils.transformJson(JsonObject.class, zip, "test.json") { json ->
|
||||
def test = json.get("test").getAsString()
|
||||
json.addProperty("test", test.toUpperCase())
|
||||
json
|
||||
}
|
||||
|
||||
def transformed = ZipUtils.unpackJson(zip, "test.json", JsonObject.class)
|
||||
|
||||
then:
|
||||
transformed.get("test").asString == "THIS IS A TEST OF TRANSFORMING"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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.test.unit.fmj
|
||||
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.JsonObject
|
||||
import org.intellij.lang.annotations.Language
|
||||
import spock.lang.Specification
|
||||
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonUtils
|
||||
|
||||
class FabricModJsonUtilsTest extends Specification {
|
||||
// Test that the schemaVersion is moved to the first position
|
||||
def "optimize FMJ"() {
|
||||
given:
|
||||
// Matches LoomGradlePlugin
|
||||
def gson = new GsonBuilder().setPrettyPrinting().create()
|
||||
def json = gson.fromJson(INPUT_FMJ, JsonObject.class)
|
||||
when:
|
||||
def outputJson = FabricModJsonUtils.optimizeFmj(json)
|
||||
def output = gson.toJson(outputJson)
|
||||
then:
|
||||
output == OUTPUT_FMJ
|
||||
true
|
||||
}
|
||||
|
||||
// schemaVersion is not first
|
||||
@Language("json")
|
||||
static String INPUT_FMJ = """
|
||||
{
|
||||
"id": "modid",
|
||||
"version": "1.0.0",
|
||||
"name": "Example mod",
|
||||
"description": "This is an example description! Tell everyone what your mod is about!",
|
||||
"license": "CC0-1.0",
|
||||
"icon": "assets/modid/icon.png",
|
||||
"environment": "*",
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"com.example.ExampleMod"
|
||||
],
|
||||
"client": [
|
||||
"com.example.ExampleModClient"
|
||||
]
|
||||
},
|
||||
"schemaVersion": 1,
|
||||
"mixins": [
|
||||
"modid.mixins.json",
|
||||
{
|
||||
"config": "modid.client.mixins.json",
|
||||
"environment": "client"
|
||||
}
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": "\\u003e\\u003d0.15.0",
|
||||
"minecraft": "~1.20.4",
|
||||
"java": "\\u003e\\u003d17",
|
||||
"fabric-api": "*"
|
||||
},
|
||||
"suggests": {
|
||||
"another-mod": "*"
|
||||
}
|
||||
}
|
||||
|
||||
""".trim()
|
||||
|
||||
// schemaVersion is first, everything else is unchanged
|
||||
@Language("json")
|
||||
static String OUTPUT_FMJ = """
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "modid",
|
||||
"version": "1.0.0",
|
||||
"name": "Example mod",
|
||||
"description": "This is an example description! Tell everyone what your mod is about!",
|
||||
"license": "CC0-1.0",
|
||||
"icon": "assets/modid/icon.png",
|
||||
"environment": "*",
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"com.example.ExampleMod"
|
||||
],
|
||||
"client": [
|
||||
"com.example.ExampleModClient"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
"modid.mixins.json",
|
||||
{
|
||||
"config": "modid.client.mixins.json",
|
||||
"environment": "client"
|
||||
}
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": "\\u003e\\u003d0.15.0",
|
||||
"minecraft": "~1.20.4",
|
||||
"java": "\\u003e\\u003d17",
|
||||
"fabric-api": "*"
|
||||
},
|
||||
"suggests": {
|
||||
"another-mod": "*"
|
||||
}
|
||||
}
|
||||
|
||||
""".trim()
|
||||
}
|
||||
Reference in New Issue
Block a user