Introduce tooling model for Kotlin gradle projects
A KotlinProject model for Gradle projects including Kotlin (JVM, JS or common) plugins is introduced. Its model builder KotlinModelBuilder produces an implementation of these models and can be queried through the Gradle Tooling API when needed. Model builder is registered in the corresponding Kotlin Gradle plugins. Model definition should be published as a separate artifact in public repositories so it can be consumed when needed.
This commit is contained in:
committed by
Sergey Igushkin
parent
4b03db771a
commit
9def6f020f
+15
@@ -1,7 +1,10 @@
|
||||
package org.jetbrains.kotlin.gradle
|
||||
|
||||
import org.gradle.api.logging.LogLevel
|
||||
import org.gradle.tooling.GradleConnector
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.jetbrains.kotlin.gradle.model.ModelContainer
|
||||
import org.jetbrains.kotlin.gradle.model.ModelFetcherBuildAction
|
||||
import org.jetbrains.kotlin.gradle.util.*
|
||||
import org.junit.After
|
||||
import org.junit.AfterClass
|
||||
@@ -274,6 +277,18 @@ abstract class BaseGradleIT {
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Project.getModels(modelType: Class<T>): ModelContainer<T> {
|
||||
if (!projectDir.exists()) {
|
||||
setupWorkingDir()
|
||||
}
|
||||
|
||||
val connection = GradleConnector.newConnector().forProjectDirectory(projectDir).connect()
|
||||
val options = defaultBuildOptions()
|
||||
val model = connection.action(ModelFetcherBuildAction(modelType)) .withArguments("-Pkotlin_version=" + options.kotlinVersion).run()
|
||||
connection.close()
|
||||
return model
|
||||
}
|
||||
|
||||
fun CompiledProject.assertSuccessful() {
|
||||
if (resultCode == 0) return
|
||||
|
||||
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* 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.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class KotlinProjectIT : BaseGradleIT() {
|
||||
|
||||
@Test
|
||||
fun testKotlinProject() {
|
||||
val project = Project("kotlinProject")
|
||||
val kotlinProject = project.getModels(KotlinProject::class.java).getModel(":")!!
|
||||
|
||||
kotlinProject.assertBasics("kotlinProject", defaultBuildOptions().kotlinVersion, KotlinProject.ProjectType.PLATFORM_JVM, "WARN")
|
||||
assertTrue(kotlinProject.expectedByDependencies.isEmpty())
|
||||
|
||||
assertEquals(2, kotlinProject.sourceSets.size)
|
||||
val mainSourceSet = kotlinProject.sourceSets.find { it.name == "main" }!!
|
||||
val testSourceSet = kotlinProject.sourceSets.find { it.name == "test" }!!
|
||||
|
||||
mainSourceSet.assertBasics("main", SourceSet.SourceSetType.PRODUCTION, emptySet())
|
||||
testSourceSet.assertBasics("test", SourceSet.SourceSetType.TEST, listOf("main"))
|
||||
|
||||
assertEquals(2, mainSourceSet.sourceDirectories.size)
|
||||
assertEquals(1, mainSourceSet.sourceDirectories.filter { it.absolutePath.contains("src/main/kotlin") }.size)
|
||||
assertEquals(1, mainSourceSet.sourceDirectories.filter { it.absolutePath.contains("src/main/java") }.size)
|
||||
assertEquals(1, mainSourceSet.resourcesDirectories.size)
|
||||
assertEquals(1, mainSourceSet.resourcesDirectories.filter { it.absolutePath.contains("src/main/resources") }.size)
|
||||
assertTrue(mainSourceSet.classesOutputDirectory.absolutePath.contains("build/classes/kotlin/main"))
|
||||
assertTrue(mainSourceSet.resourcesOutputDirectory.absolutePath.contains("build/resources/main"))
|
||||
assertTrue(mainSourceSet.compilerArguments.compileClasspath.any { it.absolutePath.contains("guava") })
|
||||
assertFalse(mainSourceSet.compilerArguments.compileClasspath.any { it.absolutePath.contains("testng") })
|
||||
|
||||
assertEquals(2, testSourceSet.sourceDirectories.size)
|
||||
assertEquals(1, testSourceSet.sourceDirectories.filter { it.absolutePath.contains("src/test/kotlin") }.size)
|
||||
assertEquals(1, testSourceSet.sourceDirectories.filter { it.absolutePath.contains("src/test/java") }.size)
|
||||
assertEquals(1, testSourceSet.resourcesDirectories.size)
|
||||
assertEquals(1, testSourceSet.resourcesDirectories.filter { it.absolutePath.contains("src/test/resources") }.size)
|
||||
assertTrue(testSourceSet.classesOutputDirectory.absolutePath.contains("build/classes/kotlin/test"))
|
||||
assertTrue(testSourceSet.resourcesOutputDirectory.absolutePath.contains("build/resources/test"))
|
||||
assertTrue(testSourceSet.compilerArguments.compileClasspath.any { it.absolutePath.contains("guava") })
|
||||
assertTrue(testSourceSet.compilerArguments.compileClasspath.any { it.absolutePath.contains("testng") })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testKotlinJavaProject() {
|
||||
val project = Project("kotlinJavaProject")
|
||||
val kotlinProject = project.getModels(KotlinProject::class.java).getModel(":")!!
|
||||
|
||||
kotlinProject.assertBasics(
|
||||
"kotlinJavaProject",
|
||||
defaultBuildOptions().kotlinVersion,
|
||||
KotlinProject.ProjectType.PLATFORM_JVM,
|
||||
"WARN"
|
||||
)
|
||||
|
||||
assertEquals(3, kotlinProject.sourceSets.size)
|
||||
val mainSourceSet = kotlinProject.sourceSets.find { it.name == "main" }!!
|
||||
val deploySourceSet = kotlinProject.sourceSets.find { it.name == "deploy" }!!
|
||||
val testSourceSet = kotlinProject.sourceSets.find { it.name == "test" }!!
|
||||
|
||||
mainSourceSet.assertBasics("main", SourceSet.SourceSetType.PRODUCTION, emptySet())
|
||||
deploySourceSet.assertBasics("deploy", SourceSet.SourceSetType.PRODUCTION, emptySet())
|
||||
testSourceSet.assertBasics("test", SourceSet.SourceSetType.TEST, listOf("main"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMultiplatformProject() {
|
||||
val project = Project("multiplatformProject")
|
||||
val models = project.getModels(KotlinProject::class.java)
|
||||
|
||||
val libKotlinProject = models.getModel(":lib")!!
|
||||
val libJsKotlinProject = models.getModel(":libJs")!!
|
||||
val libJvmKotlinProject = models.getModel(":libJvm")!!
|
||||
|
||||
libKotlinProject.assertBasics("lib", defaultBuildOptions().kotlinVersion, KotlinProject.ProjectType.PLATFORM_COMMON, "WARN")
|
||||
libJsKotlinProject.assertBasics("libJs", defaultBuildOptions().kotlinVersion, KotlinProject.ProjectType.PLATFORM_JS, "WARN")
|
||||
libJvmKotlinProject.assertBasics("libJvm", defaultBuildOptions().kotlinVersion, KotlinProject.ProjectType.PLATFORM_JVM, "WARN")
|
||||
|
||||
assertEquals(1, libJsKotlinProject.expectedByDependencies.size)
|
||||
assertTrue(libJsKotlinProject.expectedByDependencies.contains(":lib"))
|
||||
|
||||
assertEquals(1, libJvmKotlinProject.expectedByDependencies.size)
|
||||
assertTrue(libJvmKotlinProject.expectedByDependencies.contains(":lib"))
|
||||
|
||||
|
||||
assertEquals(2, libJsKotlinProject.sourceSets.size)
|
||||
val mainJsSourceSet = libJsKotlinProject.sourceSets.find { it.name == "main" }!!
|
||||
val testJsSourceSet = libJsKotlinProject.sourceSets.find { it.name == "test" }!!
|
||||
|
||||
mainJsSourceSet.assertBasics("main", SourceSet.SourceSetType.PRODUCTION, emptySet())
|
||||
testJsSourceSet.assertBasics("test", SourceSet.SourceSetType.TEST, listOf("main"))
|
||||
|
||||
assertEquals(1, mainJsSourceSet.sourceDirectories.size)
|
||||
assertEquals(1, mainJsSourceSet.sourceDirectories.filter { it.absolutePath.contains("src/main/kotlin") }.size)
|
||||
assertEquals(1, mainJsSourceSet.resourcesDirectories.size)
|
||||
assertEquals(1, mainJsSourceSet.resourcesDirectories.filter { it.absolutePath.contains("src/main/resources") }.size)
|
||||
assertTrue(mainJsSourceSet.classesOutputDirectory.absolutePath.contains("build/classes/kotlin/main"))
|
||||
assertTrue(mainJsSourceSet.resourcesOutputDirectory.absolutePath.contains("build/resources/main"))
|
||||
|
||||
assertEquals(1, testJsSourceSet.sourceDirectories.size)
|
||||
assertEquals(1, testJsSourceSet.sourceDirectories.filter { it.absolutePath.contains("src/test/kotlin") }.size)
|
||||
assertEquals(1, testJsSourceSet.resourcesDirectories.size)
|
||||
assertEquals(1, testJsSourceSet.resourcesDirectories.filter { it.absolutePath.contains("src/test/resources") }.size)
|
||||
assertTrue(testJsSourceSet.classesOutputDirectory.absolutePath.contains("build/classes/kotlin/test"))
|
||||
assertTrue(testJsSourceSet.resourcesOutputDirectory.absolutePath.contains("build/resources/test"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCoroutinesProjectDSL() {
|
||||
val project = Project("coroutinesProjectDSL")
|
||||
val kotlinProject = project.getModels(KotlinProject::class.java).getModel(":")!!
|
||||
|
||||
kotlinProject.assertBasics(
|
||||
"coroutinesProjectDSL",
|
||||
defaultBuildOptions().kotlinVersion,
|
||||
KotlinProject.ProjectType.PLATFORM_JVM,
|
||||
"ENABLE"
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private fun KotlinProject.assertBasics(
|
||||
expectedName: String,
|
||||
expectedKotlinVersion: String,
|
||||
expectedProjectType: KotlinProject.ProjectType,
|
||||
expectedCoroutines: String
|
||||
) {
|
||||
assertEquals(1L, modelVersion)
|
||||
assertEquals(expectedName, name)
|
||||
assertEquals(expectedKotlinVersion, kotlinVersion)
|
||||
assertEquals(expectedProjectType, projectType)
|
||||
assertEquals(expectedCoroutines, experimentalFeatures.coroutines)
|
||||
}
|
||||
|
||||
private fun SourceSet.assertBasics(
|
||||
expectedName: String,
|
||||
expectedType: SourceSet.SourceSetType,
|
||||
expectedFriendSourceSets: Collection<String>
|
||||
) {
|
||||
assertEquals(expectedName, name)
|
||||
assertEquals(expectedType, type)
|
||||
assertEquals(expectedFriendSourceSets.toList(), friendSourceSets.toList())
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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 java.io.Serializable
|
||||
|
||||
/**
|
||||
* Wraps models of a given type for all different projects inside a Gradle multi project.
|
||||
*/
|
||||
class ModelContainer<T> : Serializable {
|
||||
// Key is the project path
|
||||
private val modelContainer = HashMap<String, T>()
|
||||
|
||||
fun addModel(path: String, model: T) {
|
||||
modelContainer[path] = model
|
||||
}
|
||||
|
||||
fun getModel(path: String): T? {
|
||||
return modelContainer[path]
|
||||
}
|
||||
|
||||
fun hasModel(path: String): Boolean {
|
||||
return modelContainer[path] != null
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.gradle.tooling.BuildAction
|
||||
import org.gradle.tooling.BuildController
|
||||
import org.gradle.tooling.model.gradle.BasicGradleProject
|
||||
import java.io.Serializable
|
||||
|
||||
class ModelFetcherBuildAction<T>(private val modelType: Class<T>) : BuildAction<ModelContainer<T>>, Serializable {
|
||||
|
||||
override fun execute(controller: BuildController): ModelContainer<T> {
|
||||
val modelContainer = ModelContainer<T>()
|
||||
modelContainer.populateModels(controller, controller.buildModel.rootProject)
|
||||
return modelContainer
|
||||
}
|
||||
|
||||
private fun ModelContainer<T>.populateModels(controller: BuildController, gradleProject: BasicGradleProject) {
|
||||
val model = controller.findModel(gradleProject, modelType)
|
||||
if (model != null && !hasModel(gradleProject.path)) {
|
||||
addModel(gradleProject.path, model)
|
||||
}
|
||||
gradleProject.children.forEach { populateModels(controller, it) }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user