Register KotlinModelBuilder for kotlin-android plugin

This commit is contained in:
Bradley Smith
2018-11-01 18:59:21 +00:00
committed by Sergey Igushkin
parent 939b58f8f4
commit f3482d1251
4 changed files with 78 additions and 8 deletions
@@ -7,14 +7,23 @@ package org.jetbrains.kotlin.gradle.model
import org.jetbrains.kotlin.gradle.BaseGradleIT import org.jetbrains.kotlin.gradle.BaseGradleIT
import org.jetbrains.kotlin.gradle.GradleVersionRequired import org.jetbrains.kotlin.gradle.GradleVersionRequired
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.junit.Test import org.junit.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFalse import kotlin.test.assertFalse
import kotlin.test.assertNotEquals
import kotlin.test.assertTrue import kotlin.test.assertTrue
class KotlinProjectIT : BaseGradleIT() { class KotlinProjectIT : BaseGradleIT() {
override val defaultGradleVersion: GradleVersionRequired override val defaultGradleVersion: GradleVersionRequired
get() = GradleVersionRequired.AtLeast("4.0") get() = GradleVersionRequired.AtLeast("4.1")
override fun defaultBuildOptions(): BuildOptions {
return super.defaultBuildOptions().copy(
androidGradlePluginVersion = "3.0.0",
androidHome = KotlinTestUtils.findAndroidSdk()
)
}
@Test @Test
fun testKotlinProject() { fun testKotlinProject() {
@@ -25,7 +34,8 @@ class KotlinProjectIT : BaseGradleIT() {
"kotlinProject", "kotlinProject",
defaultBuildOptions().kotlinVersion, defaultBuildOptions().kotlinVersion,
KotlinProject.ProjectType.PLATFORM_JVM, KotlinProject.ProjectType.PLATFORM_JVM,
"DEFAULT") "DEFAULT"
)
assertTrue(kotlinProject.expectedByDependencies.isEmpty()) assertTrue(kotlinProject.expectedByDependencies.isEmpty())
assertEquals(2, kotlinProject.sourceSets.size) assertEquals(2, kotlinProject.sourceSets.size)
@@ -120,6 +130,39 @@ class KotlinProjectIT : BaseGradleIT() {
assertEquals(project.projectDir.resolve("libJs/build/resources/test"), testJsSourceSet.resourcesOutputDirectory) assertEquals(project.projectDir.resolve("libJs/build/resources/test"), testJsSourceSet.resourcesOutputDirectory)
} }
@Test
fun testAndroidProject() {
val project = Project("AndroidExtensionsProject")
val kotlinProject = project.getModels(KotlinProject::class.java).getModel(":app")!!
kotlinProject.assertBasics(
"app",
defaultBuildOptions().kotlinVersion,
KotlinProject.ProjectType.PLATFORM_JVM,
"DEFAULT"
)
val expectedSourceSetNames = listOf("release", "debug", "releaseUnitTest", "debugUnitTest", "debugAndroidTest")
assertTrue(kotlinProject.expectedByDependencies.isEmpty())
assertEquals(5, kotlinProject.sourceSets.size)
fun verifySourceSet(sourceSet: SourceSet) {
// These are unused in Android projects so will be empty.
assertEquals(0, sourceSet.sourceDirectories.size)
assertEquals(0, sourceSet.resourcesDirectories.size)
assertEquals(project.projectDir.resolve("build/tmp/kotlin-classes/${sourceSet.name}"), sourceSet.classesOutputDirectory)
// This value is just a placeholder since this information is obtained from the Android Plugin models.
assertEquals(project.projectDir.resolve("build/tmp/kotlin-classes/${sourceSet.name}"), sourceSet.resourcesOutputDirectory)
assertNotEquals(0, sourceSet.compilerArguments.currentArguments.size)
assertNotEquals(0, sourceSet.compilerArguments.defaultArguments.size)
}
assertEquals(0, kotlinProject.sourceSets.filter {
verifySourceSet(it)
expectedSourceSetNames.contains(it.name)
}.size)
}
@Test @Test
fun testCoroutinesProjectDSL() { fun testCoroutinesProjectDSL() {
val project = Project("coroutinesProjectDSL") val project = Project("coroutinesProjectDSL")
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
/** /**
* [ToolingModelBuilder] for [KotlinProject] models. * [ToolingModelBuilder] for [KotlinProject] models.
* This model builder is registered for base Kotlin JVM, Kotlin JS and Kotlin Common plugins. * This model builder is registered for base Kotlin JVM (including Android), Kotlin JS and Kotlin Common plugins.
*/ */
class KotlinModelBuilder(private val kotlinPluginVersion: String) : ToolingModelBuilder { class KotlinModelBuilder(private val kotlinPluginVersion: String) : ToolingModelBuilder {
@@ -42,7 +42,9 @@ class KotlinModelBuilder(private val kotlinPluginVersion: String) : ToolingModel
project.name, project.name,
kotlinPluginVersion, kotlinPluginVersion,
projectType, projectType,
kotlinCompileTasks.mapNotNull { it.createSourceSet(project, projectType) }, kotlinCompileTasks.mapNotNull {
if (project.isAndroid()) it.createAndroidSourceSet() else it.createSourceSet(project, projectType)
},
getExpectedByDependencies(project), getExpectedByDependencies(project),
kotlinCompileTasks.first()!!.createExperimentalFeatures() kotlinCompileTasks.first()!!.createExperimentalFeatures()
) )
@@ -51,9 +53,14 @@ class KotlinModelBuilder(private val kotlinPluginVersion: String) : ToolingModel
} }
companion object { companion object {
private fun Project.isAndroid(): Boolean {
return project.plugins.hasPlugin("kotlin-android")
}
private fun getProjectType(project: Project): KotlinProject.ProjectType { private fun getProjectType(project: Project): KotlinProject.ProjectType {
return if (project.plugins.hasPlugin("kotlin") || project.plugins.hasPlugin("kotlin-platform-jvm")) { return if (project.plugins.hasPlugin("kotlin") || project.plugins.hasPlugin("kotlin-platform-jvm") ||
project.isAndroid()
) {
KotlinProject.ProjectType.PLATFORM_JVM KotlinProject.ProjectType.PLATFORM_JVM
} else if (project.plugins.hasPlugin("kotlin2js") || project.plugins.hasPlugin("kotlin-platform-js")) { } else if (project.plugins.hasPlugin("kotlin2js") || project.plugins.hasPlugin("kotlin-platform-js")) {
KotlinProject.ProjectType.PLATFORM_JS KotlinProject.ProjectType.PLATFORM_JS
@@ -91,6 +98,24 @@ class KotlinModelBuilder(private val kotlinPluginVersion: String) : ToolingModel
} else null } else null
} }
/**
* The [SourceSet] returned by this method is not intended to be complete, most of the information here is exposed by the
* Android Gradle plugin and as such is not populated here. The important information here that is required by
* Android Studio are the [CompilerArguments].
*/
private fun AbstractKotlinCompile<*>.createAndroidSourceSet(): SourceSet {
return SourceSetImpl(
sourceSetName,
if (sourceSetName.contains("test", true)) SourceSet.SourceSetType.TEST else SourceSet.SourceSetType.PRODUCTION,
findFriendSourceSets(),
emptyList(), // Obtained from the Android model
emptyList(), // Obtained from the Android model
destinationDir,
destinationDir, // Obtained from the Android model
createCompilerArguments()
)
}
private fun AbstractKotlinCompile<*>.findFriendSourceSets(): Collection<String> { private fun AbstractKotlinCompile<*>.findFriendSourceSets(): Collection<String> {
val friendSourceSets = ArrayList<String>() val friendSourceSets = ArrayList<String>()
friendTask?.sourceSetName?.let { friendSourceSets.add(it) } friendTask?.sourceSetName?.let { friendSourceSets.add(it) }
@@ -559,7 +559,8 @@ internal open class Kotlin2JsPlugin(
} }
internal open class KotlinAndroidPlugin( internal open class KotlinAndroidPlugin(
private val kotlinPluginVersion: String private val kotlinPluginVersion: String,
private val registry: ToolingModelBuilderRegistry
) : Plugin<Project> { ) : Plugin<Project> {
override fun apply(project: Project) { override fun apply(project: Project) {
@@ -570,6 +571,7 @@ internal open class KotlinAndroidPlugin(
project, androidTarget, tasksProvider, project, androidTarget, tasksProvider,
kotlinPluginVersion kotlinPluginVersion
) )
registry.register(KotlinModelBuilder(kotlinPluginVersion))
} }
companion object { companion object {
@@ -733,7 +735,7 @@ abstract class AbstractAndroidProjectHandler<V>(private val kotlinConfigurationT
kotlinTask.destinationDir = File(project.buildDir, "tmp/kotlin-classes/$variantDataName") kotlinTask.destinationDir = File(project.buildDir, "tmp/kotlin-classes/$variantDataName")
kotlinTask.description = "Compiles the $variantDataName kotlin." kotlinTask.description = "Compiles the $variantDataName kotlin."
// Register the source only after the task is created, because tne task is required for that: // Register the source only after the task is created, because the task is required for that:
compilation.source(defaultSourceSet) compilation.source(defaultSourceSet)
configureSources(kotlinTask, variantData, compilation) configureSources(kotlinTask, variantData, compilation)
@@ -116,7 +116,7 @@ open class KotlinAndroidPluginWrapper @Inject constructor(
protected val registry: ToolingModelBuilderRegistry protected val registry: ToolingModelBuilderRegistry
) : KotlinBasePluginWrapper(fileResolver) { ) : KotlinBasePluginWrapper(fileResolver) {
override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin<Project> = override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin<Project> =
KotlinAndroidPlugin(kotlinPluginVersion) KotlinAndroidPlugin(kotlinPluginVersion, registry)
} }
open class Kotlin2JsPluginWrapper @Inject constructor( open class Kotlin2JsPluginWrapper @Inject constructor(