Warning for Kotlin plugins loaded multiple times (KT-30276)
Print a warning with an instruction on how to fix this. Don't warn about different versions and duplicate plugins in composite build. Issue #KT-30276 Fixed
This commit is contained in:
+68
@@ -17,6 +17,8 @@
|
|||||||
package org.jetbrains.kotlin.gradle
|
package org.jetbrains.kotlin.gradle
|
||||||
|
|
||||||
import org.gradle.api.logging.LogLevel
|
import org.gradle.api.logging.LogLevel
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.MULTIPLE_KOTLIN_PLUGINS_LOADED_WARNING
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_WARNING
|
||||||
import org.jetbrains.kotlin.gradle.tasks.USING_JVM_INCREMENTAL_COMPILATION_MESSAGE
|
import org.jetbrains.kotlin.gradle.tasks.USING_JVM_INCREMENTAL_COMPILATION_MESSAGE
|
||||||
import org.jetbrains.kotlin.gradle.util.*
|
import org.jetbrains.kotlin.gradle.util.*
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -823,4 +825,70 @@ class KotlinGradleIT : BaseGradleIT() {
|
|||||||
assertTasksExecuted(":jvm-app:compileKotlin")
|
assertTasksExecuted(":jvm-app:compileKotlin")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDetectingDifferentClassLoaders() = with(Project("kt-27059-pom-rewriting", GradleVersionRequired.AtLeast("4.10.2"))) {
|
||||||
|
setupWorkingDir()
|
||||||
|
|
||||||
|
val originalRootBuildScript = gradleBuildScript().readText()
|
||||||
|
gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl)
|
||||||
|
|
||||||
|
build("publish", "-PmppProjectDependency=true") {
|
||||||
|
assertSuccessful()
|
||||||
|
assertNotContains(MULTIPLE_KOTLIN_PLUGINS_LOADED_WARNING)
|
||||||
|
assertNotContains(MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_WARNING)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specify the plugin versions in the subprojects with different plugin sets – this will make Gradle use separate class loaders
|
||||||
|
gradleBuildScript().modify {
|
||||||
|
originalRootBuildScript.checkedReplace("id \"org.jetbrains.kotlin.multiplatform\"", "//")
|
||||||
|
}
|
||||||
|
gradleBuildScript("mpp-lib").modify {
|
||||||
|
it.checkedReplace(
|
||||||
|
"id \"org.jetbrains.kotlin.multiplatform\"",
|
||||||
|
"id \"org.jetbrains.kotlin.multiplatform\" version \"<pluginMarkerVersion>\""
|
||||||
|
).let(::transformBuildScriptWithPluginsDsl)
|
||||||
|
}
|
||||||
|
gradleBuildScript("jvm-app").modify {
|
||||||
|
it.checkedReplace(
|
||||||
|
"id \"org.jetbrains.kotlin.jvm\"",
|
||||||
|
"id \"org.jetbrains.kotlin.jvm\" version \"<pluginMarkerVersion>\""
|
||||||
|
).let(::transformBuildScriptWithPluginsDsl)
|
||||||
|
}
|
||||||
|
gradleBuildScript("js-app").modify {
|
||||||
|
it.checkedReplace(
|
||||||
|
"id \"kotlin2js\"",
|
||||||
|
"id \"kotlin2js\" version \"<pluginMarkerVersion>\""
|
||||||
|
).let(::transformBuildScriptWithPluginsDsl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also include another project via a composite build:
|
||||||
|
transformProjectWithPluginsDsl("allopenPluginsDsl", directoryPrefix = "pluginsDsl").let { other ->
|
||||||
|
val result = other.projectName
|
||||||
|
other.setupWorkingDir()
|
||||||
|
other.projectDir.copyRecursively(projectDir.resolve(result))
|
||||||
|
gradleSettingsScript().appendText("\nincludeBuild(\"${result}\")")
|
||||||
|
gradleBuildScript().appendText(
|
||||||
|
"\ntasks.create(\"publish\").dependsOn(gradle.includedBuild(\"${result}\").task(\":assemble\"))"
|
||||||
|
)
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
build("publish", "-PmppProjectDependency=true") {
|
||||||
|
assertSuccessful()
|
||||||
|
assertContains(MULTIPLE_KOTLIN_PLUGINS_LOADED_WARNING)
|
||||||
|
|
||||||
|
val specificProjectsReported = Regex("$MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_WARNING((?:'.*'(?:, )?)+)")
|
||||||
|
.find(output)!!.groupValues[1].split(", ").map { it.removeSurrounding("'") }.toSet()
|
||||||
|
|
||||||
|
assertEquals(setOf(":mpp-lib", ":jvm-app", ":js-app"), specificProjectsReported)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the flag that turns off the warnings
|
||||||
|
build("publish", "-PmppProjectDependency=true", "-Pkotlin.pluginLoadedInMultipleProjects.ignore=true") {
|
||||||
|
assertSuccessful()
|
||||||
|
assertNotContains(MULTIPLE_KOTLIN_PLUGINS_LOADED_WARNING)
|
||||||
|
assertNotContains(MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_WARNING)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+56
-7
@@ -18,23 +18,19 @@ package org.jetbrains.kotlin.gradle.plugin
|
|||||||
|
|
||||||
import org.gradle.BuildAdapter
|
import org.gradle.BuildAdapter
|
||||||
import org.gradle.BuildResult
|
import org.gradle.BuildResult
|
||||||
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.invocation.Gradle
|
import org.gradle.api.invocation.Gradle
|
||||||
import org.gradle.api.logging.Logger
|
|
||||||
import org.gradle.api.logging.Logging
|
import org.gradle.api.logging.Logging
|
||||||
|
import org.gradle.api.plugins.ExtraPropertiesExtension
|
||||||
import org.jetbrains.kotlin.compilerRunner.DELETED_SESSION_FILE_PREFIX
|
import org.jetbrains.kotlin.compilerRunner.DELETED_SESSION_FILE_PREFIX
|
||||||
import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner
|
import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner
|
||||||
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskLoggers
|
|
||||||
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
|
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
|
||||||
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskExecutionResults
|
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskExecutionResults
|
||||||
import org.jetbrains.kotlin.gradle.report.KotlinBuildReporter
|
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskLoggers
|
||||||
import org.jetbrains.kotlin.gradle.report.configureBuildReporter
|
import org.jetbrains.kotlin.gradle.report.configureBuildReporter
|
||||||
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
|
|
||||||
import org.jetbrains.kotlin.gradle.utils.relativeToRoot
|
import org.jetbrains.kotlin.gradle.utils.relativeToRoot
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.sumByLong
|
import org.jetbrains.kotlin.utils.addToStdlib.sumByLong
|
||||||
import java.io.File
|
|
||||||
import java.lang.management.ManagementFactory
|
import java.lang.management.ManagementFactory
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
internal class KotlinGradleBuildServices private constructor(
|
internal class KotlinGradleBuildServices private constructor(
|
||||||
private val gradle: Gradle
|
private val gradle: Gradle
|
||||||
@@ -137,5 +133,58 @@ internal class KotlinGradleBuildServices private constructor(
|
|||||||
|
|
||||||
private fun getGcCount(): Long =
|
private fun getGcCount(): Long =
|
||||||
ManagementFactory.getGarbageCollectorMXBeans().sumByLong { Math.max(0, it.collectionCount) }
|
ManagementFactory.getGarbageCollectorMXBeans().sumByLong { Math.max(0, it.collectionCount) }
|
||||||
|
|
||||||
|
private var loadedInProjectPath: String? = null
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
internal fun detectKotlinPluginLoadedInMultipleProjects(project: Project, kotlinPluginVersion: String) {
|
||||||
|
val projectPath = project.path
|
||||||
|
|
||||||
|
val loadedInProjectsPropertyName = "kotlin.plugin.loaded.in.projects.${kotlinPluginVersion}"
|
||||||
|
|
||||||
|
if (loadedInProjectPath == null) {
|
||||||
|
loadedInProjectPath = projectPath
|
||||||
|
|
||||||
|
val ext = project.rootProject.extensions.getByType(ExtraPropertiesExtension::class.java)
|
||||||
|
|
||||||
|
if (!ext.has(loadedInProjectsPropertyName)) {
|
||||||
|
ext.set(loadedInProjectsPropertyName, projectPath)
|
||||||
|
|
||||||
|
gradle.taskGraph.whenReady {
|
||||||
|
val loadedInProjects = (ext.get(loadedInProjectsPropertyName) as String).split(";")
|
||||||
|
if (loadedInProjects.size > 1) {
|
||||||
|
if (PropertiesProvider(project).ignorePluginLoadedInMultipleProjects != true) {
|
||||||
|
project.logger.warn(MULTIPLE_KOTLIN_PLUGINS_LOADED_WARNING)
|
||||||
|
project.logger.warn(
|
||||||
|
MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_WARNING + loadedInProjects.joinToString(limit = 4) { "'$it'" }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
project.logger.info(
|
||||||
|
"$MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_INFO: " +
|
||||||
|
loadedInProjects.joinToString { "'$it'" }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ext.set(loadedInProjectsPropertyName, (ext.get(loadedInProjectsPropertyName) as String) + ";" + loadedInProjectPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const val MULTIPLE_KOTLIN_PLUGINS_LOADED_WARNING: String =
|
||||||
|
"\nThe Kotlin Gradle plugin was loaded multiple times in different subprojects, which is not supported and may break the build. \n" +
|
||||||
|
|
||||||
|
"This might happen in subprojects that apply the Kotlin plugins with the Gradle 'plugins { ... }' DSL if they specify " +
|
||||||
|
"explicit versions, even if the versions are equal.\n" +
|
||||||
|
|
||||||
|
"Please add the Kotlin plugin to the common parent project or the root project, then remove the versions in the subprojects.\n" +
|
||||||
|
|
||||||
|
"If the parent project does not need the plugin, add 'apply false' to the plugin line.\n" +
|
||||||
|
|
||||||
|
"See: https://docs.gradle.org/current/userguide/plugins.html#sec:subprojects_plugins_dsl"
|
||||||
|
|
||||||
|
const val MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_WARNING: String =
|
||||||
|
"The Kotlin plugin was loaded in the following projects: "
|
||||||
|
|
||||||
|
const val MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_INFO: String = "The full list of projects that loaded the Kotlin plugin is: "
|
||||||
|
|||||||
+2
@@ -67,6 +67,8 @@ abstract class KotlinBasePluginWrapper(
|
|||||||
System.setProperty(org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY, "true")
|
System.setProperty(org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY, "true")
|
||||||
val kotlinGradleBuildServices = KotlinGradleBuildServices.getInstance(project.gradle)
|
val kotlinGradleBuildServices = KotlinGradleBuildServices.getInstance(project.gradle)
|
||||||
|
|
||||||
|
kotlinGradleBuildServices.detectKotlinPluginLoadedInMultipleProjects(project, kotlinPluginVersion)
|
||||||
|
|
||||||
project.createKotlinExtension(projectExtensionClass).apply {
|
project.createKotlinExtension(projectExtensionClass).apply {
|
||||||
fun kotlinSourceSetContainer(factory: NamedDomainObjectFactory<KotlinSourceSet>) =
|
fun kotlinSourceSetContainer(factory: NamedDomainObjectFactory<KotlinSourceSet>) =
|
||||||
project.container(KotlinSourceSet::class.java, factory)
|
project.container(KotlinSourceSet::class.java, factory)
|
||||||
|
|||||||
+3
@@ -82,6 +82,9 @@ internal class PropertiesProvider(private val project: Project) {
|
|||||||
val keepMppDependenciesIntactInPoms: Boolean?
|
val keepMppDependenciesIntactInPoms: Boolean?
|
||||||
get() = booleanProperty("kotlin.mpp.keepMppDependenciesIntactInPoms")
|
get() = booleanProperty("kotlin.mpp.keepMppDependenciesIntactInPoms")
|
||||||
|
|
||||||
|
val ignorePluginLoadedInMultipleProjects: Boolean?
|
||||||
|
get() = booleanProperty("kotlin.pluginLoadedInMultipleProjects.ignore")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables parallel tasks execution within a project with Workers API.
|
* Enables parallel tasks execution within a project with Workers API.
|
||||||
* Does not enable using actual worker proccesses
|
* Does not enable using actual worker proccesses
|
||||||
|
|||||||
Reference in New Issue
Block a user