org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.GradleException
import org.gradle.api.NamedDomainObjectFactory
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
import org.gradle.api.model.ObjectFactory
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.compilerRunner.registerCommonizerClasspathConfigurationIfNecessary
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.internal.KOTLIN_COMPILER_EMBEDDABLE
import org.jetbrains.kotlin.gradle.internal.KOTLIN_MODULE_GROUP
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20GradlePlugin
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20ProjectExtension
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSetFactory
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsCompilerAttribute
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsPlugin
import org.jetbrains.kotlin.gradle.targets.js.npm.addNpmDependencyExtension
import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropKlibLibraryElements
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
import org.jetbrains.kotlin.gradle.testing.internal.KotlinTestsRegistry
import org.jetbrains.kotlin.gradle.tooling.buildKotlinToolingMetadataTask
import org.jetbrains.kotlin.gradle.utils.checkGradleCompatibility
import org.jetbrains.kotlin.gradle.utils.loadPropertyFromResources
import org.jetbrains.kotlin.gradle.utils.runProjectConfigurationHealthCheck
import org.jetbrains.kotlin.statistics.metrics.StringMetrics
import javax.inject.Inject
import kotlin.reflect.KClass
abstract class KotlinBasePluginWrapper: Plugin {
private val log = Logging.getLogger(this.javaClass)
@Deprecated(
message = "Scheduled to be removed in 1.7 release",
replaceWith = ReplaceWith(
"project.getKotlinPluginVersion()",
"org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion"
)
)
val kotlinPluginVersion by lazy { loadKotlinVersionFromResource(log) }
open val projectExtensionClass: KClass get() = KotlinProjectExtension::class
internal open fun kotlinSourceSetFactory(project: Project): NamedDomainObjectFactory =
DefaultKotlinSourceSetFactory(project)
override fun apply(project: Project) {
val kotlinPluginVersion = project.getKotlinPluginVersion()
val statisticsReporter = KotlinBuildStatsService.getOrCreateInstance(project)
statisticsReporter?.report(StringMetrics.KOTLIN_COMPILER_VERSION, kotlinPluginVersion)
checkGradleCompatibility()
project.gradle.projectsEvaluated {
whenBuildEvaluated(project)
}
addKotlinCompilerConfiguration(project)
project.configurations.maybeCreate(PLUGIN_CLASSPATH_CONFIGURATION_NAME)
project.configurations.maybeCreate(NATIVE_COMPILER_PLUGIN_CLASSPATH_CONFIGURATION_NAME).apply {
isTransitive = false
}
project.registerCommonizerClasspathConfigurationIfNecessary()
KotlinGradleBuildServices.registerIfAbsent(project).get()
KotlinGradleBuildServices.detectKotlinPluginLoadedInMultipleProjects(project, kotlinPluginVersion)
project.createKotlinExtension(projectExtensionClass).apply {
coreLibrariesVersion = kotlinPluginVersion
fun kotlinSourceSetContainer(factory: NamedDomainObjectFactory) =
project.container(KotlinSourceSet::class.java, factory)
val topLevelExtension = project.topLevelExtension
if (topLevelExtension is KotlinProjectExtension) {
project.kotlinExtension.sourceSets = kotlinSourceSetContainer(kotlinSourceSetFactory(project))
}
}
project.extensions.add(KotlinTestsRegistry.PROJECT_EXTENSION_NAME, createTestRegistry(project))
val plugin = getPlugin(project)
setupAttributeMatchingStrategy(project)
plugin.apply(project)
project.addNpmDependencyExtension()
project.buildKotlinToolingMetadataTask
}
private fun addKotlinCompilerConfiguration(project: Project) {
project
.configurations
.maybeCreate(COMPILER_CLASSPATH_CONFIGURATION_NAME)
.defaultDependencies {
it.add(
project.dependencies.create("$KOTLIN_MODULE_GROUP:$KOTLIN_COMPILER_EMBEDDABLE:${project.getKotlinPluginVersion()}")
)
}
project
.tasks
.withType(AbstractKotlinCompile::class.java)
.configureEach { task ->
task.defaultCompilerClasspath.setFrom(
project.configurations.named(COMPILER_CLASSPATH_CONFIGURATION_NAME)
)
}
}
open fun whenBuildEvaluated(project: Project) {
}
internal open fun createTestRegistry(project: Project) = KotlinTestsRegistry(project)
private fun setupAttributeMatchingStrategy(project: Project) = with(project.dependencies.attributesSchema) {
KotlinPlatformType.setupAttributesMatchingStrategy(this)
KotlinUsages.setupAttributesMatchingStrategy(project, this)
KotlinJsCompilerAttribute.setupAttributesMatchingStrategy(project.dependencies.attributesSchema)
ProjectLocalConfigurations.setupAttributesMatchingStrategy(this)
CInteropKlibLibraryElements.setupAttributesMatchingStrategy(this)
}
internal abstract fun getPlugin(
project: Project,
): Plugin
}
open class KotlinPluginWrapper @Inject constructor(
protected val registry: ToolingModelBuilderRegistry
) : KotlinBasePluginWrapper() {
override fun getPlugin(project: Project): Plugin =
KotlinPlugin(registry)
override val projectExtensionClass: KClass
get() = KotlinJvmProjectExtension::class
}
open class KotlinCommonPluginWrapper @Inject constructor(
protected val registry: ToolingModelBuilderRegistry
) : KotlinBasePluginWrapper() {
override fun getPlugin(project: Project): Plugin =
KotlinCommonPlugin(registry)
override val projectExtensionClass: KClass
get() = KotlinCommonProjectExtension::class
}
open class KotlinAndroidPluginWrapper @Inject constructor(
protected val registry: ToolingModelBuilderRegistry
) : KotlinBasePluginWrapper() {
override fun getPlugin(project: Project): Plugin =
KotlinAndroidPlugin(registry)
override val projectExtensionClass: KClass
get() = KotlinAndroidProjectExtension::class
}
open class Kotlin2JsPluginWrapper @Inject constructor(
protected val registry: ToolingModelBuilderRegistry
) : KotlinBasePluginWrapper() {
override fun getPlugin(project: Project): Plugin =
Kotlin2JsPlugin(registry)
override val projectExtensionClass: KClass
get() = Kotlin2JsProjectExtension::class
}
open class KotlinJsPluginWrapper : KotlinBasePluginWrapper() {
override fun getPlugin(project: Project): Plugin =
KotlinJsPlugin(project.getKotlinPluginVersion())
override val projectExtensionClass: KClass
get() = KotlinJsProjectExtension::class
override fun whenBuildEvaluated(project: Project) = project.runProjectConfigurationHealthCheck {
val isJsTargetUninitialized = (project.kotlinExtension as KotlinJsProjectExtension)
._target == null
if (isJsTargetUninitialized) {
throw GradleException(
"""
Please initialize the Kotlin/JS target in '${project.name} (${project.path})'. Use:
kotlin {
js {
// To build distributions and run tests for browser or Node.js use one or both of:
browser()
nodejs()
}
}
Read more https://kotlinlang.org/docs/reference/js-project-setup.html
""".trimIndent()
)
}
}
override fun createTestRegistry(project: Project) = KotlinTestsRegistry(project, "test")
}
open class KotlinMultiplatformPluginWrapper : KotlinBasePluginWrapper() {
override fun getPlugin(project: Project): Plugin =
KotlinMultiplatformPlugin()
override val projectExtensionClass: KClass
get() = KotlinMultiplatformExtension::class
override fun whenBuildEvaluated(project: Project) = project.runProjectConfigurationHealthCheck {
val isNoTargetsInitialized = (project.kotlinExtension as KotlinMultiplatformExtension)
.targets
.none { it !is KotlinMetadataTarget }
if (isNoTargetsInitialized) {
throw GradleException(
"""
Please initialize at least one Kotlin target in '${project.name} (${project.path})'.
Read more https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#setting-up-targets
""".trimIndent()
)
}
}
}
open class KotlinPm20PluginWrapper @Inject constructor(
private val objectFactory: ObjectFactory
) : KotlinBasePluginWrapper() {
override fun getPlugin(project: Project): Plugin =
objectFactory.newInstance(KotlinPm20GradlePlugin::class.java)
override val projectExtensionClass: KClass
get() = KotlinPm20ProjectExtension::class
}
@Deprecated(
message = "Scheduled to be removed in 1.7 release",
replaceWith = ReplaceWith(
"project.getKotlinPluginVersion()",
"org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion"
)
)
fun Plugin<*>.loadKotlinVersionFromResource(log: Logger): String {
log.kotlinDebug("Loading version information")
val projectVersion = loadPropertyFromResources("project.properties", "project.version")
log.kotlinDebug("Found project version [$projectVersion]")
return projectVersion
}
fun Project.getKotlinPluginVersion(): String {
if (!kotlinPluginVersionFromResources.isInitialized()) {
project.logger.kotlinDebug("Loading version information")
project.logger.kotlinDebug("Found project version [${kotlinPluginVersionFromResources.value}")
}
return kotlinPluginVersionFromResources.value
}
private fun loadKotlinPluginVersionFromResourcesOf(any: Any) =
any.loadPropertyFromResources("project.properties", "project.version")
private val kotlinPluginVersionFromResources = lazy {
loadKotlinPluginVersionFromResourcesOf(object {})
}