KT-37720 Replace ArtifactTransform with TransformAction

This commit is contained in:
nataliya.valtman
2020-04-13 12:10:29 +03:00
parent b9585dabd4
commit 9e737156dd
4 changed files with 100 additions and 53 deletions
@@ -26,12 +26,12 @@ import org.gradle.tooling.provider.model.ToolingModelBuilder
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.CLASS_STRUCTURE_ARTIFACT_TYPE
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureArtifactTransform
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureTransformAction
import org.jetbrains.kotlin.gradle.model.builder.KaptModelBuilder
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileTaskData
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileTaskData
import org.jetbrains.kotlin.gradle.tasks.locateTask
import org.jetbrains.kotlin.gradle.tasks.registerTask
import java.io.ByteArrayOutputStream
@@ -507,15 +507,14 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
private fun maybeRegisterTransform(project: Project) {
if (!project.extensions.extraProperties.has("KaptStructureTransformAdded")) {
project.dependencies.registerTransform { variantTransform ->
variantTransform.artifactTransform(StructureArtifactTransform::class.java)
variantTransform.from.attribute(artifactType, "jar")
variantTransform.to.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE)
project.dependencies.registerTransform(StructureTransformAction::class.java) { transformSpec ->
transformSpec.from.attribute(artifactType, "jar")
transformSpec.to.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE)
}
project.dependencies.registerTransform { variantTransform ->
variantTransform.artifactTransform(StructureArtifactTransform::class.java)
variantTransform.from.attribute(artifactType, "directory")
variantTransform.to.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE)
project.dependencies.registerTransform(StructureTransformAction::class.java) { transformSpec ->
transformSpec.from.attribute(artifactType, "directory")
transformSpec.to.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE)
}
project.extensions.extraProperties["KaptStructureTransformAdded"] = true
@@ -590,6 +589,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
override fun getPluginArtifact(): SubpluginArtifact =
JetBrainsSubpluginArtifact(artifactId = KAPT_ARTIFACT_NAME)
}
private val artifactType = Attribute.of("artifactType", String::class.java)
// Don't reference the BaseVariant type in the Kapt plugin signatures, as those type references will fail to link when there's no Android
@@ -5,7 +5,12 @@
package org.jetbrains.kotlin.gradle.internal.kapt.incremental
import org.gradle.api.artifacts.transform.ArtifactTransform
import org.gradle.api.artifacts.transform.InputArtifact
import org.gradle.api.artifacts.transform.TransformAction
import org.gradle.api.artifacts.transform.TransformOutputs
import org.gradle.api.artifacts.transform.TransformParameters
import org.gradle.api.file.FileSystemLocation
import org.gradle.api.provider.Provider
import org.jetbrains.org.objectweb.asm.ClassReader
import org.jetbrains.org.objectweb.asm.ClassWriter
import java.io.*
@@ -15,19 +20,23 @@ import java.util.zip.ZipFile
const val CLASS_STRUCTURE_ARTIFACT_TYPE = "class-structure"
private const val MODULE_INFO = "module-info.class"
class StructureArtifactTransform : ArtifactTransform() {
override fun transform(input: File): MutableList<File> {
abstract class StructureTransformAction : TransformAction<TransformParameters.None> {
@get:InputArtifact
abstract val inputArtifact: File
override fun transform(outputs: TransformOutputs) {
try {
val input = inputArtifact
val data = if (input.isDirectory) {
visitDirectory(input)
} else {
visitJar(input)
}
val dataFile = outputDirectory.resolve("output.bin")
val dataFile = outputs.file("output.bin")
data.saveTo(dataFile)
return mutableListOf(dataFile)
} catch (e: Throwable) {
throw e
}
@@ -10,8 +10,12 @@ package org.jetbrains.kotlin.gradle.scripting.internal
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.transform.ArtifactTransform
import org.gradle.api.artifacts.transform.InputArtifact
import org.gradle.api.artifacts.transform.TransformAction
import org.gradle.api.artifacts.transform.TransformOutputs
import org.gradle.api.artifacts.transform.TransformParameters
import org.gradle.api.attributes.Attribute
import org.gradle.api.file.FileSystemLocation
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.compile.AbstractCompile
@@ -25,7 +29,6 @@ import org.jetbrains.kotlin.gradle.scripting.ScriptingExtension
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.reporter
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsFromClasspathDiscoverySource
import java.io.File
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
private const val SCRIPTING_LOG_PREFIX = "kotlin scripting plugin:"
@@ -149,46 +152,45 @@ private fun configureDiscoveryTransformation(
}
}
internal class DiscoverScriptExtensionsTransform : ArtifactTransform() {
internal abstract class DiscoverScriptExtensionsTransformAction : TransformAction<TransformParameters.None> {
@InputArtifact
abstract fun getInputArtifact(): Provider<FileSystemLocation>
override fun transform(outputs: TransformOutputs) {
val input = getInputArtifact().get().asFile
override fun transform(input: File): List<File> {
val definitions =
ScriptDefinitionsFromClasspathDiscoverySource(
listOf(input),
defaultJvmScriptingHostConfiguration,
PrintingMessageCollector(System.out, MessageRenderer.WITHOUT_PATHS, false).reporter
).definitions
val extensions = definitions.mapTo(arrayListOf()) { it.fileExtension }
return if (extensions.isNotEmpty()) {
val outputFile = outputDirectory.resolve("${input.nameWithoutExtension}.discoveredScriptsExtensions.txt")
if (extensions.isNotEmpty()) {
val outputFile = outputs.file("${input.nameWithoutExtension}.discoveredScriptsExtensions.txt")
outputFile.writeText(extensions.joinToString("\n"))
listOf(outputFile)
} else emptyList()
}
}
}
private
fun Project.registerDiscoverScriptExtensionsTransform() {
private fun Project.registerDiscoverScriptExtensionsTransform() {
dependencies.apply {
registerTransform {
with(it) {
from.attribute(artifactType, "jar")
to.attribute(artifactType, scriptFilesExtensions)
artifactTransform(DiscoverScriptExtensionsTransform::class.java)
}
registerTransform(DiscoverScriptExtensionsTransformAction::class.java) { transformSpec ->
transformSpec.from.attribute(artifactType, "jar")
transformSpec.to.attribute(artifactType, scriptFilesExtensions)
}
registerTransform {
with(it) {
from.attribute(artifactType, "classes")
to.attribute(artifactType, scriptFilesExtensions)
artifactTransform(DiscoverScriptExtensionsTransform::class.java)
}
registerTransform(DiscoverScriptExtensionsTransformAction::class.java) { transformSpec ->
transformSpec.from.attribute(artifactType, "classes")
transformSpec.to.attribute(artifactType, scriptFilesExtensions)
}
}
}
private
fun <T> Project.withRegisteredDiscoverScriptExtensionsTransform(block: () -> T): T {
private fun <T> Project.withRegisteredDiscoverScriptExtensionsTransform(block: () -> T): T {
if (!project.extensions.extraProperties.has("DiscoverScriptExtensionsTransform")) {
registerDiscoverScriptExtensionsTransform()
project.extensions.extraProperties["DiscoverScriptExtensionsTransform"] = true
@@ -200,8 +202,7 @@ private val artifactType = Attribute.of("artifactType", String::class.java)
private val scriptFilesExtensions = "script-files-extensions"
private
fun Configuration.discoverScriptExtensionsFiles() =
private fun Configuration.discoverScriptExtensionsFiles() =
incoming.artifactView {
attributes {
it.attribute(artifactType, scriptFilesExtensions)
@@ -5,12 +5,20 @@
package org.jetbrains.kotlin.gradle.internal.kapt.incremental
import org.gradle.api.artifacts.transform.TransformOutputs
import org.gradle.api.artifacts.transform.TransformParameters
import org.gradle.api.file.FileSystemLocation
import org.gradle.api.internal.file.DefaultFileSystemLocation
import org.gradle.api.internal.provider.DefaultProvider
import org.gradle.api.provider.Provider
import org.jetbrains.org.objectweb.asm.ClassWriter
import org.jetbrains.org.objectweb.asm.Opcodes
import org.junit.Assert.*
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import java.io.File
import java.util.concurrent.Callable
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
@@ -32,10 +40,10 @@ class ClasspathAnalyzerTest {
it.writeBytes(emptyClass("A"))
}
}
val transform = StructureArtifactTransform().also { it.outputDirectory = tmp.newFolder() }
val outputs = transform.transform(classesDir)
val outputs = TransformOutputsMock(tmp.newFolder())
StructureTransformTestAction(classesDir).transform(outputs)
val data = ClasspathEntryData.ClasspathEntrySerializer.loadFrom(outputs.single())
val data = ClasspathEntryData.ClasspathEntrySerializer.loadFrom(outputs.createdOutputs.single())
assertEquals(setOf("test/A", "test/B"), data.classAbiHash.keys)
assertEquals(setOf("test/A", "test/B"), data.classDependencies.keys)
assertEquals(emptySet<String>(), data.classDependencies["test/A"]!!.abiTypes)
@@ -68,10 +76,10 @@ class ClasspathAnalyzerTest {
it.closeEntry()
}
}
val transform = StructureArtifactTransform().also { it.outputDirectory = tmp.newFolder() }
val outputs = transform.transform(inputJar)
val outputs = TransformOutputsMock(tmp.newFolder())
StructureTransformTestAction(inputJar).transform(outputs)
val data = ClasspathEntryData.ClasspathEntrySerializer.loadFrom(outputs.single())
val data = ClasspathEntryData.ClasspathEntrySerializer.loadFrom(outputs.createdOutputs.single())
assertEquals(setOf("test/A", "test/B"), data.classAbiHash.keys)
assertEquals(setOf("test/A", "test/B"), data.classDependencies.keys)
assertEquals(emptySet<String>(), data.classDependencies["test/A"]!!.abiTypes)
@@ -94,7 +102,8 @@ class ClasspathAnalyzerTest {
it.closeEntry()
}
}
val outputA = StructureArtifactTransform().also { it.outputDirectory = tmp.newFolder() }.transform(jarA).single()
val outputsA = TransformOutputsMock(tmp.newFolder())
StructureTransformTestAction(jarA).transform(outputsA)
val jarB = tmp.newFile("inputB.jar").also { jar ->
ZipOutputStream(jar.outputStream()).use {
@@ -107,18 +116,20 @@ class ClasspathAnalyzerTest {
it.closeEntry()
}
}
val outputB = StructureArtifactTransform().also { it.outputDirectory = tmp.newFolder() }.transform(jarB).single()
val outputsB = TransformOutputsMock(tmp.newFolder())
StructureTransformTestAction(jarB).transform(outputsB)
assertArrayEquals(outputA.readBytes(), outputB.readBytes())
assertArrayEquals(outputsA.createdOutputs.single().readBytes(), outputsB.createdOutputs.single().readBytes())
}
@Test
fun emptyInput() {
val inputDir = tmp.newFolder("input")
val transform = StructureArtifactTransform().also { it.outputDirectory = tmp.newFolder() }
val outputs = transform.transform(inputDir)
val transformAction = StructureTransformTestAction(tmp.newFolder("input"))
val outputs = TransformOutputsMock(tmp.newFolder())
val data = ClasspathEntryData.ClasspathEntrySerializer.loadFrom(outputs.single())
transformAction.transform(outputs)
val data = ClasspathEntryData.ClasspathEntrySerializer.loadFrom(outputs.createdOutputs.single())
assertTrue(data.classAbiHash.isEmpty())
assertTrue(data.classDependencies.isEmpty())
}
@@ -128,4 +139,30 @@ class ClasspathAnalyzerTest {
writer.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, internalName, null, "java/lang/Object", emptyArray())
return writer.toByteArray()
}
}
class StructureTransformTestAction(val input: File) : StructureTransformAction() {
override val inputArtifact: File = input
override fun getParameters(): TransformParameters.None? {
//no need for StructureTransformAction and so for test
return null
}
}
class TransformOutputsMock(val outputDir: File) : TransformOutputs {
val createdOutputs = mutableListOf<File>()
override fun file(name: Any): File {
val newFile = outputDir.resolve(name as String)
createdOutputs.add(newFile)
return newFile
}
override fun dir(name: Any): File {
val newDir = outputDir.resolve(name as String)
createdOutputs.add(newDir)
return newDir
}
}