From 5671dbb929994f1d22f73afbefceb484c91c98c4 Mon Sep 17 00:00:00 2001 From: Lucas Smaira Date: Tue, 5 Jun 2018 13:08:02 +0100 Subject: [PATCH] Introduce tooling model for Kapt gradle projects A Kapt model for Gradle projects including 'kotlin-kapt'plugin is introduced. Its model builder KaptModelBuilder produces an implementation of these models and can be queried through the Gradle Tooling API when needed. Model builder is registered in Kapt3GradleSubplugin. --- .../kotlin/gradle/model/KaptModelIT.kt | 55 ++++++++++++++++ .../jetbrains/kotlin/gradle/model/Kapt.java | 41 ++++++++++++ .../kotlin/gradle/model/KaptSourceSet.java | 65 +++++++++++++++++++ .../kapt/Kapt3KotlinGradleSubplugin.kt | 6 +- .../gradle/model/builder/KaptModelBuilder.kt | 51 +++++++++++++++ .../kotlin/gradle/model/impl/KaptImpl.kt | 35 ++++++++++ .../gradle/model/impl/KaptSourceSetImpl.kt | 42 ++++++++++++ .../model/builder/KaptModelBuilderTest.kt | 20 ++++++ .../kotlin/gradle/model/impl/KaptImplTest.kt | 18 +++++ .../model/impl/KaptSourceSetImplTest.kt | 18 +++++ 10 files changed, 350 insertions(+), 1 deletion(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/model/KaptModelIT.kt create mode 100644 libraries/tools/kotlin-gradle-plugin-model/src/main/java/org/jetbrains/kotlin/gradle/model/Kapt.java create mode 100644 libraries/tools/kotlin-gradle-plugin-model/src/main/java/org/jetbrains/kotlin/gradle/model/KaptSourceSet.java create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/builder/KaptModelBuilder.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/impl/KaptImpl.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/impl/KaptSourceSetImpl.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/model/builder/KaptModelBuilderTest.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/model/impl/KaptImplTest.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/model/impl/KaptSourceSetImplTest.kt diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/model/KaptModelIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/model/KaptModelIT.kt new file mode 100644 index 00000000000..68156d9ccfb --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/model/KaptModelIT.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.model + +import org.jetbrains.kotlin.gradle.BaseGradleIT +import org.junit.Test +import kotlin.test.assertEquals +import kotlin.test.assertNull +import kotlin.test.assertTrue + +class KaptModelIT : BaseGradleIT() { + + @Test + fun testKaptSimple() { + val project = Project("simple", directoryPrefix = "kapt2") + val kaptModel = project.getModels(Kapt::class.java).getModel(":")!! + + kaptModel.assertBasics("simple") + + assertEquals(2, kaptModel.kaptSourceSets.size) + val mainSourceSet = kaptModel.kaptSourceSets.find { it.name == "main" }!! + val testSourceSet = kaptModel.kaptSourceSets.find { it.name == "test" }!! + + assertEquals(KaptSourceSet.KaptSourceSetType.PRODUCTION, mainSourceSet.type) + assertTrue(mainSourceSet.generatedSourcesDirectory.absolutePath.contains("build/generated/source/kapt/main")) + assertTrue(mainSourceSet.generatedKotlinSourcesDirectory.absolutePath.contains("build/generated/source/kaptKotlin/main")) + assertTrue(mainSourceSet.generatedClassesDirectory.absolutePath.contains("tmp/kapt3/classes/main")) + + assertEquals(KaptSourceSet.KaptSourceSetType.TEST, testSourceSet.type) + assertTrue(testSourceSet.generatedSourcesDirectory.absolutePath.contains("build/generated/source/kapt/test")) + assertTrue(testSourceSet.generatedKotlinSourcesDirectory.absolutePath.contains("build/generated/source/kaptKotlin/test")) + assertTrue(testSourceSet.generatedClassesDirectory.absolutePath.contains("tmp/kapt3/classes/test")) + } + + @Test + fun testNonJvmProjects() { + val project = Project("kotlin2JsProject") + val models = project.getModels(Kapt::class.java) + + assertNull(models.getModel(":")) + assertNull(models.getModel(":libraryProject")) + assertNull(models.getModel(":mainProject")) + } + + companion object { + + private fun Kapt.assertBasics(expectedName: String) { + assertEquals(1L, modelVersion) + assertEquals(expectedName, name) + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-model/src/main/java/org/jetbrains/kotlin/gradle/model/Kapt.java b/libraries/tools/kotlin-gradle-plugin-model/src/main/java/org/jetbrains/kotlin/gradle/model/Kapt.java new file mode 100644 index 00000000000..568dc8bcfd1 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-model/src/main/java/org/jetbrains/kotlin/gradle/model/Kapt.java @@ -0,0 +1,41 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.model; + +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; + +/** + * Entry point for annotation processor model. + * Plugin 'kotlin-kapt' can produce this model. + */ +public interface Kapt { + + /** + * Return a number representing the version of this API. + * Always increasing if changed. + * + * @return the version of this model. + */ + long getModelVersion(); + + /** + * Returns the module (Gradle project) name. + * + * @return the module name. + */ + @NotNull + String getName(); + + /** + * Return all kapt source sets. + * + * @return all kapt source sets. + */ + @NotNull + Collection getKaptSourceSets(); +} diff --git a/libraries/tools/kotlin-gradle-plugin-model/src/main/java/org/jetbrains/kotlin/gradle/model/KaptSourceSet.java b/libraries/tools/kotlin-gradle-plugin-model/src/main/java/org/jetbrains/kotlin/gradle/model/KaptSourceSet.java new file mode 100644 index 00000000000..5fc85db60bb --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-model/src/main/java/org/jetbrains/kotlin/gradle/model/KaptSourceSet.java @@ -0,0 +1,65 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.model; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * Represents a source set for a given kapt model. + * @see Kapt + */ +public interface KaptSourceSet { + + /** + * Possible source set types. + */ + enum KaptSourceSetType { + PRODUCTION, + TEST + } + + /** + * Return the source set name. + * + * @return the source set name. + */ + @NotNull + String getName(); + + /** + * Return the type of the source set. + * + * @return the type of the source set. + */ + @NotNull + KaptSourceSetType getType(); + + /** + * Return generated sources directory. + * + * @return generated sources directory. + */ + @NotNull + File getGeneratedSourcesDirectory(); + + /** + * Return Kotlin generated sources directory. + * + * @return Kotlin generated sources directory. + */ + @NotNull + File getGeneratedKotlinSourcesDirectory(); + + /** + * Return Kotlin generated classes directory. + * + * @return Kotlin generated classes directory. + */ + @NotNull + File getGeneratedClassesDirectory(); +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt index 26e7129fd0b..7bde3e33ae7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt @@ -18,10 +18,12 @@ import org.gradle.api.tasks.TaskDependency import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.JavaCompile import org.gradle.process.CommandLineArgumentProvider +import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.getKaptGeneratedClassesDir import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.getKaptGeneratedKotlinSourcesDir import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.getKaptGeneratedSourcesDir import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin.Companion.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME +import org.jetbrains.kotlin.gradle.model.builder.KaptModelBuilder import org.jetbrains.kotlin.gradle.tasks.isWorkerAPISupported import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions @@ -31,9 +33,10 @@ import java.io.ByteArrayOutputStream import java.io.File import java.io.ObjectOutputStream import java.util.* +import javax.inject.Inject // apply plugin: 'kotlin-kapt' -class Kapt3GradleSubplugin : Plugin { +class Kapt3GradleSubplugin @Inject internal constructor(private val registry: ToolingModelBuilderRegistry) : Plugin { companion object { fun isEnabled(project: Project) = project.plugins.findPlugin(Kapt3GradleSubplugin::class.java) != null @@ -61,6 +64,7 @@ class Kapt3GradleSubplugin : Plugin { } ?: project.logger.error("Kotlin plugin should be enabled before 'kotlin-kapt'") } } + registry.register(KaptModelBuilder()) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/builder/KaptModelBuilder.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/builder/KaptModelBuilder.kt new file mode 100644 index 00000000000..81eaacd6344 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/builder/KaptModelBuilder.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.model.builder + +import org.gradle.api.Project +import org.gradle.tooling.provider.model.ToolingModelBuilder +import org.jetbrains.kotlin.gradle.internal.KaptTask +import org.jetbrains.kotlin.gradle.model.Kapt +import org.jetbrains.kotlin.gradle.model.KaptSourceSet +import org.jetbrains.kotlin.gradle.model.impl.KaptImpl +import org.jetbrains.kotlin.gradle.model.impl.KaptSourceSetImpl + +/** + * [ToolingModelBuilder] for [Kapt] models. + * This model builder is registered for Kapt Gradle sub-plugin. + */ +class KaptModelBuilder : ToolingModelBuilder { + + override fun canBuild(modelName: String): Boolean { + return modelName == Kapt::class.java.name + } + + override fun buildAll(modelName: String, project: Project): Any? { + if (modelName == Kapt::class.java.name) { + val kaptTasks = project.tasks.withType(KaptTask::class.java) + return KaptImpl(project.name, kaptTasks.map { it.createKaptSourceSet() }) + } + return null + } + + companion object { + + private fun KaptTask.createKaptSourceSet(): KaptSourceSet { + val sourceSetName = kotlinCompileTask.sourceSetName + return KaptSourceSetImpl( + sourceSetName, + if (sourceSetName.contains( + "test", + true + ) + ) KaptSourceSet.KaptSourceSetType.TEST else KaptSourceSet.KaptSourceSetType.PRODUCTION, + destinationDir, + kotlinSourcesDestinationDir, + classesDir + ) + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/impl/KaptImpl.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/impl/KaptImpl.kt new file mode 100644 index 00000000000..44e55a82b05 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/impl/KaptImpl.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.model.impl + +import org.jetbrains.kotlin.gradle.model.Kapt +import org.jetbrains.kotlin.gradle.model.KaptSourceSet +import java.io.Serializable + +/** + * Implementation of the [Kapt] interface. + */ +data class KaptImpl( + private val myName: String, + private val kaptSourceSets: Collection +) : Kapt, Serializable { + + override fun getModelVersion(): Long { + return serialVersionUID + } + + override fun getName(): String { + return myName + } + + override fun getKaptSourceSets(): Collection { + return kaptSourceSets + } + + companion object { + private const val serialVersionUID = 1L + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/impl/KaptSourceSetImpl.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/impl/KaptSourceSetImpl.kt new file mode 100644 index 00000000000..9bca3bbf468 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/impl/KaptSourceSetImpl.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.model.impl + +import org.jetbrains.kotlin.gradle.model.KaptSourceSet +import java.io.File +import java.io.Serializable + +/** + * Implementation of the [KaptSourceSet] interface. + */ +data class KaptSourceSetImpl( + private val myName: String, + private val myType: KaptSourceSet.KaptSourceSetType, + private val myGeneratedSourcesDirectory: File, + private val myGeneratedKotlinSourcesDirectory: File, + private val myGeneratedClassesDirectory: File +) : KaptSourceSet, Serializable { + + override fun getName(): String { + return myName + } + + override fun getType(): KaptSourceSet.KaptSourceSetType { + return myType + } + + override fun getGeneratedSourcesDirectory(): File { + return myGeneratedSourcesDirectory + } + + override fun getGeneratedKotlinSourcesDirectory(): File { + return myGeneratedKotlinSourcesDirectory + } + + override fun getGeneratedClassesDirectory(): File { + return myGeneratedClassesDirectory + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/model/builder/KaptModelBuilderTest.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/model/builder/KaptModelBuilderTest.kt new file mode 100644 index 00000000000..f214f5e033e --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/model/builder/KaptModelBuilderTest.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.model.builder + +import org.jetbrains.kotlin.gradle.model.Kapt +import org.junit.Test +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class KaptModelBuilderTest { + @Test + fun testCanBuild() { + val modelBuilder = KaptModelBuilder() + assertTrue(modelBuilder.canBuild(Kapt::class.java.name)) + assertFalse(modelBuilder.canBuild("wrongModel")) + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/model/impl/KaptImplTest.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/model/impl/KaptImplTest.kt new file mode 100644 index 00000000000..f0598332d87 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/model/impl/KaptImplTest.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.model.impl + +import nl.jqno.equalsverifier.EqualsVerifier +import nl.jqno.equalsverifier.Warning +import org.junit.Test + +class KaptImplTest { + @Test + @Throws(Exception::class) + fun equals() { + EqualsVerifier.forClass(KaptImpl::class.java).suppress(Warning.NULL_FIELDS).verify() + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/model/impl/KaptSourceSetImplTest.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/model/impl/KaptSourceSetImplTest.kt new file mode 100644 index 00000000000..914438c80de --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/model/impl/KaptSourceSetImplTest.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.model.impl + +import nl.jqno.equalsverifier.EqualsVerifier +import nl.jqno.equalsverifier.Warning +import org.junit.Test + +class KaptSourceSetImplTest { + @Test + @Throws(Exception::class) + fun equals() { + EqualsVerifier.forClass(KaptSourceSetImpl::class.java).suppress(Warning.NULL_FIELDS).verify() + } +} \ No newline at end of file