Skip to content

Commit

Permalink
Add deprecations Gradle DSL
Browse files Browse the repository at this point in the history
  • Loading branch information
ALikhachev committed Sep 18, 2024
1 parent 3948905 commit eaa5c29
Show file tree
Hide file tree
Showing 11 changed files with 151 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib:2.0.20")
}

kapiFence {
deprecateClass("kotlin.collections.AbstractSet", null)
}

tasks.withType(JavaCompile).configureEach {
options.compilerArgs << '-Xlint:deprecation' << '-Werror'
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ repositories {
mavenCentral()
}

kapiFence {
deprecateClass("kotlin.collections.AbstractSet", null)
}

kotlin {
compilerOptions {
allWarningsAsErrors = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.gradle.api.artifacts.transform.TransformParameters
import org.gradle.api.file.ArchiveOperations
import org.gradle.api.file.FileSystemLocation
import org.gradle.api.logging.Logging
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Input
Expand All @@ -17,6 +18,7 @@ import org.jetbrains.hackathon2024.visitor.DeprecatingClassVisitor
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter
import proguard.KeepClassSpecification
import java.io.InputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
import javax.inject.Inject
Expand All @@ -27,6 +29,9 @@ internal abstract class DeprecatingTransformAction :
@get:Optional
@get:Input
val deprecationMessage: Property<String>

@get:Input
val proguardConfig: ListProperty<String>
}

private val logger = Logging.getLogger(DeprecatingTransformAction::class.java)
Expand All @@ -44,22 +49,26 @@ internal abstract class DeprecatingTransformAction :
ZipOutputStream(outputFile.outputStream()).use { resultZip ->
archiveOperations.zipTree(inputFile).visit { details ->
val file = details.file
if (file.endsWith("AbstractSet.class")) { // TODO: matching logic
logger.info("Deprecating $file") // TODO: replace with FQN
file.inputStream().use { inputStream ->
if (file.path.endsWith(".class")) {
logger.info("Transforming ${file.name}")
// not optimal :(
var inputStream: InputStream = file.inputStream()
var lastBytes: ByteArray? = null
for (proguardConfig in parameters.proguardConfig.get()) {
val classReader = ClassReader(inputStream)
val classWriter = ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES)
// TODO(Dmitrii Krasnov): remove hardcode
val keepClassSpecifications = ProguardParser().parse("class kotlin.collections.AbstractSet{}")
logger.info("Handling $proguardConfig")
SpecificationProcessor().process(
classReader, classWriter, keepClassSpecifications, parameters.deprecationMessage.orNull
classReader, classWriter, ProguardParser().parse(proguardConfig), parameters.deprecationMessage.orNull
?: "The class is deprecated within the project by KapiFence plugin"
)
val entry = ZipEntry(details.relativePath.pathString)
resultZip.putNextEntry(entry)
resultZip.write(classWriter.toByteArray())
resultZip.closeEntry()
lastBytes = classWriter.toByteArray()
inputStream = classWriter.toByteArray().inputStream()
}
val entry = ZipEntry(details.relativePath.pathString)
resultZip.putNextEntry(entry)
resultZip.write(lastBytes!!)
resultZip.closeEntry()
} else {
val archivePath = if (details.isDirectory) "${details.path}/" else details.path
val entry = ZipEntry(archivePath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.gradle.api.Project
import org.gradle.api.artifacts.type.ArtifactTypeDefinition
import org.gradle.api.attributes.Attribute
import org.gradle.api.plugins.JavaPlugin
import org.jetbrains.hackathon2024.dsl.KapiFenceRootBuilder
import java.io.Serializable

interface DeprecationsAttribute : Named, Serializable {
Expand Down Expand Up @@ -52,7 +53,7 @@ internal fun Project.configureDeprecationsAttribute() {
}
}

internal fun Project.registerDeprecationsTransform() {
internal fun Project.registerDeprecationsTransform(dslBuilder: KapiFenceRootBuilder) {
with(dependencies) {
registerTransform(DeprecatingTransformAction::class.java) {
it.from.attribute(
Expand All @@ -69,6 +70,10 @@ internal fun Project.registerDeprecationsTransform() {
DeprecationsAttribute.WITH_DEPRECATIONS
)
)
it.parameters.deprecationMessage.set(dslBuilder.deprecationMessage)
it.parameters.proguardConfig.set(project.provider {
dslBuilder.records
})
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ package org.jetbrains.hackathon2024

import org.gradle.api.Project
import org.gradle.api.Plugin
import org.jetbrains.hackathon2024.dsl.KapiFenceRootBuilder

class KapiFencePlugin : Plugin<Project> {
override fun apply(project: Project) {
with(project) {
val dslBuilder = KapiFenceRootBuilder(this)
project.extensions.add(KapiFenceRootDsl::class.java, "kapiFence", dslBuilder)
configureDeprecationsAttribute()
registerDeprecationsTransform()
registerDeprecationsTransform(dslBuilder)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.jetbrains.hackathon2024.dsl

import org.gradle.api.Project
import org.gradle.api.provider.Property
import org.jetbrains.hackathon2024.ArgumentType
import org.jetbrains.hackathon2024.KapiFenceClassDsl
import org.jetbrains.hackathon2024.KapiFenceRootDsl

internal class KapiFenceRootBuilder(project: Project) : KapiFenceRootDsl {
internal val records: List<String>
get() = records_
private val records_: MutableList<String> = mutableListOf()

override val deprecationMessage: Property<String> = project.objects.property(String::class.java)

override fun deprecateClass(
name: String,
body: (KapiFenceClassDsl.() -> Unit)?,
) {
records_.add("class $name")
if (body != null) {
deprecateMembers(name, body)
}
}

override fun deprecateMembers(
name: String,
body: KapiFenceClassDsl.() -> Unit,
) {
val funBuilder = StringBuilder()
funBuilder.appendLine("class $name {")
val propBuilder = StringBuilder()
propBuilder.appendLine("class $name {")
KapiFenceClassBuilder(funBuilder, propBuilder).body()
funBuilder.appendLine("}")
propBuilder.appendLine("}")
records_.add(funBuilder.toString())
records_.add(propBuilder.toString())
}
}

internal class KapiFenceClassBuilder(private val funBuilder: StringBuilder, private val propBuilder: StringBuilder) : KapiFenceClassDsl {
override fun deprecateConstructor(vararg argumentType: ArgumentType) {
deprecateFun("<init>", *argumentType)
}

override fun deprecateFun(
name: String,
vararg argumentType: ArgumentType,
) {
funBuilder.appendLine("*** $name(${argumentType.joinToString(", ") { it.type }});")
}

override fun deprecateProperty(name: String) {
propBuilder.appendLine("private *** $name;")
}
}
46 changes: 46 additions & 0 deletions plugin/src/main/kotlin/org/jetbrains/hackathon2024/kapiFenceDsl.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.jetbrains.hackathon2024

import org.gradle.api.provider.Property

@DslMarker
annotation class KapiFenceDsl

@KapiFenceDsl
sealed class ArgumentType(val type: kotlin.String) {

object Byte : ArgumentType("byte")
object NullableByte : ArgumentType("java.lang.Byte")
object Short : ArgumentType("short")
object NullableShort : ArgumentType("java.lang.Short")
object Int : ArgumentType("int")
object NullableInt : ArgumentType("java.lang.Integer")
object Long : ArgumentType("long")
object NullableLong : ArgumentType("java.lang.Long")
object Float : ArgumentType("float")
object NullableFloat : ArgumentType("java.lang.Float")
object Double : ArgumentType("double")
object NullableDouble : ArgumentType("java.lang.Double")
object Char : ArgumentType("char")
object NullableChar : ArgumentType("java.lang.Character")
object Boolean : ArgumentType("boolean")
object NullableBoolean : ArgumentType("java.lang.Boolean")
object String : ArgumentType("java.lang.String")
object Wildcard : ArgumentType("***")
class Class(name: kotlin.String) : ArgumentType(name)
}

@KapiFenceDsl
interface KapiFenceRootDsl {
val deprecationMessage: Property<String>
fun deprecateClass(name: String, body: (KapiFenceClassDsl.() -> Unit)? = null)
fun deprecateMembers(name: String, body: KapiFenceClassDsl.() -> Unit)
}

const val KAPI_FENCE_WILDCARD_NAME = "*"

@KapiFenceDsl
interface KapiFenceClassDsl {
fun deprecateConstructor(vararg argumentType: ArgumentType)
fun deprecateFun(name: String, vararg argumentType: ArgumentType)
fun deprecateProperty(name: String)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ abstract class BaseVisitor(
classWriter: ClassWriter,
) : ClassVisitor(Opcodes.ASM9, classWriter) {

protected lateinit var kotlinMetadata: KotlinClassMetadata
protected var kotlinMetadata: KotlinClassMetadata? = null
private set

/**
* Reads the existing [Metadata] and overrides it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ class DeprecatingClassFields(
}

override fun visitEnd() {
writeAnnotation(kotlinMetadata.write())
kotlinMetadata?.let {
writeAnnotation(it.write())
}
}

private inner class DeprecatingMethodVisitor(originalVisitor: MethodVisitor) :
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ class DeprecatingClassMethodVisitor(
}
}

writeAnnotation(metadata.write())
kotlinMetadata?.let {
writeAnnotation(it.write())
}
}

private inner class DeprecatingMethodVisitor(originalVisitor: MethodVisitor) : MethodVisitor(Opcodes.ASM9, originalVisitor) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ class DeprecatingClassVisitor(
kClass.hasAnnotations = true
}

writeAnnotation(metadata.write())
kotlinMetadata?.let {
writeAnnotation(it.write())
}
super.visitEnd()
if (!isAlreadyDeprecated && shouldApplyChanges) {
// don't deprecate and don't override the message if the class is already deprecated
Expand Down

0 comments on commit eaa5c29

Please sign in to comment.