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.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions 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.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.model.builder.KaptModelBuilder
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation 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.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileTaskData
import org.jetbrains.kotlin.gradle.tasks.locateTask import org.jetbrains.kotlin.gradle.tasks.locateTask
import org.jetbrains.kotlin.gradle.tasks.registerTask import org.jetbrains.kotlin.gradle.tasks.registerTask
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
@@ -507,15 +507,14 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
private fun maybeRegisterTransform(project: Project) { private fun maybeRegisterTransform(project: Project) {
if (!project.extensions.extraProperties.has("KaptStructureTransformAdded")) { if (!project.extensions.extraProperties.has("KaptStructureTransformAdded")) {
project.dependencies.registerTransform { variantTransform -> project.dependencies.registerTransform(StructureTransformAction::class.java) { transformSpec ->
variantTransform.artifactTransform(StructureArtifactTransform::class.java) transformSpec.from.attribute(artifactType, "jar")
variantTransform.from.attribute(artifactType, "jar") transformSpec.to.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE)
variantTransform.to.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE)
} }
project.dependencies.registerTransform { variantTransform ->
variantTransform.artifactTransform(StructureArtifactTransform::class.java) project.dependencies.registerTransform(StructureTransformAction::class.java) { transformSpec ->
variantTransform.from.attribute(artifactType, "directory") transformSpec.from.attribute(artifactType, "directory")
variantTransform.to.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE) transformSpec.to.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE)
} }
project.extensions.extraProperties["KaptStructureTransformAdded"] = true project.extensions.extraProperties["KaptStructureTransformAdded"] = true
@@ -590,6 +589,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
override fun getPluginArtifact(): SubpluginArtifact = override fun getPluginArtifact(): SubpluginArtifact =
JetBrainsSubpluginArtifact(artifactId = KAPT_ARTIFACT_NAME) JetBrainsSubpluginArtifact(artifactId = KAPT_ARTIFACT_NAME)
} }
private val artifactType = Attribute.of("artifactType", String::class.java) 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 // 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 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.ClassReader
import org.jetbrains.org.objectweb.asm.ClassWriter import org.jetbrains.org.objectweb.asm.ClassWriter
import java.io.* import java.io.*
@@ -15,19 +20,23 @@ import java.util.zip.ZipFile
const val CLASS_STRUCTURE_ARTIFACT_TYPE = "class-structure" const val CLASS_STRUCTURE_ARTIFACT_TYPE = "class-structure"
private const val MODULE_INFO = "module-info.class" private const val MODULE_INFO = "module-info.class"
class StructureArtifactTransform : ArtifactTransform() { abstract class StructureTransformAction : TransformAction<TransformParameters.None> {
override fun transform(input: File): MutableList<File> { @get:InputArtifact
abstract val inputArtifact: File
override fun transform(outputs: TransformOutputs) {
try { try {
val input = inputArtifact
val data = if (input.isDirectory) { val data = if (input.isDirectory) {
visitDirectory(input) visitDirectory(input)
} else { } else {
visitJar(input) visitJar(input)
} }
val dataFile = outputDirectory.resolve("output.bin") val dataFile = outputs.file("output.bin")
data.saveTo(dataFile) data.saveTo(dataFile)
return mutableListOf(dataFile)
} catch (e: Throwable) { } catch (e: Throwable) {
throw e throw e
} }
@@ -10,8 +10,12 @@ package org.jetbrains.kotlin.gradle.scripting.internal
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration 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.attributes.Attribute
import org.gradle.api.file.FileSystemLocation
import org.gradle.api.plugins.JavaPluginConvention import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.gradle.api.tasks.compile.AbstractCompile 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.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.reporter import org.jetbrains.kotlin.scripting.compiler.plugin.impl.reporter
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsFromClasspathDiscoverySource import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsFromClasspathDiscoverySource
import java.io.File
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
private const val SCRIPTING_LOG_PREFIX = "kotlin scripting plugin:" 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 = val definitions =
ScriptDefinitionsFromClasspathDiscoverySource( ScriptDefinitionsFromClasspathDiscoverySource(
listOf(input), listOf(input),
defaultJvmScriptingHostConfiguration, defaultJvmScriptingHostConfiguration,
PrintingMessageCollector(System.out, MessageRenderer.WITHOUT_PATHS, false).reporter PrintingMessageCollector(System.out, MessageRenderer.WITHOUT_PATHS, false).reporter
).definitions ).definitions
val extensions = definitions.mapTo(arrayListOf()) { it.fileExtension } 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")) outputFile.writeText(extensions.joinToString("\n"))
listOf(outputFile) listOf(outputFile)
} else emptyList() }
} }
} }
private private fun Project.registerDiscoverScriptExtensionsTransform() {
fun Project.registerDiscoverScriptExtensionsTransform() {
dependencies.apply { dependencies.apply {
registerTransform { registerTransform(DiscoverScriptExtensionsTransformAction::class.java) { transformSpec ->
with(it) { transformSpec.from.attribute(artifactType, "jar")
from.attribute(artifactType, "jar") transformSpec.to.attribute(artifactType, scriptFilesExtensions)
to.attribute(artifactType, scriptFilesExtensions)
artifactTransform(DiscoverScriptExtensionsTransform::class.java)
}
} }
registerTransform { registerTransform(DiscoverScriptExtensionsTransformAction::class.java) { transformSpec ->
with(it) { transformSpec.from.attribute(artifactType, "classes")
from.attribute(artifactType, "classes") transformSpec.to.attribute(artifactType, scriptFilesExtensions)
to.attribute(artifactType, scriptFilesExtensions)
artifactTransform(DiscoverScriptExtensionsTransform::class.java)
}
} }
} }
} }
private private fun <T> Project.withRegisteredDiscoverScriptExtensionsTransform(block: () -> T): T {
fun <T> Project.withRegisteredDiscoverScriptExtensionsTransform(block: () -> T): T {
if (!project.extensions.extraProperties.has("DiscoverScriptExtensionsTransform")) { if (!project.extensions.extraProperties.has("DiscoverScriptExtensionsTransform")) {
registerDiscoverScriptExtensionsTransform() registerDiscoverScriptExtensionsTransform()
project.extensions.extraProperties["DiscoverScriptExtensionsTransform"] = true 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 val scriptFilesExtensions = "script-files-extensions"
private private fun Configuration.discoverScriptExtensionsFiles() =
fun Configuration.discoverScriptExtensionsFiles() =
incoming.artifactView { incoming.artifactView {
attributes { attributes {
it.attribute(artifactType, scriptFilesExtensions) it.attribute(artifactType, scriptFilesExtensions)
@@ -5,12 +5,20 @@
package org.jetbrains.kotlin.gradle.internal.kapt.incremental 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.ClassWriter
import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes
import org.junit.Assert.* import org.junit.Assert.*
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.rules.TemporaryFolder import org.junit.rules.TemporaryFolder
import java.io.File
import java.util.concurrent.Callable
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream import java.util.zip.ZipOutputStream
@@ -32,10 +40,10 @@ class ClasspathAnalyzerTest {
it.writeBytes(emptyClass("A")) it.writeBytes(emptyClass("A"))
} }
} }
val transform = StructureArtifactTransform().also { it.outputDirectory = tmp.newFolder() } val outputs = TransformOutputsMock(tmp.newFolder())
val outputs = transform.transform(classesDir) 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.classAbiHash.keys)
assertEquals(setOf("test/A", "test/B"), data.classDependencies.keys) assertEquals(setOf("test/A", "test/B"), data.classDependencies.keys)
assertEquals(emptySet<String>(), data.classDependencies["test/A"]!!.abiTypes) assertEquals(emptySet<String>(), data.classDependencies["test/A"]!!.abiTypes)
@@ -68,10 +76,10 @@ class ClasspathAnalyzerTest {
it.closeEntry() it.closeEntry()
} }
} }
val transform = StructureArtifactTransform().also { it.outputDirectory = tmp.newFolder() } val outputs = TransformOutputsMock(tmp.newFolder())
val outputs = transform.transform(inputJar) 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.classAbiHash.keys)
assertEquals(setOf("test/A", "test/B"), data.classDependencies.keys) assertEquals(setOf("test/A", "test/B"), data.classDependencies.keys)
assertEquals(emptySet<String>(), data.classDependencies["test/A"]!!.abiTypes) assertEquals(emptySet<String>(), data.classDependencies["test/A"]!!.abiTypes)
@@ -94,7 +102,8 @@ class ClasspathAnalyzerTest {
it.closeEntry() 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 -> val jarB = tmp.newFile("inputB.jar").also { jar ->
ZipOutputStream(jar.outputStream()).use { ZipOutputStream(jar.outputStream()).use {
@@ -107,18 +116,20 @@ class ClasspathAnalyzerTest {
it.closeEntry() 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 @Test
fun emptyInput() { fun emptyInput() {
val inputDir = tmp.newFolder("input") val transformAction = StructureTransformTestAction(tmp.newFolder("input"))
val transform = StructureArtifactTransform().also { it.outputDirectory = tmp.newFolder() } val outputs = TransformOutputsMock(tmp.newFolder())
val outputs = transform.transform(inputDir)
val data = ClasspathEntryData.ClasspathEntrySerializer.loadFrom(outputs.single()) transformAction.transform(outputs)
val data = ClasspathEntryData.ClasspathEntrySerializer.loadFrom(outputs.createdOutputs.single())
assertTrue(data.classAbiHash.isEmpty()) assertTrue(data.classAbiHash.isEmpty())
assertTrue(data.classDependencies.isEmpty()) assertTrue(data.classDependencies.isEmpty())
} }
@@ -129,3 +140,29 @@ class ClasspathAnalyzerTest {
return writer.toByteArray() 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
}
}