diff --git a/build.gradle.kts b/build.gradle.kts index 8e5eb61..7df49d9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -70,10 +70,6 @@ dependencies { testImplementation(kotlin("test")) } -tasks.test { - useJUnitPlatform() -} - tasks.jar { from(shared.output) @@ -126,6 +122,11 @@ val agentShadeJar = tasks.register("agentShadowJar") { } } +tasks.test { + useJUnitPlatform() + dependsOn(tasks.jar, annotationJar, agentShadeJar) +} + tasks.assemble { dependsOn(annotationJar) dependsOn(agentShadeJar) diff --git a/expect-platform-test/build.gradle.kts b/expect-platform-test/build.gradle.kts index 0457b18..d6c44bd 100644 --- a/expect-platform-test/build.gradle.kts +++ b/expect-platform-test/build.gradle.kts @@ -1,8 +1,11 @@ @file:Suppress("DSL_SCOPE_VIOLATION") import xyz.wagyourtail.unimined.expect.task.ExpectPlatformFiles import xyz.wagyourtail.unimined.expect.task.ExpectPlatformJar -import xyz.wagyourtail.unimined.expect.ExpectPlatformExtension -import java.util.* +import xyz.wagyourtail.unimined.expect.expectPlatform + +val epVersion = projectDir.parentFile.resolve("gradle.properties").readText() + .split("\n").find { it.startsWith("version") }!! + .split("=").last().trimStart() buildscript { repositories { @@ -12,9 +15,11 @@ buildscript { } } dependencies { - if (!project.hasProperty("runningTest")) { - classpath("xyz.wagyourtail.unimined.expect-platform:expect-platform:1.0.3") + val epVersion = projectDir.parentFile.resolve("gradle.properties").readText() + .split("\n").find { it.startsWith("version") }!! + .split("=").last().trimStart() + classpath("xyz.wagyourtail.unimined.expect-platform:expect-platform:${epVersion}") classpath("org.ow2.asm:asm:9.7") classpath("org.ow2.asm:asm-commons:9.7") classpath("org.ow2.asm:asm-tree:9.7") @@ -25,9 +30,7 @@ buildscript { plugins { java if (project.hasProperty("runningTest")) { - plugins { - id("xyz.wagyourtail.unimined.expect-platform") - } + id("xyz.wagyourtail.unimined.expect-platform") } } @@ -35,7 +38,6 @@ plugins { apply(plugin = "xyz.wagyourtail.unimined.expect-platform") - sourceSets { create("a") { compileClasspath += sourceSets.main.get().output @@ -54,13 +56,9 @@ repositories { } } -val expectPlatform = project.extensions.getByType(ExpectPlatformExtension::class) -expectPlatform.version = run { - projectDir.parentFile.resolve("gradle.properties").inputStream().use { - val props = Properties() - props.load(it) - props.getProperty("version") as String - } +project.expectPlatform { + version = epVersion + stripAnnotations = true } dependencies { @@ -81,6 +79,7 @@ val aExpectPlatform by tasks.registering(ExpectPlatformFiles::class) { val bExpectPlatform by tasks.registering(ExpectPlatformFiles::class) { platformName = "b" inputCollection = sourceSets.main.get().output + stripAnnotations = false remap = mapOf( "xyz/wagyourtail/unimined/expect/annotation/Environment" to "xyz/wagyourtail/ept/b/OnlyIn", @@ -100,21 +99,21 @@ val cExpectPlatform by tasks.registering(ExpectPlatformFiles::class) { ) } -tasks.register("runA", JavaExec::class) { +tasks.register("runA") { dependsOn(aExpectPlatform) classpath = sourceSets["a"].runtimeClasspath + aExpectPlatform.get().outputCollection mainClass = "xyz.wagyourtail.ept.Main" group = "ept" } -tasks.register("runB", JavaExec::class) { +tasks.register("runB") { dependsOn(bExpectPlatform) classpath = sourceSets["b"].runtimeClasspath + bExpectPlatform.get().outputCollection mainClass = "xyz.wagyourtail.ept.Main" group = "ept" } -tasks.register("runC", JavaExec::class) { +tasks.register("runC") { dependsOn(cExpectPlatform) classpath = sourceSets["c"].runtimeClasspath + cExpectPlatform.get().outputCollection mainClass = "xyz.wagyourtail.ept.Main" @@ -175,6 +174,7 @@ val jarB by tasks.registering(ExpectPlatformJar::class) { inputFiles = sourceSets.main.get().output from(sourceSets["b"].output) archiveFileName = "b.jar" + stripAnnotations = false remap = mapOf( "xyz/wagyourtail/unimined/expect/annotation/Environment" to "xyz/wagyourtail/ept/b/OnlyIn", diff --git a/gradle.properties b/gradle.properties index e0e2c0e..3461615 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ kotlin.code.style=official -version = 1.0.5 +version = 1.1.0 asmVersion=9.7 diff --git a/src/agent/java/xyz/wagyourtail/unimined/expect/ExpectPlatformAgent.java b/src/agent/java/xyz/wagyourtail/unimined/expect/ExpectPlatformAgent.java index a47b009..3169aa6 100644 --- a/src/agent/java/xyz/wagyourtail/unimined/expect/ExpectPlatformAgent.java +++ b/src/agent/java/xyz/wagyourtail/unimined/expect/ExpectPlatformAgent.java @@ -14,14 +14,20 @@ public class ExpectPlatformAgent { private static final String platform = System.getProperty(EXPECT_PLATFORM); private static final String remap = System.getProperty(REMAP); - private static final TransformPlatform transformPlatform = new TransformPlatform(platform, remap); + private static final TransformPlatform transformPlatform = new TransformPlatform(platform, remap, false); public static void premain(String args, Instrumentation inst) { - System.out.println("[ExpectPlatformAgent] Platform: " + platform); - System.out.println("[ExpectPlatformAgent] Remap: " + transformPlatform.getRemap()); if (platform == null) { throw new IllegalStateException("-D" + EXPECT_PLATFORM + " not set"); } + + if(!inst.isRetransformClassesSupported()) { + System.out.println("[ExpectPlatformAgent] ur instrumentation is bad lol"); + } + + System.out.println("[ExpectPlatformAgent] Platform: " + platform); + System.out.println("[ExpectPlatformAgent] Remap: " + transformPlatform.getRemap()); + inst.addTransformer(new ExpectPlatformTransformer(), inst.isRetransformClassesSupported()); } @@ -33,6 +39,7 @@ public static class ExpectPlatformTransformer implements ClassFileTransformer { @Override public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { + System.out.println("[ExpectPlatformAgent] Transforming: " + className); ClassReader reader = new ClassReader(classfileBuffer); ClassNode classNode = new ClassNode(); reader.accept(classNode, 0); diff --git a/src/annotations/java/xyz/wagyourtail/unimined/expect/Target.java b/src/annotations/java/xyz/wagyourtail/unimined/expect/Target.java index 6429886..bb7029e 100644 --- a/src/annotations/java/xyz/wagyourtail/unimined/expect/Target.java +++ b/src/annotations/java/xyz/wagyourtail/unimined/expect/Target.java @@ -8,6 +8,6 @@ private Target() { * @return the currently targeted platform */ public static String getCurrentTarget() { - throw new AssertionError("failed to transform method"); + throw new AssertionError("stub method, this shouldn't even be on your runtime classpath!"); } } diff --git a/src/annotations/java/xyz/wagyourtail/unimined/expect/annotation/PlatformOnly.java b/src/annotations/java/xyz/wagyourtail/unimined/expect/annotation/PlatformOnly.java index 70c887d..e7dd1f8 100644 --- a/src/annotations/java/xyz/wagyourtail/unimined/expect/annotation/PlatformOnly.java +++ b/src/annotations/java/xyz/wagyourtail/unimined/expect/annotation/PlatformOnly.java @@ -14,6 +14,7 @@ String[] value(); String FORGE = "forge"; + String NEOFORGE = "neoforge"; String FABRIC = "fabric"; String QUIILT = "quilt"; } diff --git a/src/main/kotlin/xyz/wagyourtail/unimined/expect/ExpectPlatformExtension.kt b/src/main/kotlin/xyz/wagyourtail/unimined/expect/ExpectPlatformExtension.kt index 2f72f02..1862814 100644 --- a/src/main/kotlin/xyz/wagyourtail/unimined/expect/ExpectPlatformExtension.kt +++ b/src/main/kotlin/xyz/wagyourtail/unimined/expect/ExpectPlatformExtension.kt @@ -9,6 +9,11 @@ import org.gradle.process.JavaExecSpec import org.jetbrains.annotations.VisibleForTesting import xyz.wagyourtail.unimined.expect.transform.ExpectPlatformParams import xyz.wagyourtail.unimined.expect.transform.ExpectPlatformTransform +import xyz.wagyourtail.unimined.expect.utils.FinalizeOnRead +import java.io.File + +val Project.expectPlatform: ExpectPlatformExtension + get() = extensions.getByType(ExpectPlatformExtension::class.java) abstract class ExpectPlatformExtension(val project: Project) { @@ -18,6 +23,8 @@ abstract class ExpectPlatformExtension(val project: Project) { val annotationsDep by lazy { "xyz.wagyourtail.unimined.expect-platform:expect-platform-annotations:$version" } val agentDep by lazy { "xyz.wagyourtail.unimined.expect-platform:expect-platform-agent:$version" } + var stripAnnotations by FinalizeOnRead(false) + @JvmOverloads fun platform(platformName: String, configuration: Configuration, action: ExpectPlatformParams.() -> Unit = {}) { val expectPlatformAttribute = Attribute.of("expectPlatform.${configuration.name}", Boolean::class.javaObjectType) @@ -40,6 +47,7 @@ abstract class ExpectPlatformExtension(val project: Project) { spec.parameters { it.platformName.set(platformName) + it.stripAnnotations.convention(stripAnnotations) it.action() } } @@ -67,12 +75,20 @@ abstract class ExpectPlatformExtension(val project: Project) { @JvmOverloads fun insertAgent(spec: JavaExecSpec, platformName: String, remap: Map = emptyMap()) { - spec.jvmArgs("-javaagent:${agentJar.absolutePath}", "-Dexpect.platform=${platformName}", "-Dexpect.remap=${TransformPlatform.mapToString(remap)}") + spec.jvmArgs( + "-javaagent:${agentJar.absolutePath}", + "-Dexpect.platform=${platformName}", + "-Dexpect.remap=${TransformPlatform.mapToString(remap)}" + ) } - val agentJar by lazy { + val agentJar: File by lazy { val config = project.configurations.detachedConfiguration(project.dependencies.create(agentDep)) config.resolve().first { it.extension == "jar" } } + operator fun invoke(action: ExpectPlatformExtension.() -> Unit) { + action(this) + } + } \ No newline at end of file diff --git a/src/main/kotlin/xyz/wagyourtail/unimined/expect/task/ExpectPlatformFiles.kt b/src/main/kotlin/xyz/wagyourtail/unimined/expect/task/ExpectPlatformFiles.kt index 73a2c28..ac2e814 100644 --- a/src/main/kotlin/xyz/wagyourtail/unimined/expect/task/ExpectPlatformFiles.kt +++ b/src/main/kotlin/xyz/wagyourtail/unimined/expect/task/ExpectPlatformFiles.kt @@ -7,8 +7,8 @@ import org.gradle.api.tasks.Internal import org.gradle.api.tasks.TaskAction import xyz.wagyourtail.unimined.expect.utils.FinalizeOnRead import xyz.wagyourtail.unimined.expect.utils.MustSet -import xyz.wagyourtail.unimined.expect.ExpectPlatformExtension import xyz.wagyourtail.unimined.expect.TransformPlatform +import xyz.wagyourtail.unimined.expect.expectPlatform import xyz.wagyourtail.unimined.expect.transform.ExpectPlatformParams import xyz.wagyourtail.unimined.expect.utils.openZipFileSystem import java.io.File @@ -19,11 +19,6 @@ import kotlin.io.path.name abstract class ExpectPlatformFiles : ConventionTask(), ExpectPlatformParams { - @get:Internal - protected val ep by lazy { - project.extensions.getByType(ExpectPlatformExtension::class.java) - } - @get:InputFiles var inputCollection: FileCollection by FinalizeOnRead(MustSet()) @@ -46,13 +41,12 @@ abstract class ExpectPlatformFiles : ConventionTask(), ExpectPlatformParams { } @TaskAction - fun doTranform() { + fun doTransform() { var toTransform = inputCollection.map { it.toPath() }.filter { it.exists() } val fileSystems = mutableSetOf() try { - outputs.files.forEach { it.deleteRecursively() } val transformed = toTransform.map { temporaryDir.resolve(it.name) }.map { @@ -70,10 +64,13 @@ abstract class ExpectPlatformFiles : ConventionTask(), ExpectPlatformParams { fs.getPath("/") } } + + val transformer = TransformPlatform(platformName.get(), remap.get(), stripAnnotations.getOrElse(project.expectPlatform.stripAnnotations)) + for (i in toTransform.indices) { val input = toTransform[i] val output = transformed[i] - TransformPlatform(platformName.get(), remap.get()).transform(input, output) + transformer.transform(input, output) } } finally { fileSystems.forEach { it.close() } diff --git a/src/main/kotlin/xyz/wagyourtail/unimined/expect/task/ExpectPlatformJar.kt b/src/main/kotlin/xyz/wagyourtail/unimined/expect/task/ExpectPlatformJar.kt index 27a52cf..23edff8 100644 --- a/src/main/kotlin/xyz/wagyourtail/unimined/expect/task/ExpectPlatformJar.kt +++ b/src/main/kotlin/xyz/wagyourtail/unimined/expect/task/ExpectPlatformJar.kt @@ -5,44 +5,37 @@ package xyz.wagyourtail.unimined.expect.task import org.gradle.api.file.FileCollection import org.gradle.api.tasks.InputFiles import org.gradle.api.tasks.TaskAction -import org.gradle.jvm.tasks.Jar +import org.gradle.api.tasks.bundling.Jar import xyz.wagyourtail.unimined.expect.utils.FinalizeOnRead import xyz.wagyourtail.unimined.expect.utils.MustSet -import xyz.wagyourtail.unimined.expect.ExpectPlatformExtension import xyz.wagyourtail.unimined.expect.TransformPlatform +import xyz.wagyourtail.unimined.expect.expectPlatform import xyz.wagyourtail.unimined.expect.transform.ExpectPlatformParams import xyz.wagyourtail.unimined.expect.utils.openZipFileSystem abstract class ExpectPlatformJar : Jar(), ExpectPlatformParams { - private val ep by lazy { - project.extensions.getByType(ExpectPlatformExtension::class.java) - } - @get:InputFiles var inputFiles: FileCollection by FinalizeOnRead(MustSet()) @TaskAction fun doTransform() { + val transformer = TransformPlatform(platformName.get(), remap.get(), stripAnnotations.getOrElse(project.expectPlatform.stripAnnotations)) for (input in inputFiles) { if (input.isDirectory) { val output = temporaryDir.resolve(input.name + "-expect-platform") - TransformPlatform(platformName.get(), remap.get()).transform(input.toPath(), output.toPath()) + transformer.transform(input.toPath(), output.toPath()) from(output) } else if (input.extension == "jar") { val output = temporaryDir.resolve(input.nameWithoutExtension + "-expect-platform." + input.extension) input.toPath().openZipFileSystem().use { inputFs -> output.toPath().openZipFileSystem(mapOf("create" to true)).use { outputFs -> - TransformPlatform(platformName.get(), remap.get()).transform( - inputFs.getPath("/"), - outputFs.getPath("/") - ) + transformer.transform(inputFs.getPath("/"), outputFs.getPath("/")) } } from(project.zipTree(output)) } else if (input.exists()) { throw IllegalStateException("ExpectPlatformJar: $input is not a directory or jar file") - } } diff --git a/src/main/kotlin/xyz/wagyourtail/unimined/expect/transform/ExpectPlatformParams.kt b/src/main/kotlin/xyz/wagyourtail/unimined/expect/transform/ExpectPlatformParams.kt index fd31b5b..79f9e43 100644 --- a/src/main/kotlin/xyz/wagyourtail/unimined/expect/transform/ExpectPlatformParams.kt +++ b/src/main/kotlin/xyz/wagyourtail/unimined/expect/transform/ExpectPlatformParams.kt @@ -19,4 +19,8 @@ interface ExpectPlatformParams : TransformParameters { @get:Optional val remap: MapProperty + @get:Input + @get:Optional + val stripAnnotations: Property + } \ No newline at end of file diff --git a/src/main/kotlin/xyz/wagyourtail/unimined/expect/transform/ExpectPlatformTransform.kt b/src/main/kotlin/xyz/wagyourtail/unimined/expect/transform/ExpectPlatformTransform.kt index e03a908..da96a0f 100644 --- a/src/main/kotlin/xyz/wagyourtail/unimined/expect/transform/ExpectPlatformTransform.kt +++ b/src/main/kotlin/xyz/wagyourtail/unimined/expect/transform/ExpectPlatformTransform.kt @@ -16,15 +16,17 @@ abstract class ExpectPlatformTransform : TransformAction { override fun transform(outputs: TransformOutputs) { val platformName = parameters.platformName.get() val remap = parameters.remap.get() + val transformer = TransformPlatform(platformName, remap, parameters.stripAnnotations.get()) + val input = inputArtifact.get().asFile if (input.isDirectory) { val output = outputs.dir(input.name + "-expect-platform") - TransformPlatform(platformName, remap).transform(input.toPath(), output.toPath()) + transformer.transform(input.toPath(), output.toPath()) } else if (input.extension == "jar") { val output = outputs.file(input.nameWithoutExtension + "-expect-platform." + input.extension) input.toPath().openZipFileSystem().use { inputFs -> output.toPath().openZipFileSystem(mapOf("create" to true)).use { outputFs -> - TransformPlatform(platformName, remap).transform(inputFs.getPath("/"), outputFs.getPath("/")) + transformer.transform(inputFs.getPath("/"), outputFs.getPath("/")) } } } else { diff --git a/src/shared/java/xyz/wagyourtail/unimined/expect/TransformPlatform.java b/src/shared/java/xyz/wagyourtail/unimined/expect/TransformPlatform.java index e80e868..727b5e1 100644 --- a/src/shared/java/xyz/wagyourtail/unimined/expect/TransformPlatform.java +++ b/src/shared/java/xyz/wagyourtail/unimined/expect/TransformPlatform.java @@ -17,16 +17,26 @@ public class TransformPlatform { private static final int EXPECT_PLATFORM_ACCESS = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC; + private static final String EXPECT_PLATFORM_DESC = "Lxyz/wagyourtail/unimined/expect/annotation/ExpectPlatform;"; + private static final String EXPECT_PLATFORM_TRANSFORMED_DESC = "Lxyz/wagyourtail/unimined/expect/annotation/ExpectPlatform$Transformed"; + private static final String PLATFORM_ONLY_DESC = "Lxyz/wagyourtail/unimined/expect/annotation/PlatformOnly;"; + private static final String TARGET_CLASS = "xyz/wagyourtail/unimined/expect/Target"; + private static final String TARGET_METHOD = "getCurrentTarget"; + + private final String platformName; + private final boolean stripAnnotations; private final Map remap = new HashMap<>(); - public TransformPlatform(String platformName, String map) { + public TransformPlatform(String platformName, String map, boolean stripAnnotations) { this.platformName = platformName; + this.stripAnnotations = stripAnnotations; stringMapParser(map); } - public TransformPlatform(String platformName, Map map) { + public TransformPlatform(String platformName, Map map, boolean stripAnnotations) { this.platformName = platformName; + this.stripAnnotations = stripAnnotations; remap.putAll(map); } @@ -80,20 +90,30 @@ public ClassNode transform(ClassNode classNode) { for (MethodNode method : classNode.methods) { if (method.invisibleAnnotations == null) continue; for (AnnotationNode annotation : method.invisibleAnnotations) { - if (annotation.desc.equals("Lxyz/wagyourtail/unimined/expect/annotation/ExpectPlatform;")) { + if (annotation.desc.equals(EXPECT_PLATFORM_DESC)) { expectPlatform.put(method, annotation); - } else if (annotation.desc.equals("Lxyz/wagyourtail/unimined/expect/annotation/PlatformOnly;")) { + } else if (annotation.desc.equals(PLATFORM_ONLY_DESC)) { platformOnly.put(method, annotation); } } } for (Map.Entry entry : expectPlatform.entrySet()) { - expectPlatform(entry.getKey(), classNode, entry.getValue()); + MethodNode method = entry.getKey(); + AnnotationNode annotation = entry.getValue(); + expectPlatform(method, classNode, annotation); + if (stripAnnotations) { + method.invisibleAnnotations.remove(annotation); + } } for (Map.Entry entry : platformOnly.entrySet()) { - platformOnly(entry.getKey(), classNode, entry.getValue()); + MethodNode method = entry.getKey(); + AnnotationNode annotation = entry.getValue(); + platformOnly(method, classNode, annotation); + if (stripAnnotations) { + method.invisibleAnnotations.remove(annotation); + } } getCurrentTarget(classNode); @@ -106,7 +126,6 @@ private void expectPlatform(MethodNode methodNode, ClassNode classNode, Annotati throw new RuntimeException("ExpectPlatform methods must be public and static"); } - String platformClass = null; List platforms = getAnnotationValue(annotationNode, "platforms"); if (platforms != null) { @@ -130,13 +149,8 @@ private void expectPlatform(MethodNode methodNode, ClassNode classNode, Annotati } if (platformClass == null) { int lastSlash = classNode.name.lastIndexOf('/'); - String pkg; - if (lastSlash == -1) { - pkg = ""; - } else { - pkg = classNode.name.substring(0, lastSlash); - } - String className = classNode.name.substring(lastSlash + 1); + String pkg = lastSlash == -1 ? "" : classNode.name.substring(0, lastSlash); + String className = classNode.name.substring(lastSlash + 1); if (pkg.isEmpty()) { platformClass = platformName + "/" + className + "Impl"; } else { @@ -167,6 +181,10 @@ private void expectPlatform(MethodNode methodNode, ClassNode classNode, Annotati // recalculate proper maxStack and maxLocals manually so we don't have to recompute anything methodNode.maxStack = Math.max(type.getReturnType().getSize(), stackIndex); methodNode.maxLocals = stackIndex; + + if(!stripAnnotations) { + methodNode.invisibleAnnotations.add(new AnnotationNode(EXPECT_PLATFORM_TRANSFORMED_DESC)); + } } private void platformOnly(MethodNode methodNode, ClassNode classNode, AnnotationNode annotationNode) { @@ -186,9 +204,7 @@ private void getCurrentTarget(ClassNode classNode) { AbstractInsnNode insnNode = iterator.next(); if (insnNode.getOpcode() == Opcodes.INVOKESTATIC) { MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode; - if (methodInsnNode.owner.equals("xyz/wagyourtail/unimined/expect/Target") && - methodInsnNode.name.equals("getCurrentTarget") - ) { + if (methodInsnNode.owner.equals(TARGET_CLASS) && methodInsnNode.name.equals(TARGET_METHOD)) { iterator.set(new LdcInsnNode(platformName)); } }