From 6e3e1f3c64000c8290b389ab9f8e062e666c1c9f Mon Sep 17 00:00:00 2001 From: Brian Neumann-Fopiano Date: Tue, 8 Sep 2026 03:40:29 -0400 Subject: [PATCH] Single relocation declaration - Add gradle/runtime-relocations.gradle as the one runtime-download relocation map - Read the slimJar relocations and shrinkRelocations from that map - Pass the derived relocation prefixes into BukkitArtifactVerifier - Drop the duplicate jar size check the packaging audit already enforces --- build.gradle | 23 +++-------- .../src/main/java/BukkitArtifactVerifier.java | 36 +++++----------- .../test/java/BukkitArtifactVerifierTest.java | 41 +++++++++++-------- core/build.gradle | 19 +++------ gradle/runtime-relocations.gradle | 19 +++++++++ 5 files changed, 64 insertions(+), 74 deletions(-) create mode 100644 gradle/runtime-relocations.gradle diff --git a/build.gradle b/build.gradle index 4f11ede7f..5868f317d 100644 --- a/build.gradle +++ b/build.gradle @@ -49,6 +49,7 @@ plugins { } apply plugin: 'art.arcane.volmit-packaging' +apply from: file('gradle/runtime-relocations.gradle') group = 'art.arcane' version = providers.gradleProperty('irisVersion').getOrElse('4.1.0-26.2') @@ -87,8 +88,9 @@ String bukkitArtifactName = irisArtifactName('CraftBukkit', bukkitMinecraftRange String fabricArtifactName = irisArtifactName('Fabric', "${minecraftVersion}+${loaderDisplayVersion(fabricLoaderVersion)}") String forgeArtifactName = irisArtifactName('Forge', "${minecraftVersion}+${loaderDisplayVersion(forgeVersion)}") String neoForgeArtifactName = irisArtifactName('NeoForge', "${minecraftVersion}+${loaderDisplayVersion(neoForgeVersion)}") +Map runtimeDownloadRelocations = (Map) ext.runtimeDownloadRelocations +List runtimeDownloadedPrefixes = (List) ext.runtimeDownloadedPrefixes File pluginOutDirectory = layout.projectDirectory.dir('../PluginOuts').asFile -long maximumBukkitArtifactBytes = 7_600_000L apply plugin: ApiGenerator // Where `buildAll` drops the per-platform jars for a local test server. Use the approved sibling @@ -561,7 +563,7 @@ tasks.register('verifyBukkitArtifact') { artifact, requiredBukkitArtifactEntries, 16, - maximumBukkitArtifactBytes) + runtimeDownloadedPrefixes) logger.lifecycle("Verified ${artifact.name} packaging and class reference graph") } } @@ -757,22 +759,7 @@ pluginPackaging { shrinkLibraries.from(provider { project(':core').configurations.compileClasspath }) shrinkLibraries.from(provider { project(':adapters:bukkit:plugin').configurations.compileClasspath }) shrinkLibraries.from(provider { project(':adapters:bukkit:nms:v26_2_R1').configurations.compileClasspath }) - shrinkRelocations = [ - 'com.dfsek.paralithic': 'art.arcane.iris.util.paralithic', - 'com.google.gson': 'art.arcane.iris.util.gson', - 'com.googlecode.concurrentlinkedhashmap': 'art.arcane.iris.util.lru', - 'io.papermc.lib': 'art.arcane.iris.util.paper', - 'net.kyori': 'art.arcane.iris.util.kyori', - 'org.bstats': 'art.arcane.iris.util.metrics', - 'org.apache.maven': 'art.arcane.iris.util.maven', - 'org.codehaus.plexus': 'art.arcane.iris.util.plexus', - 'org.eclipse.sisu': 'art.arcane.iris.util.sisu', - 'org.eclipse.aether': 'art.arcane.iris.util.aether', - 'com.google.inject': 'art.arcane.iris.util.guice', - 'org.dom4j': 'art.arcane.iris.util.dom4j', - 'org.jaxen': 'art.arcane.iris.util.jaxen', - 'com.github.benmanes.caffeine': 'art.arcane.iris.util.caffeine' - ] + shrinkRelocations = runtimeDownloadRelocations } } } diff --git a/buildSrc/src/main/java/BukkitArtifactVerifier.java b/buildSrc/src/main/java/BukkitArtifactVerifier.java index 8d4503923..9eeaaa5cb 100644 --- a/buildSrc/src/main/java/BukkitArtifactVerifier.java +++ b/buildSrc/src/main/java/BukkitArtifactVerifier.java @@ -3,6 +3,7 @@ import org.gradle.api.GradleException; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.util.Collection; import java.util.Enumeration; import java.util.LinkedHashSet; import java.util.List; @@ -23,39 +24,24 @@ public final class BukkitArtifactVerifier { "art/arcane/iris/", "art/arcane/volmlib/" ); - // Relocation targets for the libraries slimjar downloads and relocates at runtime. Compiled - // references to them are correct and the classes are correctly absent from the jar. - private static final List RUNTIME_DOWNLOADED_PREFIXES = List.of( - "art/arcane/iris/util/paper/", - "art/arcane/iris/util/kyori/", - "art/arcane/iris/util/metrics/", - "art/arcane/iris/util/maven/", - "art/arcane/iris/util/plexus/", - "art/arcane/iris/util/sisu/", - "art/arcane/iris/util/aether/", - "art/arcane/iris/util/guice/", - "art/arcane/iris/util/dom4j/", - "art/arcane/iris/util/jaxen/", - "art/arcane/iris/util/gson/", - "art/arcane/iris/util/lru/", - "art/arcane/iris/util/caffeine/", - "art/arcane/iris/util/paralithic/" - ); private static final String MATTER_SLICE_PACKAGE = "art/arcane/volmlib/util/matter/slices/"; private static final String LANGUAGE_DIRECTORY = "languages/"; private BukkitArtifactVerifier() { } + /** + * @param runtimeDownloadedPrefixes relocation targets for the libraries slimjar downloads and + * relocates at runtime, derived from the single relocation + * declaration in gradle/runtime-relocations.gradle. Compiled + * references to them are correct and the classes are correctly + * absent from the jar. + */ public static void verify(File artifact, List requiredEntries, - int minimumMatterSlices, long maximumArtifactBytes) { + int minimumMatterSlices, Collection runtimeDownloadedPrefixes) { if (!artifact.isFile()) { throw new GradleException("Missing Bukkit Iris artifact: " + artifact.getAbsolutePath()); } - if (artifact.length() > maximumArtifactBytes) { - throw new GradleException(artifact.getName() + " is " + artifact.length() - + " bytes; Bukkit artifacts must not exceed " + maximumArtifactBytes + " bytes"); - } try (JarFile jar = new JarFile(artifact)) { for (String requiredEntry : requiredEntries) { @@ -113,7 +99,7 @@ public final class BukkitArtifactVerifier { for (String reference : ClassReferences.read(readEntryBytes(jar, entry))) { if (shippedClasses.contains(reference) || !startsWithAny(reference, SHIPPED_PREFIXES) - || startsWithAny(reference, RUNTIME_DOWNLOADED_PREFIXES)) { + || startsWithAny(reference, runtimeDownloadedPrefixes)) { continue; } dangling.putIfAbsent(reference, entry.getName()); @@ -145,7 +131,7 @@ public final class BukkitArtifactVerifier { } } - private static boolean startsWithAny(String value, List prefixes) { + private static boolean startsWithAny(String value, Collection prefixes) { for (String prefix : prefixes) { if (value.startsWith(prefix)) { return true; diff --git a/buildSrc/src/test/java/BukkitArtifactVerifierTest.java b/buildSrc/src/test/java/BukkitArtifactVerifierTest.java index c92ebacae..24937d861 100644 --- a/buildSrc/src/test/java/BukkitArtifactVerifierTest.java +++ b/buildSrc/src/test/java/BukkitArtifactVerifierTest.java @@ -30,6 +30,13 @@ public class BukkitArtifactVerifierTest { NMS_BINDING + ".class" ); private static final int MATTER_SLICES = 1; + private static final List RUNTIME_DOWNLOADED_PREFIXES = List.of( + "art/arcane/iris/util/kyori/", + "art/arcane/iris/util/gson/", + "art/arcane/iris/util/lru/", + "art/arcane/iris/util/caffeine/", + "art/arcane/iris/util/paralithic/" + ); @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -38,7 +45,7 @@ public class BukkitArtifactVerifierTest { public void acceptsCompleteArtifact() throws Exception { File artifact = createArtifact(validEntries()); - BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, Long.MAX_VALUE); + BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, RUNTIME_DOWNLOADED_PREFIXES); } @Test @@ -48,7 +55,7 @@ public class BukkitArtifactVerifierTest { File artifact = createArtifact(entries); GradleException failure = assertThrows(GradleException.class, - () -> BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, Long.MAX_VALUE)); + () -> BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, RUNTIME_DOWNLOADED_PREFIXES)); assertTrue(failure.getMessage().contains(PLUGIN_DESCRIPTOR)); } @@ -59,7 +66,7 @@ public class BukkitArtifactVerifierTest { File artifact = createArtifact(entries); GradleException failure = assertThrows(GradleException.class, - () -> BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, Long.MAX_VALUE)); + () -> BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, RUNTIME_DOWNLOADED_PREFIXES)); assertTrue(failure.getMessage().contains(SLIMJAR_DEPENDENCIES)); } @@ -70,7 +77,7 @@ public class BukkitArtifactVerifierTest { File artifact = createArtifact(entries); GradleException failure = assertThrows(GradleException.class, - () -> BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, Long.MAX_VALUE)); + () -> BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, RUNTIME_DOWNLOADED_PREFIXES)); assertTrue(failure.getMessage().contains(SLIMJAR_RESOLUTIONS)); } @@ -81,7 +88,7 @@ public class BukkitArtifactVerifierTest { File artifact = createArtifact(entries); GradleException failure = assertThrows(GradleException.class, - () -> BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, Long.MAX_VALUE)); + () -> BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, RUNTIME_DOWNLOADED_PREFIXES)); assertTrue(failure.getMessage().contains("art/arcane/volmlib/util/noise/CNG")); } @@ -100,20 +107,20 @@ public class BukkitArtifactVerifierTest { classReferencing("art/arcane/iris/ParalithicConsumer", "art/arcane/iris/util/paralithic/functions/Function")); File artifact = createArtifact(entries); - BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, Long.MAX_VALUE); + BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, RUNTIME_DOWNLOADED_PREFIXES); } @Test - public void rejectsArtifactAboveConfiguredSize() throws Exception { - File artifact = createArtifact(validEntries()); + public void rejectsReferenceOutsideRuntimeDownloadedPrefixes() throws Exception { + Map entries = validEntries(); + entries.put("art/arcane/iris/PaperConsumer.class", + classReferencing("art/arcane/iris/PaperConsumer", "art/arcane/iris/util/paper/PaperLib")); + File artifact = createArtifact(entries); GradleException failure = assertThrows(GradleException.class, - () -> BukkitArtifactVerifier.verify( - artifact, - REQUIRED_ENTRIES, - MATTER_SLICES, - artifact.length() - 1L)); - assertTrue(failure.getMessage().contains("must not exceed")); + () -> BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, + RUNTIME_DOWNLOADED_PREFIXES)); + assertTrue(failure.getMessage().contains("art/arcane/iris/util/paper/PaperLib")); } @Test @@ -123,7 +130,7 @@ public class BukkitArtifactVerifierTest { File artifact = createArtifact(entries); GradleException failure = assertThrows(GradleException.class, - () -> BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, Long.MAX_VALUE)); + () -> BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, RUNTIME_DOWNLOADED_PREFIXES)); assertTrue(failure.getMessage().contains("locale files")); } @@ -134,7 +141,7 @@ public class BukkitArtifactVerifierTest { File artifact = createArtifact(entries); GradleException failure = assertThrows(GradleException.class, - () -> BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, Long.MAX_VALUE)); + () -> BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, RUNTIME_DOWNLOADED_PREFIXES)); assertTrue(failure.getMessage().contains("Matter slice types")); } @@ -145,7 +152,7 @@ public class BukkitArtifactVerifierTest { classAnnotatedWith("art/arcane/iris/Annotated", "com/google/errorprone/annotations/CanIgnoreReturnValue")); File artifact = createArtifact(entries); - BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, Long.MAX_VALUE); + BukkitArtifactVerifier.verify(artifact, REQUIRED_ENTRIES, MATTER_SLICES, RUNTIME_DOWNLOADED_PREFIXES); } private Map validEntries() { diff --git a/core/build.gradle b/core/build.gradle index 299588439..2ba42ad7b 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -33,6 +33,8 @@ plugins { alias(libs.plugins.slimjar) } +apply from: rootProject.file('gradle/runtime-relocations.gradle') + def lib = 'art.arcane.iris.util' String volmLibCoordinate = providers.gradleProperty('volmLibCoordinate') .orElse('com.github.VolmitSoftware:VolmLib:master-SNAPSHOT') @@ -158,20 +160,9 @@ slimJar { ) ] - relocate('com.dfsek.paralithic', "${lib}.paralithic") - relocate('com.google.gson', "${lib}.gson") - relocate('com.googlecode.concurrentlinkedhashmap', "${lib}.lru") - relocate('io.papermc.lib', "${lib}.paper") - relocate('net.kyori', "${lib}.kyori") - relocate('org.bstats', "${lib}.metrics") - relocate('org.apache.maven', "${lib}.maven") - relocate('org.codehaus.plexus', "${lib}.plexus") - relocate('org.eclipse.sisu', "${lib}.sisu") - relocate('org.eclipse.aether', "${lib}.aether") - relocate('com.google.inject', "${lib}.guice") - relocate('org.dom4j', "${lib}.dom4j") - relocate('org.jaxen', "${lib}.jaxen") - relocate('com.github.benmanes.caffeine', "${lib}.caffeine") + for (Map.Entry relocation : runtimeDownloadRelocations.entrySet()) { + relocate(relocation.getKey(), relocation.getValue()) + } } def embeddedAgentJar = project(':core:agent').tasks.named('jar', Jar) diff --git a/gradle/runtime-relocations.gradle b/gradle/runtime-relocations.gradle new file mode 100644 index 000000000..3e2e4db04 --- /dev/null +++ b/gradle/runtime-relocations.gradle @@ -0,0 +1,19 @@ +ext.runtimeDownloadRelocations = [ + 'com.dfsek.paralithic' : 'art.arcane.iris.util.paralithic', + 'com.google.gson' : 'art.arcane.iris.util.gson', + 'com.googlecode.concurrentlinkedhashmap': 'art.arcane.iris.util.lru', + 'io.papermc.lib' : 'art.arcane.iris.util.paper', + 'net.kyori' : 'art.arcane.iris.util.kyori', + 'org.bstats' : 'art.arcane.iris.util.metrics', + 'org.apache.maven' : 'art.arcane.iris.util.maven', + 'org.codehaus.plexus' : 'art.arcane.iris.util.plexus', + 'org.eclipse.sisu' : 'art.arcane.iris.util.sisu', + 'org.eclipse.aether' : 'art.arcane.iris.util.aether', + 'com.google.inject' : 'art.arcane.iris.util.guice', + 'org.dom4j' : 'art.arcane.iris.util.dom4j', + 'org.jaxen' : 'art.arcane.iris.util.jaxen', + 'com.github.benmanes.caffeine' : 'art.arcane.iris.util.caffeine' +] as LinkedHashMap + +ext.runtimeDownloadedPrefixes = ext.runtimeDownloadRelocations.values() + .collect { String target -> target.replace('.', '/') + '/' } as List