package net.fabricmc.yarn.buildlogic.task import groovy.transform.CompileStatic import org.gradle.api.DefaultTask import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction import org.objectweb.asm.ClassReader import org.objectweb.asm.Opcodes import org.objectweb.asm.tree.ClassNode import java.util.zip.ZipFile @CompileStatic class GeneratePackageInfoMappingsTask extends DefaultTask { @InputFile final RegularFileProperty inputJar = project.objects.fileProperty() @OutputDirectory final Property packageName = project.objects.property(String.class) @OutputDirectory final DirectoryProperty outputDir = project.objects.directoryProperty() @TaskAction def run() { project.logger.lifecycle("Scanning ${inputJar.get().asFile} for package-info classes") outputDir.get().asFile.deleteDir() new ZipFile(inputJar.get().asFile).withCloseable {zipFile -> zipFile.entries().iterator().forEachRemaining({ entry -> if (entry.name.endsWith(".class")) { zipFile.getInputStream(entry).withCloseable {is -> processEntry(entry.name, is) } } }) } } private void processEntry(String name, InputStream inputStream) { name = name.replace(".class", "") if (name.contains("\$")) { // Dont care about inner classes return } ClassReader classReader = new ClassReader(inputStream) ClassNode classNode = new ClassNode() classReader.accept(classNode, 0) if (classNode.access != (Opcodes.ACC_ABSTRACT | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_INTERFACE )) { // We only care about abstract synthetic interfaces, hopefully this is specific enough return } if (classNode.methods.size() > 0 || classNode.fields.size() > 0 || classNode.interfaces.size() > 0) { // Nope cannot be a package-info return } generateMapping(name) } private void generateMapping(String name) { String inputName = name.substring(name.lastIndexOf("/") + 1) String className = "PackageInfo" + name.substring(name.lastIndexOf("_") + 1) String fullName = packageName.get() + className; File mappingsFile = new File(outputDir.get().asFile, "${className}.mapping") mappingsFile.parentFile.mkdirs() mappingsFile.text = """\ CLASS net/minecraft/$inputName $fullName """.stripIndent() } }