yarn/build-logic/src/main/groovy/net/fabricmc/yarn/buildlogic/task/GeneratePackageInfoMappings...

81 lines
2.7 KiB
Groovy

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<String> 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()
}
}