Files
kotlin-fork/prepare/reflect/build.gradle.kts
T
2017-09-19 21:37:06 +02:00

132 lines
4.8 KiB
Kotlin

import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.api.Project
import org.jetbrains.org.objectweb.asm.*
import org.gradle.jvm.tasks.Jar
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.util.jar.JarFile
import java.util.zip.ZipOutputStream
buildscript {
repositories {
jcenter()
}
dependencies {
classpath("com.github.jengelman.gradle.plugins:shadow:1.2.3")
classpath(ideaSdkDeps("asm-all"))
}
}
apply { plugin("com.github.johnrengelman.shadow") }
// Set to false to prevent relocation and metadata stripping on kotlin-reflect.jar and reflection sources. Use to debug reflection
val obfuscateReflect = true
val classesFromProjectsCfg = configurations.create("classes-from-projects")
val otherDepsCfg = configurations.create("other-deps")
val mainCfg = configurations.create("default")
val outputReflectJarFileBase = "$buildDir/libs/kotlin-reflect"
val coreProjectName = ":core"
val reflectionProjectName = ":core:reflection.jvm"
artifacts.add(mainCfg.name, File(outputReflectJarFileBase + ".jar"))
dependencies {
classesFromProjectsCfg.name(projectDepIntransitive(coreProjectName))
classesFromProjectsCfg.name(projectDepIntransitive(":core:util.runtime"))
classesFromProjectsCfg.name(projectDepIntransitive(reflectionProjectName))
otherDepsCfg.name(protobufLite())
otherDepsCfg.name(commonDep("javax.inject"))
buildVersion()
}
val prePackReflectTask = task<ShadowJar>("pre-pack-reflect") {
classifier = if (obfuscateReflect) outputReflectJarFileBase + "_beforeStrip" else outputReflectJarFileBase
configurations = listOf(mainCfg)
setupRuntimeJar("Kotlin Reflect")
dependsOn("$coreProjectName:assemble", "$reflectionProjectName:assemble", protobufLiteTask)
from(project(reflectionProjectName).getCompiledClasses())
from(project(coreProjectName).getCompiledClasses())
from(project(":core:util.runtime").getCompiledClasses())
from(project(coreProjectName).file("descriptor.loader.java/src")) {
include("META-INF/services/**")
}
from(otherDepsCfg.files)
manifest.attributes.put("Class-Path", "kotlin-runtime.jar")
if (obfuscateReflect) {
relocate("org.jetbrains.kotlin", "kotlin.reflect.jvm.internal.impl")
relocate("javax.inject", "kotlin.reflect.jvm.internal.impl.javax.inject")
}
}
val mainTask = task("prepare") {
dependsOn(prePackReflectTask)
val inFile = File(outputReflectJarFileBase + "_beforeStrip.jar")
val outFile = File(outputReflectJarFileBase + ".jar")
inputs.file(inFile)
outputs.file(outFile)
val annotationRegex = "kotlin/Metadata".toRegex()
val classRegex = "kotlin/reflect/jvm/internal/impl/.*".toRegex()
doLast {
println("Stripping annotations from all classes in $inFile")
println("Input file size: ${inFile.length()} bytes")
fun transform(entryName: String, bytes: ByteArray): ByteArray {
if (!entryName.endsWith(".class")) return bytes
if (!classRegex.matches(entryName.removeSuffix(".class"))) return bytes
var changed = false
val classWriter = ClassWriter(0)
val classVisitor = object : ClassVisitor(Opcodes.ASM5, classWriter) {
override fun visitAnnotation(desc: String, visible: Boolean): AnnotationVisitor? {
if (annotationRegex.matches(Type.getType(desc).internalName)) {
changed = true
return null
}
return super.visitAnnotation(desc, visible)
}
}
ClassReader(bytes).accept(classVisitor, 0)
if (!changed) return bytes
return classWriter.toByteArray()
}
ZipOutputStream(BufferedOutputStream(FileOutputStream(outFile))).use { outJar ->
val inJar = JarFile(inFile)
try {
for (entry in inJar.entries()) {
if (entry.isDirectory) continue
val inBytes = inJar.getInputStream(entry).readBytes()
val outBytes = transform(entry.name, inBytes)
if (inBytes.size < outBytes.size) {
error("Size increased for ${entry.name}: was ${inBytes.size} bytes, became ${outBytes.size} bytes")
}
entry.compressedSize = -1L
outJar.putNextEntry(entry)
outJar.write(outBytes)
outJar.closeEntry()
}
}
finally {
// Yes, JarFile does not extend Closeable on JDK 6 so we can't use "use" here
inJar.close()
}
}
println("Output written to $outFile")
println("Output file size: ${outFile.length()} bytes")
}
}
defaultTasks(mainTask.name)