[Gradle] Add circular dependency check for KT-31459
^KT-31459
This commit is contained in:
+51
-4
@@ -5,9 +5,14 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.fail
|
||||
|
||||
class KT31459JvmMainClassesTest {
|
||||
|
||||
@@ -27,15 +32,57 @@ class KT31459JvmMainClassesTest {
|
||||
|
||||
assertEquals(
|
||||
setOf("compileKotlinJvm", "compileJava", "jvmProcessResources"),
|
||||
task.allDependencies
|
||||
task.directDependencies
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns names of all tasks that given task depends on
|
||||
* This mechanism used by `kotlinx-atomicfu` gradle plugin. It replaces compilation classes to transformed classes dir
|
||||
*/
|
||||
private val Task.allDependencies: Set<String> get() = taskDependencies
|
||||
.getDependencies(this)
|
||||
@Test
|
||||
fun `it should be possible to replace compilation output classes`() {
|
||||
|
||||
/**
|
||||
* Code taken from `kotlinx-atomicfu` gradle plugin
|
||||
*/
|
||||
fun Project.addClassesTransformationTask(target: KotlinTarget) {
|
||||
val compilation = target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
|
||||
val classesDirs = compilation.output.classesDirs
|
||||
|
||||
// make copy of original classes directory
|
||||
val originalClassesDirs: FileCollection =
|
||||
project.files(classesDirs.from.toTypedArray())
|
||||
val transformedClassesDir = project.buildDir.resolve("classes/atomicfu/${target.name}/${compilation.name}")
|
||||
val transformTask = project.tasks.create("transformTask") {
|
||||
it.dependsOn(compilation.compileAllTaskName)
|
||||
it.inputs.files(originalClassesDirs)
|
||||
it.outputs.files(transformedClassesDir)
|
||||
}
|
||||
classesDirs.setFrom(transformedClassesDir)
|
||||
classesDirs.builtBy(transformTask)
|
||||
}
|
||||
|
||||
// Given MPP Project with JVM target
|
||||
val project = buildProjectWithMPP {
|
||||
kotlin {
|
||||
val target = jvm {}
|
||||
|
||||
// And classes transformation task applied
|
||||
addClassesTransformationTask(target)
|
||||
}
|
||||
}
|
||||
|
||||
project.evaluate()
|
||||
|
||||
val jvmMainClasses = project.tasks.getByName("jvmMainClasses")
|
||||
jvmMainClasses.assertNoCircularTaskDependencies()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns names of all tasks that given task directly depends on
|
||||
*/
|
||||
private val Task.directDependencies: Set<String> get() = taskDependencies
|
||||
.getDependencies(null)
|
||||
.map { it.name }
|
||||
.toSet()
|
||||
}
|
||||
+23
-2
@@ -7,10 +7,8 @@ package org.jetbrains.kotlin.gradle
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
|
||||
import org.jetbrains.kotlin.gradle.utils.`is`
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.fail
|
||||
@@ -31,6 +29,29 @@ fun Task.assertNotDependsOn(other: Task) {
|
||||
}
|
||||
}
|
||||
|
||||
fun Task.assertNoCircularTaskDependencies() {
|
||||
data class TaskAndDependants(
|
||||
val task: Task,
|
||||
val dependants: List<Task>
|
||||
)
|
||||
|
||||
val visited = mutableSetOf<Task>()
|
||||
val queue = ArrayDeque(taskDependencies.getDependencies(this).map { TaskAndDependants(it, listOf(this)) })
|
||||
|
||||
while(queue.isNotEmpty()) {
|
||||
val (task, dependants) = queue.removeFirst()
|
||||
if (task in visited) {
|
||||
val dependencyChain = dependants.joinToString(" -> ") { it.name }
|
||||
fail("Task $name has circular dependency: $dependencyChain")
|
||||
}
|
||||
visited.add(task)
|
||||
|
||||
val dependencies = task.taskDependencies.getDependencies(null)
|
||||
queue.addAll(dependencies.map { TaskAndDependants(it, dependants + task) })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun Task.assertTaskDependenciesEquals(dependencies: Set<Task>) {
|
||||
assertEquals(
|
||||
dependencies, this.taskDependencies.getDependencies(null),
|
||||
|
||||
Reference in New Issue
Block a user