name.remal.gradle_plugins.dsl.internal.PluginClassesProcessor.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-plugins-kotlin-dsl Show documentation
Show all versions of gradle-plugins-kotlin-dsl Show documentation
Remal Gradle plugins: gradle-plugins-kotlin-dsl
package name.remal.gradle_plugins.dsl.internal
import name.remal.ASM_API
import name.remal.get
import name.remal.gradle_plugins.api.AutoService
import name.remal.gradle_plugins.api.classes_processing.BytecodeModifier
import name.remal.gradle_plugins.api.classes_processing.ClassesProcessor
import name.remal.gradle_plugins.api.classes_processing.ClassesProcessor.COLLECTION_STAGE
import name.remal.gradle_plugins.api.classes_processing.ClassesProcessorsGradleTaskFactory
import name.remal.gradle_plugins.api.classes_processing.ProcessContext
import name.remal.gradle_plugins.dsl.*
import name.remal.gradle_plugins.dsl.extensions.toHasEntries
import name.remal.gradle_plugins.dsl.extensions.unwrapProviders
import name.remal.nullIfEmpty
import name.remal.storeAsString
import org.gradle.api.tasks.compile.AbstractCompile
import org.gradle.util.GradleVersion
import org.objectweb.asm.AnnotationVisitor
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassReader.*
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.Type.getDescriptor
import org.objectweb.asm.tree.AnnotationNode
import java.util.*
class PluginClassesProcessor(minGradleVersionDefault: String?) : ClassesProcessor {
private val minGradleVersionDefault: GradleVersion? = minGradleVersionDefault?.let(GradleVersion::version)
companion object {
private val pluginDesc: String = getDescriptor(Plugin::class.java)
private val minGradleVersionDesc: String = getDescriptor(MinGradleVersion::class.java)
private val maxGradleVersionDesc: String = getDescriptor(MaxGradleVersion::class.java)
}
override fun process(bytecode: ByteArray, bytecodeModifier: BytecodeModifier, className: String, resourceName: String, context: ProcessContext) {
val pluginAnnotationNodes = mutableListOf()
val minGradleVersionNodes = mutableListOf()
val maxGradleVersionNodes = mutableListOf()
ClassReader(bytecode).accept(
object : ClassVisitor(ASM_API) {
override fun visitAnnotation(desc: String?, visible: Boolean): AnnotationVisitor? {
if (pluginDesc == desc) return AnnotationNode(desc).also { pluginAnnotationNodes.add(it) }
if (minGradleVersionDesc == desc) return AnnotationNode(desc).also { minGradleVersionNodes.add(it) }
if (maxGradleVersionDesc == desc) return AnnotationNode(desc).also { maxGradleVersionNodes.add(it) }
return null
}
},
SKIP_DEBUG or SKIP_FRAMES or SKIP_CODE
)
val pluginAnnotationNode = pluginAnnotationNodes.singleOrNull() ?: return
val pluginId = pluginAnnotationNode[Plugin::id] ?: return
context.writeTextResource(
"META-INF/gradle-plugins/$pluginId.properties",
Properties().apply {
setProperty(IMPLEMENTATION_CLASS_PLUGIN_DESCRIPTOR_KEY, className)
pluginAnnotationNode[Plugin::description].canonize()?.let { setProperty(DESCRIPTION_PLUGIN_DESCRIPTOR_KEY, it) }
pluginAnnotationNode[Plugin::tags]?.joinToString(";").canonize()?.let { setProperty(TAGS_PLUGIN_DESCRIPTOR_KEY, it) }
pluginAnnotationNode[Plugin::isHidden]?.let { setProperty(IS_HIDDEN_DESCRIPTOR_KEY, it.toString()) }
minGradleVersionDefault?.let { setProperty(MIN_GRADLE_VERSION_PLUGIN_DESCRIPTOR_KEY, it.version) }
minGradleVersionNodes.singleOrNull()
?.let { it[MinGradleVersion::value] }
?.let { extractGradleVersion(it[1]) }
?.let { minGradleVersion ->
if (minGradleVersionDefault == null || minGradleVersion > minGradleVersionDefault) {
setProperty(MIN_GRADLE_VERSION_PLUGIN_DESCRIPTOR_KEY, minGradleVersion.version)
}
}
maxGradleVersionNodes.singleOrNull()
?.let { it[MaxGradleVersion::value] }
?.let { extractGradleVersion(it[1]) }
?.let { maxGradleVersion ->
setProperty(MAX_GRADLE_VERSION_PLUGIN_DESCRIPTOR_KEY, maxGradleVersion.version)
}
}.storeAsString()
)
}
override fun getStage() = COLLECTION_STAGE
private fun String?.canonize() = this?.trim()?.replace("\r", "").nullIfEmpty()
private fun extractGradleVersion(enumName: String): GradleVersion {
var firstDigitPos = -1
for ((i, ch) in enumName.toCharArray().withIndex()) {
if (ch.isDigit()) {
firstDigitPos = i
break
}
}
if (firstDigitPos < 0) throw IllegalArgumentException("Gradle version enum name doesn't have digits")
return GradleVersion.version(enumName.substring(firstDigitPos).replace('_', '.'))
}
}
@AutoService
class PluginClassesProcessorFactory : ClassesProcessorsGradleTaskFactory {
override fun createClassesProcessors(compileTask: AbstractCompile): List {
if (!compileTask.classpath.toHasEntries().containsClass(Plugin::class.java)) return emptyList()
return listOf(PluginClassesProcessor(
compileTask.project.findProperty("gradle.min-version").unwrapProviders()?.toString()
))
}
}