org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformSourceSetConventions.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.dsl
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.NamedDomainObjectProvider
import org.jetbrains.kotlin.gradle.dsl.KotlinSourceSetConvention.isRegisteredByKotlinSourceSetConventionAt
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectChecker
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectCheckerContext
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics.AndroidMainSourceSetConventionUsedWithoutAndroidTarget
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics.IosSourceSetConventionUsedWithoutIosTarget
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics.PlatformSourceSetConventionUsedWithCustomTargetName
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics.PlatformSourceSetConventionUsedWithoutCorrespondingTarget
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnosticsCollector
import org.jetbrains.kotlin.gradle.plugin.diagnostics.reportDiagnostic
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
import org.jetbrains.kotlin.konan.target.Family
@KotlinGradlePluginDsl
interface KotlinMultiplatformSourceSetConventions {
val NamedDomainObjectContainer.commonMain: NamedDomainObjectProvider
val NamedDomainObjectContainer.commonTest: NamedDomainObjectProvider
val NamedDomainObjectContainer.nativeMain: NamedDomainObjectProvider
val NamedDomainObjectContainer.nativeTest: NamedDomainObjectProvider
val NamedDomainObjectContainer.appleMain: NamedDomainObjectProvider
val NamedDomainObjectContainer.appleTest: NamedDomainObjectProvider
val NamedDomainObjectContainer.iosMain: NamedDomainObjectProvider
val NamedDomainObjectContainer.iosTest: NamedDomainObjectProvider
val NamedDomainObjectContainer.tvosMain: NamedDomainObjectProvider
val NamedDomainObjectContainer.tvosTest: NamedDomainObjectProvider
val NamedDomainObjectContainer.watchosMain: NamedDomainObjectProvider
val NamedDomainObjectContainer.watchosTest: NamedDomainObjectProvider
val NamedDomainObjectContainer.macosMain: NamedDomainObjectProvider
val NamedDomainObjectContainer.macosTest: NamedDomainObjectProvider
val NamedDomainObjectContainer.linuxMain: NamedDomainObjectProvider
val NamedDomainObjectContainer.linuxTest: NamedDomainObjectProvider
val NamedDomainObjectContainer.mingwMain: NamedDomainObjectProvider
val NamedDomainObjectContainer.mingwTest: NamedDomainObjectProvider
val NamedDomainObjectContainer.androidNativeMain: NamedDomainObjectProvider
val NamedDomainObjectContainer.androidNativeTest: NamedDomainObjectProvider
val NamedDomainObjectContainer.jvmMain: NamedDomainObjectProvider
val NamedDomainObjectContainer.jvmTest: NamedDomainObjectProvider
val NamedDomainObjectContainer.jsMain: NamedDomainObjectProvider
val NamedDomainObjectContainer.jsTest: NamedDomainObjectProvider
val NamedDomainObjectContainer.androidMain: NamedDomainObjectProvider
operator fun NamedDomainObjectProvider.invoke(
configure: KotlinSourceSet.() -> Unit,
): Unit = get().run(configure)
fun NamedDomainObjectProvider.dependencies(
handler: KotlinDependencyHandler.() -> Unit,
): Unit = get().dependencies(handler)
fun NamedDomainObjectProvider.languageSettings(
configure: LanguageSettingsBuilder.() -> Unit,
): Unit = this { languageSettings(configure) }
}
/* Implementation */
internal object KotlinMultiplatformSourceSetConventionsImpl : KotlinMultiplatformSourceSetConventions {
override val NamedDomainObjectContainer.commonMain by KotlinSourceSetConvention
override val NamedDomainObjectContainer.commonTest by KotlinSourceSetConvention
override val NamedDomainObjectContainer.nativeMain by KotlinSourceSetConvention
override val NamedDomainObjectContainer.nativeTest by KotlinSourceSetConvention
override val NamedDomainObjectContainer.appleMain by KotlinSourceSetConvention
override val NamedDomainObjectContainer.appleTest by KotlinSourceSetConvention
override val NamedDomainObjectContainer.iosMain by KotlinSourceSetConvention
override val NamedDomainObjectContainer.iosTest by KotlinSourceSetConvention
override val NamedDomainObjectContainer.tvosMain by KotlinSourceSetConvention
override val NamedDomainObjectContainer.tvosTest by KotlinSourceSetConvention
override val NamedDomainObjectContainer.watchosMain by KotlinSourceSetConvention
override val NamedDomainObjectContainer.watchosTest by KotlinSourceSetConvention
override val NamedDomainObjectContainer.macosMain by KotlinSourceSetConvention
override val NamedDomainObjectContainer.macosTest by KotlinSourceSetConvention
override val NamedDomainObjectContainer.linuxMain by KotlinSourceSetConvention
override val NamedDomainObjectContainer.linuxTest by KotlinSourceSetConvention
override val NamedDomainObjectContainer.mingwMain by KotlinSourceSetConvention
override val NamedDomainObjectContainer.mingwTest by KotlinSourceSetConvention
override val NamedDomainObjectContainer.androidNativeMain by KotlinSourceSetConvention
override val NamedDomainObjectContainer.androidNativeTest by KotlinSourceSetConvention
override val NamedDomainObjectContainer.jvmMain by KotlinSourceSetConvention
override val NamedDomainObjectContainer.jvmTest by KotlinSourceSetConvention
override val NamedDomainObjectContainer.jsMain by KotlinSourceSetConvention
override val NamedDomainObjectContainer.jsTest by KotlinSourceSetConvention
override val NamedDomainObjectContainer.androidMain by KotlinSourceSetConvention
}
/* Checkers */
internal object PlatformSourceSetConventionsChecker : KotlinGradleProjectChecker {
data class CheckedPlatformInfo(
val expectedTargetName: String,
val expectedTargetType: Class,
)
override suspend fun KotlinGradleProjectCheckerContext.runChecks(collector: KotlinToolingDiagnosticsCollector) {
listOf(
CheckedPlatformInfo("js", KotlinJsTargetDsl::class.java),
CheckedPlatformInfo("jvm", KotlinJvmTarget::class.java)
).forEach { checkedPlatformInfo -> runChecks(checkedPlatformInfo) }
}
private suspend fun KotlinGradleProjectCheckerContext.runChecks(platform: CheckedPlatformInfo) {
val kotlin = project.multiplatformExtensionOrNull ?: return
val sourceSets = kotlin.awaitSourceSets()
/* Find jvmMain and jvmTest source sets that have been registered by the convention */
val platformSourceSets = listOfNotNull(
sourceSets.findByName("${platform.expectedTargetName}Main"),
sourceSets.findByName("${platform.expectedTargetName}Test")
)
.filter { it.isRegisteredByKotlinSourceSetConventionAt != null }
.ifEmpty { return }
/* Check if a custom target name was used */
val customNamedTarget = kotlin.targets.withType(platform.expectedTargetType)
.firstOrNull { target -> target.name != platform.expectedTargetName }
if (customNamedTarget != null) {
platformSourceSets.forEach { sourceSet ->
project.reportDiagnostic(
PlatformSourceSetConventionUsedWithCustomTargetName(sourceSet, customNamedTarget, platform.expectedTargetName)
)
}
} else if (kotlin.targets.findByName(platform.expectedTargetName) == null) {
platformSourceSets.forEach { sourceSet ->
project.reportDiagnostic(
PlatformSourceSetConventionUsedWithoutCorrespondingTarget(sourceSet, platform.expectedTargetName)
)
}
}
}
}
internal object AndroidMainSourceSetConventionsChecker : KotlinGradleProjectChecker {
override suspend fun KotlinGradleProjectCheckerContext.runChecks(collector: KotlinToolingDiagnosticsCollector) {
val kotlin = project.multiplatformExtensionOrNull ?: return
val androidMainSourceSet = kotlin.awaitSourceSets().findByName("androidMain") ?: return
if (androidMainSourceSet.isRegisteredByKotlinSourceSetConventionAt == null) return
val androidTarget = kotlin.awaitTargets().findByName("android")
if (androidTarget == null) {
project.reportDiagnostic(AndroidMainSourceSetConventionUsedWithoutAndroidTarget(androidMainSourceSet))
}
}
}
internal object IosSourceSetConventionChecker : KotlinGradleProjectChecker {
override suspend fun KotlinGradleProjectCheckerContext.runChecks(collector: KotlinToolingDiagnosticsCollector) {
val kotlin = project.multiplatformExtensionOrNull ?: return
val iosSourceSets = listOf("iosMain", "iosTest")
.mapNotNull { sourceSetName -> kotlin.awaitSourceSets().findByName(sourceSetName) }
.filter { it.isRegisteredByKotlinSourceSetConventionAt != null }
val hasIosTarget = kotlin.awaitTargets()
.any { target -> target is KotlinNativeTarget && target.konanTarget.family == Family.IOS }
if (!hasIosTarget) {
iosSourceSets.forEach { sourceSet ->
project.reportDiagnostic(IosSourceSetConventionUsedWithoutIosTarget(sourceSet))
}
}
}
}