[Gradle][KT-53342] Implement Multiplatform/Android V2 source set layout
^KT-53342 Verification Pending
This commit is contained in:
committed by
Space
parent
38ada5c9fc
commit
fe5a4bb12a
Generated
+4
-1
@@ -8,4 +8,7 @@
|
||||
<component name="KotlinCompilerSettings">
|
||||
<option name="additionalArguments" value="-version -Xallow-kotlin-package -Xskip-metadata-version-check" />
|
||||
</component>
|
||||
</project>
|
||||
<component name="KotlinJpsPluginSettings">
|
||||
<option name="version" value="1.8.0-dev-1006" />
|
||||
</component>
|
||||
</project>
|
||||
+10
-29
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.internal
|
||||
|
||||
import com.android.build.gradle.TestedExtension
|
||||
import com.android.build.gradle.api.TestVariant
|
||||
import com.android.build.gradle.api.UnitTestVariant
|
||||
import org.gradle.api.InvalidUserDataException
|
||||
@@ -27,10 +26,12 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmModule
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.hasKpmModel
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.kpmModules
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.android.AndroidBaseSourceSetName
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.android.AndroidVariantType
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.android.androidSourceSetInfoOrNull
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.dependsOnClosure
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.withDependsOnClosure
|
||||
import org.jetbrains.kotlin.gradle.targets.android.findAndroidTarget
|
||||
import org.jetbrains.kotlin.gradle.targets.jvm.JvmCompilationsTestRunSource
|
||||
import org.jetbrains.kotlin.gradle.tasks.locateTask
|
||||
import org.jetbrains.kotlin.gradle.testing.KotlinTaskTestRun
|
||||
@@ -112,10 +113,7 @@ internal fun configureStdlibDefaultDependency(project: Project) = with(project)
|
||||
|
||||
project.tryWithDependenciesIfUnresolved(scopeConfiguration) { dependencies ->
|
||||
val scopeToAddStdlibDependency =
|
||||
if (isRelatedToAndroidTestSourceSet(
|
||||
project,
|
||||
kotlinSourceSet
|
||||
)
|
||||
if (isRelatedToAndroidTestSourceSet(kotlinSourceSet)
|
||||
) // AGP deprecates API configurations in test source sets
|
||||
KotlinDependencyScope.IMPLEMENTATION_SCOPE
|
||||
else KotlinDependencyScope.API_SCOPE
|
||||
@@ -195,7 +193,9 @@ private fun chooseAndAddStdlibDependency(
|
||||
val stdlibModuleName = when (sourceSetStdlibPlatformType) {
|
||||
KotlinPlatformType.jvm -> stdlibModuleForJvmCompilations(compilations)
|
||||
KotlinPlatformType.androidJvm ->
|
||||
if (kotlinSourceSet.name == androidMainSourceSetName(project)) stdlibModuleForJvmCompilations(compilations) else null
|
||||
if (kotlinSourceSet.androidSourceSetInfoOrNull?.androidSourceSetName == AndroidBaseSourceSetName.Main.name)
|
||||
stdlibModuleForJvmCompilations(compilations) else null
|
||||
|
||||
KotlinPlatformType.js -> "kotlin-stdlib-js"
|
||||
KotlinPlatformType.wasm -> "kotlin-stdlib-wasm"
|
||||
KotlinPlatformType.native -> null
|
||||
@@ -214,28 +214,9 @@ private fun chooseAndAddStdlibDependency(
|
||||
}
|
||||
}
|
||||
|
||||
private fun androidMainSourceSetName(project: Project): String {
|
||||
val target = project.findAndroidTarget() ?: error("No Android target found")
|
||||
return AndroidProjectHandler.kotlinSourceSetNameForAndroidSourceSet(target, "main")
|
||||
}
|
||||
|
||||
private fun isRelatedToAndroidTestSourceSet(project: Project, kotlinSourceSet: KotlinSourceSet): Boolean {
|
||||
val androidExtension = project.extensions.findByName("android") as? TestedExtension ?: return false
|
||||
val androidTarget = project.findAndroidTarget() ?: return false
|
||||
|
||||
if (androidTarget.compilations.any {
|
||||
(it.androidVariant is UnitTestVariant || it.androidVariant is TestVariant) && it.defaultSourceSet === kotlinSourceSet
|
||||
}
|
||||
) return true
|
||||
|
||||
(androidExtension.testVariants + androidExtension.unitTestVariants).forEach { variant ->
|
||||
if (variant.sourceSets.any {
|
||||
kotlinSourceSet.name == AndroidProjectHandler.kotlinSourceSetNameForAndroidSourceSet(androidTarget, it.name)
|
||||
}
|
||||
) return true
|
||||
}
|
||||
|
||||
return false
|
||||
private fun isRelatedToAndroidTestSourceSet(kotlinSourceSet: KotlinSourceSet): Boolean {
|
||||
val androidVariantType = kotlinSourceSet.androidSourceSetInfoOrNull?.androidVariantType ?: return false
|
||||
return androidVariantType in setOf(AndroidVariantType.UnitTest, AndroidVariantType.InstrumentedTest)
|
||||
}
|
||||
|
||||
private val stdlibModules = setOf("kotlin-stdlib-common", "kotlin-stdlib", "kotlin-stdlib-jdk7", "kotlin-stdlib-jdk8", "kotlin-stdlib-js")
|
||||
|
||||
+1
-1
@@ -191,7 +191,7 @@ open class KotlinPlatformImplementationPluginBase(platformName: String) : Kotlin
|
||||
@Deprecated("Migrate to the new Kotlin source sets and use the addCommonSourceSetToPlatformSourceSet(Named, Project) overload")
|
||||
protected open fun addCommonSourceSetToPlatformSourceSet(sourceSet: SourceSet, platformProject: Project) = Unit
|
||||
|
||||
@Deprecated("Retained for older Kotlin/Native MPP plugin binary compatibility")
|
||||
@Deprecated("Retained for older Kotlin/Native MPP plugin binary compatibility", level = DeprecationLevel.ERROR)
|
||||
protected val SourceSet.kotlin: SourceDirectorySet?
|
||||
get() {
|
||||
@Suppress("DEPRECATION")
|
||||
|
||||
+5
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessageOutputStream
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType.Companion.jsCompilerProperty
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_ABI_SNAPSHOT
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ANDROID_GRADLE_PLUGIN_COMPATIBILITY_NO_WARN
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ANDROID_SOURCE_SET_LAYOUT_VERSION
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ENABLE_CINTEROP_COMMONIZATION
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ENABLE_GRANULAR_SOURCE_SETS_METADATA
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ENABLE_OPTIMISTIC_NUMBER_COMMONIZATION
|
||||
@@ -209,6 +210,9 @@ internal class PropertiesProvider private constructor(private val project: Proje
|
||||
val ignoreAndroidGradlePluginCompatibilityIssues: Boolean
|
||||
get() = booleanProperty(KOTLIN_MPP_ANDROID_GRADLE_PLUGIN_COMPATIBILITY_NO_WARN) ?: false
|
||||
|
||||
val mppAndroidSourceSetLayoutVersion: Int?
|
||||
get() = property(KOTLIN_MPP_ANDROID_SOURCE_SET_LAYOUT_VERSION)?.toIntOrNull()
|
||||
|
||||
val ignoreDisabledCInteropCommonization: Boolean
|
||||
get() = booleanProperty("$KOTLIN_MPP_ENABLE_CINTEROP_COMMONIZATION.nowarn") ?: false
|
||||
|
||||
@@ -467,6 +471,7 @@ internal class PropertiesProvider private constructor(private val project: Proje
|
||||
const val KOTLIN_MPP_HIERARCHICAL_STRUCTURE_BY_DEFAULT = "kotlin.internal.mpp.hierarchicalStructureByDefault"
|
||||
const val KOTLIN_MPP_HIERARCHICAL_STRUCTURE_SUPPORT = "kotlin.mpp.hierarchicalStructureSupport"
|
||||
const val KOTLIN_MPP_ANDROID_GRADLE_PLUGIN_COMPATIBILITY_NO_WARN = "kotlin.mpp.androidGradlePluginCompatibility.nowarn"
|
||||
const val KOTLIN_MPP_ANDROID_SOURCE_SET_LAYOUT_VERSION = "kotlin.mpp.androidSourceSetLayoutVersion"
|
||||
const val KOTLIN_NATIVE_DEPENDENCY_PROPAGATION = "kotlin.native.enableDependencyPropagation"
|
||||
const val KOTLIN_MPP_ENABLE_OPTIMISTIC_NUMBER_COMMONIZATION = "kotlin.mpp.enableOptimisticNumberCommonization"
|
||||
const val KOTLIN_KPM_EXPERIMENTAL_MODEL_MAPPING = "kotlin.kpm.experimentalModelMapping"
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ internal fun addCompilationSourcesToExternalCompileTask(
|
||||
task: TaskProvider<out AbstractKotlinCompileTool<*>>
|
||||
) {
|
||||
if (compilation is KotlinJvmAndroidCompilation) {
|
||||
compilation.androidVariant.forEachKotlinSourceDirectorySet { sourceSet ->
|
||||
compilation.androidVariant.forEachKotlinSourceDirectorySet(compilation.project) { sourceSet ->
|
||||
task.configure { it.setSource(sourceSet) }
|
||||
}
|
||||
compilation.androidVariant.forEachJavaSourceDir { sources ->
|
||||
|
||||
+4
-6
@@ -9,6 +9,7 @@ import org.gradle.api.Project
|
||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.extraProperties
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.android.androidSourceSetInfoOrNull
|
||||
import org.jetbrains.kotlin.gradle.plugin.whenEvaluated
|
||||
|
||||
object UnusedSourceSetsChecker {
|
||||
@@ -39,13 +40,10 @@ object UnusedSourceSetsChecker {
|
||||
fun checkSourceSets(project: Project) {
|
||||
project.whenEvaluated {
|
||||
val compilationsBySourceSet = CompilationSourceSetUtil.compilationsBySourceSets(project)
|
||||
val unusedSourceSets = project.kotlinExtension.sourceSets.filter {
|
||||
val unusedSourceSets = project.kotlinExtension.sourceSets
|
||||
// Ignoring Android source sets
|
||||
val isAndroidSourceSet = it.extraProperties.has(IS_ANDROID_SOURCE_SET) &&
|
||||
(it.extraProperties[IS_ANDROID_SOURCE_SET] as Boolean)
|
||||
|
||||
!isAndroidSourceSet && compilationsBySourceSet[it]?.isEmpty() ?: true
|
||||
}
|
||||
.filter { it.androidSourceSetInfoOrNull == null }
|
||||
.filter { compilationsBySourceSet[it]?.isEmpty() ?: true }
|
||||
if (unusedSourceSets.isNotEmpty()) {
|
||||
reportUnusedSourceSets(project, unusedSourceSets.toSet())
|
||||
}
|
||||
|
||||
-148
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.plugin.mpp
|
||||
|
||||
import com.android.build.gradle.BaseExtension
|
||||
import com.android.build.gradle.api.AndroidSourceSet
|
||||
import org.gradle.api.file.SourceDirectorySet
|
||||
import org.gradle.api.internal.plugins.DslObject
|
||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin
|
||||
import org.jetbrains.kotlin.gradle.plugin.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.AndroidProjectHandler.Companion.kotlinSourceSetNameForAndroidSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinSourceSetFactory.Companion.defaultSourceFolder
|
||||
|
||||
internal const val IS_ANDROID_SOURCE_SET = "android-source-set"
|
||||
|
||||
internal fun syncKotlinAndAndroidSourceSets(target: KotlinAndroidTarget) {
|
||||
val project = target.project
|
||||
val android = project.extensions.getByName("android") as BaseExtension
|
||||
val kotlinExtension = project.kotlinExtension
|
||||
|
||||
val createdKotlinSourceSets = mutableSetOf<String>()
|
||||
android.sourceSets.all { androidSourceSet ->
|
||||
val kotlinSourceSetName = kotlinSourceSetNameForAndroidSourceSet(target, androidSourceSet.name)
|
||||
createdKotlinSourceSets.add(kotlinSourceSetName)
|
||||
val kotlinSourceSet = kotlinExtension.sourceSets.maybeCreate(kotlinSourceSetName)
|
||||
|
||||
// Marking KotlinSource set is created for Android compilation to ignore it in UnusedSourceSetChecker
|
||||
kotlinSourceSet.extraProperties.set(IS_ANDROID_SOURCE_SET, true)
|
||||
|
||||
androidSourceSet.addKotlinSources(kotlinSourceSet)
|
||||
|
||||
createDefaultDependsOnEdges(target, kotlinSourceSet, androidSourceSet)
|
||||
syncKotlinAndAndroidSourceDirs(target, kotlinSourceSet, androidSourceSet)
|
||||
syncKotlinAndAndroidResources(target, kotlinSourceSet, androidSourceSet)
|
||||
|
||||
ifKaptEnabled(project) {
|
||||
Kapt3GradleSubplugin.createAptConfigurationIfNeeded(project, androidSourceSet.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal val AndroidSourceSet.kotlinSourceSet: SourceDirectorySet
|
||||
get() = checkNotNull(getExtension(KOTLIN_DSL_NAME)) { "Missing kotlinSourceSet for Android source set $name" }
|
||||
|
||||
internal fun AndroidSourceSet.addKotlinSources(kotlinSourceSet: KotlinSourceSet) {
|
||||
@Suppress("DEPRECATION") addConvention(KOTLIN_DSL_NAME, kotlinSourceSet)
|
||||
DslObject(this).addExtension(KOTLIN_DSL_NAME, kotlinSourceSet.kotlin)
|
||||
}
|
||||
|
||||
private fun createDefaultDependsOnEdges(
|
||||
target: KotlinAndroidTarget,
|
||||
kotlinSourceSet: KotlinSourceSet,
|
||||
androidSourceSet: AndroidSourceSet
|
||||
) {
|
||||
val commonSourceSetName = when (androidSourceSet.name) {
|
||||
"main" -> "commonMain"
|
||||
"test" -> "commonTest"
|
||||
"androidTest" -> "commonTest"
|
||||
else -> return
|
||||
}
|
||||
val commonSourceSet = target.project.kotlinExtension.sourceSets.findByName(commonSourceSetName) ?: return
|
||||
kotlinSourceSet.dependsOn(commonSourceSet)
|
||||
}
|
||||
|
||||
private fun syncKotlinAndAndroidSourceDirs(
|
||||
target: KotlinAndroidTarget, kotlinSourceSet: KotlinSourceSet, androidSourceSet: AndroidSourceSet
|
||||
) {
|
||||
val disambiguationClassifier = target.disambiguationClassifier
|
||||
|
||||
/*
|
||||
Mitigate ambiguity!
|
||||
Example: disambiguationClassifier="android"
|
||||
Source Directory "src/androidTest/kotlin"
|
||||
-- could be claimed by kotlin {android}Test (unit test)
|
||||
-- could be claimed by Android androidTest (instrumented test)
|
||||
|
||||
The Kotlin source set would win in this scenario.
|
||||
*/
|
||||
if (!androidSourceSet.name.startsWith(disambiguationClassifier)) {
|
||||
kotlinSourceSet.kotlin.srcDir("src/${androidSourceSet.name}/kotlin")
|
||||
}
|
||||
|
||||
kotlinSourceSet.kotlin.srcDirs(*androidSourceSet.java.srcDirs.toTypedArray())
|
||||
|
||||
/*
|
||||
Make sure to include user configuration as well.
|
||||
Unfortunately, there does not exist any "ad-hoc" API like `all`.
|
||||
Therefore we sync the directories once again after evaluation
|
||||
*/
|
||||
target.project.whenEvaluated {
|
||||
kotlinSourceSet.kotlin.srcDirs(*androidSourceSet.java.srcDirs.toTypedArray())
|
||||
}
|
||||
}
|
||||
|
||||
private fun syncKotlinAndAndroidResources(
|
||||
target: KotlinAndroidTarget,
|
||||
kotlinSourceSet: KotlinSourceSet,
|
||||
androidSourceSet: AndroidSourceSet
|
||||
) {
|
||||
/*
|
||||
Non-MPP projects will not have a different name for kotlin source sets vs Android source sets
|
||||
Registering resource folders is unnecessary therefore.
|
||||
*/
|
||||
if (kotlinSourceSet.name == androidSourceSet.name) {
|
||||
return
|
||||
}
|
||||
|
||||
val project = target.project
|
||||
|
||||
androidSourceSet.resources.srcDirs(kotlinSourceSet.resources.srcDirs)
|
||||
if (androidSourceSet.resources.srcDirs.isNotEmpty()) {
|
||||
androidSourceSet.resources.srcDir(defaultSourceFolder(project, kotlinSourceSet.name, "resources"))
|
||||
kotlinSourceSet.resources.srcDirs(androidSourceSet.resources.srcDirs)
|
||||
}
|
||||
|
||||
if (androidSourceSet.assets.srcDirs.isNotEmpty()) {
|
||||
androidSourceSet.assets.srcDir(defaultSourceFolder(project, kotlinSourceSet.name, "assets"))
|
||||
}
|
||||
|
||||
if (androidSourceSet.res.srcDirs.isNotEmpty()) {
|
||||
androidSourceSet.res.srcDir(defaultSourceFolder(project, kotlinSourceSet.name, "res"))
|
||||
}
|
||||
|
||||
if (androidSourceSet.aidl.srcDirs.isNotEmpty()) {
|
||||
androidSourceSet.aidl.srcDir(defaultSourceFolder(project, kotlinSourceSet.name, "aidl"))
|
||||
}
|
||||
|
||||
if (androidSourceSet.renderscript.srcDirs.isNotEmpty()) {
|
||||
androidSourceSet.renderscript.srcDir(defaultSourceFolder(project, kotlinSourceSet.name, "rs"))
|
||||
}
|
||||
|
||||
if (androidSourceSet.jni.srcDirs.isNotEmpty()) {
|
||||
androidSourceSet.jni.srcDir(defaultSourceFolder(project, kotlinSourceSet.name, "jni"))
|
||||
}
|
||||
|
||||
if (androidSourceSet.jniLibs.srcDirs.isNotEmpty()) {
|
||||
androidSourceSet.jniLibs.srcDir(defaultSourceFolder(project, kotlinSourceSet.name, "jniLibs"))
|
||||
}
|
||||
|
||||
if (androidSourceSet.shaders.srcDirs.isNotEmpty()) {
|
||||
androidSourceSet.shaders.srcDir(defaultSourceFolder(project, kotlinSourceSet.name, "shaders"))
|
||||
}
|
||||
}
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android
|
||||
|
||||
import com.android.build.gradle.api.AndroidSourceSet
|
||||
import org.gradle.api.NamedDomainObjectContainer
|
||||
|
||||
internal val NamedDomainObjectContainer<out AndroidSourceSet>.main: AndroidSourceSet
|
||||
get() = getByName(AndroidBaseSourceSetName.Main.name)
|
||||
|
||||
internal val NamedDomainObjectContainer<out AndroidSourceSet>.test: AndroidSourceSet
|
||||
get() = getByName(AndroidBaseSourceSetName.Test.name)
|
||||
|
||||
internal val NamedDomainObjectContainer<out AndroidSourceSet>.androidTest: AndroidSourceSet
|
||||
get() = getByName(AndroidBaseSourceSetName.AndroidTest.name)
|
||||
|
||||
/*
|
||||
Not written as enum class to avoid Enum.name ambiguity with 'source set name' semantics.
|
||||
*/
|
||||
internal sealed class AndroidBaseSourceSetName(val name: String) {
|
||||
final override fun toString(): String = name
|
||||
|
||||
object Main : AndroidBaseSourceSetName("main")
|
||||
object Test : AndroidBaseSourceSetName("test")
|
||||
object AndroidTest : AndroidBaseSourceSetName("androidTest")
|
||||
|
||||
companion object {
|
||||
fun byName(name: String): AndroidBaseSourceSetName? = when (name) {
|
||||
Main.name -> Main
|
||||
Test.name -> Test
|
||||
AndroidTest.name -> AndroidTest
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android
|
||||
|
||||
import com.android.build.gradle.api.*
|
||||
|
||||
internal val BaseVariant.type: AndroidVariantType
|
||||
get() = when (this) {
|
||||
is UnitTestVariant -> AndroidVariantType.UnitTest
|
||||
is TestVariant -> AndroidVariantType.InstrumentedTest
|
||||
is ApplicationVariant, is LibraryVariant -> AndroidVariantType.Main
|
||||
else -> AndroidVariantType.Unknown
|
||||
}
|
||||
|
||||
internal val AndroidBaseSourceSetName.variantType: AndroidVariantType
|
||||
get() = when (this) {
|
||||
AndroidBaseSourceSetName.Main -> AndroidVariantType.Main
|
||||
AndroidBaseSourceSetName.Test -> AndroidVariantType.UnitTest
|
||||
AndroidBaseSourceSetName.AndroidTest -> AndroidVariantType.InstrumentedTest
|
||||
}
|
||||
|
||||
internal enum class AndroidVariantType {
|
||||
Main, UnitTest, InstrumentedTest, Unknown;
|
||||
|
||||
/**
|
||||
* Every known type of Android variant has a 'base source set', which
|
||||
* participates in all variants of sad type (main, test, androidTest, ...)
|
||||
*/
|
||||
val androidBaseSourceSetName: AndroidBaseSourceSetName?
|
||||
get() = when (this) {
|
||||
Main -> AndroidBaseSourceSetName.Main
|
||||
UnitTest -> AndroidBaseSourceSetName.Test
|
||||
InstrumentedTest -> AndroidBaseSourceSetName.AndroidTest
|
||||
Unknown -> null
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android
|
||||
|
||||
import com.android.build.gradle.BaseExtension
|
||||
import com.android.build.gradle.api.AndroidSourceSet
|
||||
import com.android.builder.model.SourceProvider
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.UnknownDomainObjectException
|
||||
import org.gradle.api.plugins.ExtensionAware
|
||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtensionOrNull
|
||||
import org.jetbrains.kotlin.gradle.plugin.ExperimentalKotlinGradlePluginApi
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.utils.findByType
|
||||
|
||||
@ExperimentalKotlinGradlePluginApi
|
||||
val KotlinSourceSet.androidSourceSetInfoOrNull: KotlinAndroidSourceSetInfo?
|
||||
get() = (this as? ExtensionAware)?.extensions?.findByType()
|
||||
|
||||
@ExperimentalKotlinGradlePluginApi
|
||||
var KotlinSourceSet.androidSourceSetInfo: KotlinAndroidSourceSetInfo
|
||||
get() = androidSourceSetInfoOrNull ?: throw UnknownDomainObjectException("No 'androidSourceSetInfo' found on KotlinSourceSet: $name")
|
||||
internal set(value) {
|
||||
(this as ExtensionAware).extensions.add("androidSourceSetInfo", value)
|
||||
}
|
||||
|
||||
@ExperimentalKotlinGradlePluginApi
|
||||
fun Project.findAndroidSourceSet(kotlinSourceSet: KotlinSourceSet): AndroidSourceSet? {
|
||||
val androidSourceSetInfo = kotlinSourceSet.androidSourceSetInfoOrNull ?: return null
|
||||
val android = extensions.findByType<BaseExtension>() ?: return null
|
||||
return android.sourceSets.getByName(androidSourceSetInfo.androidSourceSetName)
|
||||
}
|
||||
|
||||
@ExperimentalKotlinGradlePluginApi
|
||||
fun Project.findKotlinSourceSet(androidSourceSet: AndroidSourceSet): KotlinSourceSet? {
|
||||
return findKotlinSourceSet(androidSourceSet.name)
|
||||
}
|
||||
|
||||
@ExperimentalKotlinGradlePluginApi
|
||||
fun Project.findKotlinSourceSet(androidSourceSet: SourceProvider): KotlinSourceSet? {
|
||||
return findKotlinSourceSet(androidSourceSet.name)
|
||||
}
|
||||
|
||||
private fun Project.findKotlinSourceSet(androidSourceSetName: String): KotlinSourceSet? {
|
||||
return kotlinExtensionOrNull?.sourceSets.orEmpty()
|
||||
.find { kotlinSourceSet -> kotlinSourceSet.androidSourceSetInfoOrNull?.androidSourceSetName == androidSourceSetName }
|
||||
}
|
||||
|
||||
@ExperimentalKotlinGradlePluginApi
|
||||
sealed class KotlinAndroidSourceSetInfo {
|
||||
abstract val kotlinSourceSetName: String
|
||||
abstract val androidSourceSetName: String
|
||||
internal abstract val androidVariantType: AndroidVariantType
|
||||
abstract val androidVariantNames: Set<String>
|
||||
|
||||
internal data class Mutable(
|
||||
override val kotlinSourceSetName: String,
|
||||
override val androidSourceSetName: String,
|
||||
override var androidVariantType: AndroidVariantType = AndroidVariantType.Unknown,
|
||||
override val androidVariantNames: MutableSet<String> = mutableSetOf()
|
||||
) : KotlinAndroidSourceSetInfo()
|
||||
|
||||
internal fun asMutable(): Mutable = when (this) {
|
||||
is Mutable -> this
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android
|
||||
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.android.configurator.*
|
||||
|
||||
internal data class KotlinAndroidSourceSetLayout(
|
||||
val name: String,
|
||||
val naming: KotlinAndroidSourceSetNaming,
|
||||
val sourceSetConfigurator: KotlinAndroidSourceSetConfigurator
|
||||
) {
|
||||
override fun toString(): String = "KotlinAndroidSourceSetLayout: $name"
|
||||
}
|
||||
|
||||
internal val singleTargetAndroidSourceSetLayout = KotlinAndroidSourceSetLayout(
|
||||
name = "Kotlin/Android",
|
||||
naming = SingleTargetKotlinAndroidSourceSetNaming,
|
||||
sourceSetConfigurator = KotlinAndroidSourceSetConfigurator(
|
||||
KotlinAndroidSourceSetInfoConfigurator,
|
||||
AndroidKaptSourceSetConfigurator,
|
||||
AndroidSourceSetConventionConfigurator,
|
||||
SingleTargetSourceDirConfigurator,
|
||||
)
|
||||
)
|
||||
|
||||
internal val multiplatformAndroidSourceSetLayoutV1 = KotlinAndroidSourceSetLayout(
|
||||
name = "Multiplatform/Android V1",
|
||||
naming = MultiplatformLayoutV1KotlinAndroidSourceSetNaming,
|
||||
sourceSetConfigurator = KotlinAndroidSourceSetConfigurator(
|
||||
KotlinAndroidSourceSetInfoConfigurator,
|
||||
AndroidKaptSourceSetConfigurator,
|
||||
AndroidSourceSetConventionConfigurator,
|
||||
MultiplatformAndroidResourceDirConfigurator,
|
||||
MultiplatformLayoutV1DependsOnConfigurator,
|
||||
MultiplatformLayoutV1SourceDirConfigurator
|
||||
)
|
||||
)
|
||||
|
||||
internal val multiplatformAndroidSourceSetLayoutV2 = KotlinAndroidSourceSetLayout(
|
||||
name = "Multiplatform/Android V2",
|
||||
naming = MultiplatformLayoutV2KotlinAndroidSourceSetNaming,
|
||||
sourceSetConfigurator = KotlinAndroidSourceSetConfigurator(
|
||||
KotlinAndroidSourceSetInfoConfigurator,
|
||||
AndroidKaptSourceSetConfigurator,
|
||||
MultiplatformAndroidResourceDirConfigurator,
|
||||
MultiplatformLayoutV2DependsOnConfigurator,
|
||||
MultiplatformLayoutV2SourceDirConfigurator,
|
||||
MultiplatformLayoutV2DefaultManifestLocationConfigurator
|
||||
)
|
||||
)
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android
|
||||
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
|
||||
internal interface KotlinAndroidSourceSetNaming {
|
||||
|
||||
/**
|
||||
* Returns non-null name of the corresponding [KotlinSourceSet], if the name of said source set can be
|
||||
* determined by the [disambiguationClassifier] and [androidSourceSetName] alone.
|
||||
*
|
||||
* Returns `null`, if KotlinSourceSet name requires additional [AndroidVariantType] to be determined.
|
||||
*/
|
||||
fun kotlinSourceSetName(
|
||||
disambiguationClassifier: String,
|
||||
androidSourceSetName: String
|
||||
): String?
|
||||
|
||||
/**
|
||||
* Returns the name of the corresponding [KotlinSourceSet], if the name of said source set cannot be determined
|
||||
* by the [disambiguationClassifier] and [androidSourceSetName] alone.
|
||||
*/
|
||||
fun kotlinSourceSetName(
|
||||
disambiguationClassifier: String,
|
||||
androidSourceSetName: String,
|
||||
type: AndroidVariantType
|
||||
): String
|
||||
|
||||
/**
|
||||
* Always capable of creating the [KotlinSourceSet]'s name based upon the disambiguationClassifier and androidSourceSetName alone.
|
||||
*/
|
||||
interface Simple : KotlinAndroidSourceSetNaming {
|
||||
override fun kotlinSourceSetName(disambiguationClassifier: String, androidSourceSetName: String): String
|
||||
override fun kotlinSourceSetName(disambiguationClassifier: String, androidSourceSetName: String, type: AndroidVariantType): String =
|
||||
kotlinSourceSetName(disambiguationClassifier, androidSourceSetName)
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android
|
||||
|
||||
import com.android.build.gradle.api.AndroidSourceSet
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.forEachVariant
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||
import org.jetbrains.kotlin.gradle.utils.androidExtension
|
||||
import org.jetbrains.kotlin.gradle.utils.getOrCreate
|
||||
|
||||
internal object KotlinAndroidSourceSets {
|
||||
|
||||
private val logger = Logging.getLogger(this::class.java)
|
||||
|
||||
fun setupKotlinAndroidSourceSets(
|
||||
target: KotlinAndroidTarget,
|
||||
layout: KotlinAndroidSourceSetLayout = target.project.kotlinAndroidSourceSetLayout
|
||||
) {
|
||||
logger.debug("Applying ${KotlinAndroidSourceSetLayout::class.java.simpleName}: ${layout.name}")
|
||||
|
||||
val project = target.project
|
||||
val kotlin = project.kotlinExtension
|
||||
val android = project.androidExtension
|
||||
val naming = layout.naming
|
||||
val configurator = layout.sourceSetConfigurator
|
||||
|
||||
/* Ensures that each KotlinSourceSet only invokes the 'configurator' once */
|
||||
val configuredKotlinSourceSets = mutableSetOf<KotlinSourceSet>()
|
||||
|
||||
/* Hook eagerly into AndroidSourceSet creation */
|
||||
android.sourceSets.all { androidSourceSet ->
|
||||
val kotlinSourceSetName = naming.kotlinSourceSetName(target.disambiguationClassifier, androidSourceSet.name) ?: return@all
|
||||
val kotlinSourceSet = kotlin.getOrCreateKotlinSourceSet(kotlinSourceSetName, androidSourceSet)
|
||||
|
||||
if (configuredKotlinSourceSets.add(kotlinSourceSet)) {
|
||||
configurator.configure(target, kotlinSourceSet, androidSourceSet)
|
||||
}
|
||||
}
|
||||
|
||||
/* Hook into Android's variant creation: This is invoked in 'afterEvaluate' */
|
||||
forEachVariant(project) { variant ->
|
||||
variant.sourceSets.forEach { sourceProvider ->
|
||||
val androidSourceSet = android.sourceSets.findByName(sourceProvider.name) ?: return@forEach
|
||||
val kotlinSourceSetName = naming.kotlinSourceSetName(target.disambiguationClassifier, sourceProvider.name)
|
||||
?: naming.kotlinSourceSetName(target.disambiguationClassifier, sourceProvider.name, variant.type)
|
||||
val kotlinSourceSet = kotlin.getOrCreateKotlinSourceSet(kotlinSourceSetName, androidSourceSet)
|
||||
|
||||
if (configuredKotlinSourceSets.add(kotlinSourceSet)) {
|
||||
configurator.configure(target, kotlinSourceSet, androidSourceSet)
|
||||
}
|
||||
configurator.configureWithVariant(target, kotlinSourceSet, variant)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun KotlinProjectExtension.getOrCreateKotlinSourceSet(
|
||||
name: String, androidSourceSet: AndroidSourceSet
|
||||
): KotlinSourceSet {
|
||||
return sourceSets.getOrCreate(name) { kotlinSourceSet ->
|
||||
kotlinSourceSet.androidSourceSetInfoOrNull?.let { info ->
|
||||
check(info.kotlinSourceSetName == name) { "Bad 'androidSourceSetInfo' on $name: Bad 'kotlinSourceSetName'" }
|
||||
check(info.androidSourceSetName == androidSourceSet.name) { "Bad 'androidSourceSetInfo' on $name: Bad 'androidSourceSetName'" }
|
||||
return@getOrCreate
|
||||
}
|
||||
|
||||
kotlinSourceSet.androidSourceSetInfo = KotlinAndroidSourceSetInfo.Mutable(
|
||||
kotlinSourceSetName = name,
|
||||
androidSourceSetName = androidSourceSet.name,
|
||||
androidVariantType = AndroidBaseSourceSetName.byName(androidSourceSet.name)?.variantType ?: AndroidVariantType.Unknown
|
||||
)
|
||||
|
||||
logger.debug("Created KotlinSourceSet: ${kotlinSourceSet.name} for AndroidSourceSet: ${androidSourceSet.name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android
|
||||
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
|
||||
internal object MultiplatformLayoutV1KotlinAndroidSourceSetNaming : KotlinAndroidSourceSetNaming.Simple {
|
||||
override fun kotlinSourceSetName(disambiguationClassifier: String, androidSourceSetName: String): String =
|
||||
lowerCamelCaseName(disambiguationClassifier, androidSourceSetName)
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android
|
||||
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
|
||||
internal object MultiplatformLayoutV2KotlinAndroidSourceSetNaming : KotlinAndroidSourceSetNaming {
|
||||
private val AndroidBaseSourceSetName.kotlinName
|
||||
get() = when (this) {
|
||||
AndroidBaseSourceSetName.Main -> "main"
|
||||
AndroidBaseSourceSetName.Test -> "unitTest"
|
||||
AndroidBaseSourceSetName.AndroidTest -> "instrumentedTest"
|
||||
}
|
||||
|
||||
override fun kotlinSourceSetName(
|
||||
disambiguationClassifier: String,
|
||||
androidSourceSetName: String,
|
||||
): String? {
|
||||
val androidBaseSourceSetName = AndroidBaseSourceSetName.byName(androidSourceSetName) ?: return null
|
||||
return lowerCamelCaseName(disambiguationClassifier, androidBaseSourceSetName.kotlinName)
|
||||
}
|
||||
|
||||
override fun kotlinSourceSetName(
|
||||
disambiguationClassifier: String,
|
||||
androidSourceSetName: String,
|
||||
type: AndroidVariantType
|
||||
): String {
|
||||
return lowerCamelCaseName(disambiguationClassifier, replaceAndroidBaseSourceSetName(androidSourceSetName, type))
|
||||
}
|
||||
|
||||
private fun replaceAndroidBaseSourceSetName(
|
||||
androidSourceSetName: String,
|
||||
type: AndroidVariantType
|
||||
): String {
|
||||
if (type == AndroidVariantType.Main) return androidSourceSetName
|
||||
val androidBaseSourceSetName = type.androidBaseSourceSetName ?: return androidSourceSetName
|
||||
return lowerCamelCaseName(androidBaseSourceSetName.kotlinName, androidSourceSetName.removePrefix(androidBaseSourceSetName.name))
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android
|
||||
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
|
||||
internal object SingleTargetKotlinAndroidSourceSetNaming : KotlinAndroidSourceSetNaming.Simple {
|
||||
override fun kotlinSourceSetName(disambiguationClassifier: String, androidSourceSetName: String): String {
|
||||
assert(disambiguationClassifier.isEmpty()) { "Unexpected non-empty disambiguationClassifier found: $disambiguationClassifier" }
|
||||
return lowerCamelCaseName(disambiguationClassifier, androidSourceSetName)
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android.configurator
|
||||
|
||||
import com.android.build.gradle.api.AndroidSourceSet
|
||||
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.ifKaptEnabled
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||
|
||||
internal object AndroidKaptSourceSetConfigurator : KotlinAndroidSourceSetConfigurator {
|
||||
override fun configure(
|
||||
target: KotlinAndroidTarget,
|
||||
kotlinSourceSet: KotlinSourceSet,
|
||||
androidSourceSet: AndroidSourceSet
|
||||
) = ifKaptEnabled(target.project) {
|
||||
Kapt3GradleSubplugin.createAptConfigurationIfNeeded(target.project, androidSourceSet.name)
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android.configurator
|
||||
|
||||
import com.android.build.gradle.api.AndroidSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.KOTLIN_DSL_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.addConvention
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||
|
||||
/*
|
||||
Used by AGP com.android.build.gradle.internal.utils.syncAgpAndKgpSources to automatically pick up sources
|
||||
from this KotlinSourceSet. This mechanism is deprecated.
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
internal object AndroidSourceSetConventionConfigurator : KotlinAndroidSourceSetConfigurator {
|
||||
override fun configure(target: KotlinAndroidTarget, kotlinSourceSet: KotlinSourceSet, androidSourceSet: AndroidSourceSet) {
|
||||
androidSourceSet.addConvention(KOTLIN_DSL_NAME, kotlinSourceSet)
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android.configurator
|
||||
|
||||
import com.android.build.gradle.api.AndroidSourceSet
|
||||
import com.android.build.gradle.api.BaseVariant
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||
|
||||
internal interface KotlinAndroidSourceSetConfigurator {
|
||||
/**
|
||||
* Called once, when the corresponding KotlinSourceSet is created for a given [AndroidSourceSet].
|
||||
* Note, this can also be called in 'afterEvaluate', when Android is finalizing its variants.
|
||||
*/
|
||||
fun configure(
|
||||
target: KotlinAndroidTarget, kotlinSourceSet: KotlinSourceSet, androidSourceSet: AndroidSourceSet
|
||||
) = Unit
|
||||
|
||||
/**
|
||||
* Called every time, when a given [KotlinSourceSet] participates in a given Android variant.
|
||||
*/
|
||||
fun configureWithVariant(
|
||||
target: KotlinAndroidTarget, kotlinSourceSet: KotlinSourceSet, variant: BaseVariant
|
||||
) = Unit
|
||||
}
|
||||
|
||||
/* Composite implementation */
|
||||
|
||||
internal fun KotlinAndroidSourceSetConfigurator(
|
||||
vararg configurators: KotlinAndroidSourceSetConfigurator?
|
||||
): KotlinAndroidSourceSetConfigurator {
|
||||
return CompositeKotlinAndroidSourceSetConfigurator(configurators.filterNotNull())
|
||||
}
|
||||
|
||||
internal operator fun KotlinAndroidSourceSetConfigurator.plus(
|
||||
other: KotlinAndroidSourceSetConfigurator
|
||||
): KotlinAndroidSourceSetConfigurator {
|
||||
val configurators = when {
|
||||
this is CompositeKotlinAndroidSourceSetConfigurator && other is CompositeKotlinAndroidSourceSetConfigurator ->
|
||||
this.configurators + other.configurators
|
||||
|
||||
this is CompositeKotlinAndroidSourceSetConfigurator -> this.configurators + other
|
||||
other is CompositeKotlinAndroidSourceSetConfigurator -> listOf(this) + other.configurators
|
||||
else -> listOf(this, other)
|
||||
}
|
||||
|
||||
return CompositeKotlinAndroidSourceSetConfigurator(configurators)
|
||||
}
|
||||
|
||||
private class CompositeKotlinAndroidSourceSetConfigurator(
|
||||
val configurators: List<KotlinAndroidSourceSetConfigurator>
|
||||
) : KotlinAndroidSourceSetConfigurator {
|
||||
override fun configure(
|
||||
target: KotlinAndroidTarget,
|
||||
kotlinSourceSet: KotlinSourceSet,
|
||||
androidSourceSet: AndroidSourceSet
|
||||
) {
|
||||
configurators.forEach { configurator ->
|
||||
configurator.configure(target, kotlinSourceSet, androidSourceSet)
|
||||
}
|
||||
}
|
||||
|
||||
override fun configureWithVariant(target: KotlinAndroidTarget, kotlinSourceSet: KotlinSourceSet, variant: BaseVariant) {
|
||||
configurators.forEach { configurator ->
|
||||
configurator.configureWithVariant(target, kotlinSourceSet, variant)
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android.configurator
|
||||
|
||||
import com.android.build.gradle.api.BaseVariant
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.android.androidSourceSetInfo
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.android.type
|
||||
|
||||
internal object KotlinAndroidSourceSetInfoConfigurator : KotlinAndroidSourceSetConfigurator {
|
||||
override fun configureWithVariant(target: KotlinAndroidTarget, kotlinSourceSet: KotlinSourceSet, variant: BaseVariant) {
|
||||
val info = kotlinSourceSet.androidSourceSetInfo.asMutable()
|
||||
info.androidVariantType = variant.type
|
||||
info.androidVariantNames.add(variant.name)
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android.configurator
|
||||
|
||||
import com.android.build.gradle.api.AndroidSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinSourceSetFactory
|
||||
|
||||
internal object MultiplatformAndroidResourceDirConfigurator : KotlinAndroidSourceSetConfigurator {
|
||||
override fun configure(
|
||||
target: KotlinAndroidTarget,
|
||||
kotlinSourceSet: KotlinSourceSet,
|
||||
androidSourceSet: AndroidSourceSet
|
||||
) {
|
||||
|
||||
/*
|
||||
Non-MPP projects will not have a different name for kotlin source sets vs Android source sets
|
||||
Registering resource folders is unnecessary therefore.
|
||||
*/
|
||||
if (kotlinSourceSet.name == androidSourceSet.name) {
|
||||
return
|
||||
}
|
||||
|
||||
val project = target.project
|
||||
|
||||
androidSourceSet.resources.srcDirs(kotlinSourceSet.resources.srcDirs)
|
||||
if (androidSourceSet.resources.srcDirs.isNotEmpty()) {
|
||||
androidSourceSet.resources.srcDir(KotlinSourceSetFactory.defaultSourceFolder(project, kotlinSourceSet.name, "resources"))
|
||||
kotlinSourceSet.resources.srcDirs(androidSourceSet.resources.srcDirs)
|
||||
}
|
||||
|
||||
if (androidSourceSet.assets.srcDirs.isNotEmpty()) {
|
||||
androidSourceSet.assets.srcDir(KotlinSourceSetFactory.defaultSourceFolder(project, kotlinSourceSet.name, "assets"))
|
||||
}
|
||||
|
||||
if (androidSourceSet.res.srcDirs.isNotEmpty()) {
|
||||
androidSourceSet.res.srcDir(KotlinSourceSetFactory.defaultSourceFolder(project, kotlinSourceSet.name, "res"))
|
||||
}
|
||||
|
||||
if (androidSourceSet.aidl.srcDirs.isNotEmpty()) {
|
||||
androidSourceSet.aidl.srcDir(KotlinSourceSetFactory.defaultSourceFolder(project, kotlinSourceSet.name, "aidl"))
|
||||
}
|
||||
|
||||
if (androidSourceSet.renderscript.srcDirs.isNotEmpty()) {
|
||||
androidSourceSet.renderscript.srcDir(KotlinSourceSetFactory.defaultSourceFolder(project, kotlinSourceSet.name, "rs"))
|
||||
}
|
||||
|
||||
if (androidSourceSet.jni.srcDirs.isNotEmpty()) {
|
||||
androidSourceSet.jni.srcDir(KotlinSourceSetFactory.defaultSourceFolder(project, kotlinSourceSet.name, "jni"))
|
||||
}
|
||||
|
||||
if (androidSourceSet.jniLibs.srcDirs.isNotEmpty()) {
|
||||
androidSourceSet.jniLibs.srcDir(KotlinSourceSetFactory.defaultSourceFolder(project, kotlinSourceSet.name, "jniLibs"))
|
||||
}
|
||||
|
||||
if (androidSourceSet.shaders.srcDirs.isNotEmpty()) {
|
||||
androidSourceSet.shaders.srcDir(KotlinSourceSetFactory.defaultSourceFolder(project, kotlinSourceSet.name, "shaders"))
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android.configurator
|
||||
|
||||
import com.android.build.gradle.api.AndroidSourceSet
|
||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet.Companion.COMMON_MAIN_SOURCE_SET_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet.Companion.COMMON_TEST_SOURCE_SET_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||
|
||||
internal object MultiplatformLayoutV1DependsOnConfigurator : KotlinAndroidSourceSetConfigurator {
|
||||
override fun configure(
|
||||
target: KotlinAndroidTarget,
|
||||
kotlinSourceSet: KotlinSourceSet,
|
||||
androidSourceSet: AndroidSourceSet
|
||||
) {
|
||||
val commonSourceSetName = when (androidSourceSet.name) {
|
||||
"main" -> COMMON_MAIN_SOURCE_SET_NAME
|
||||
"test" -> COMMON_TEST_SOURCE_SET_NAME
|
||||
"androidTest" -> COMMON_TEST_SOURCE_SET_NAME
|
||||
else -> return
|
||||
}
|
||||
val commonSourceSet = target.project.kotlinExtension.sourceSets.findByName(commonSourceSetName) ?: return
|
||||
kotlinSourceSet.dependsOn(commonSourceSet)
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android.configurator
|
||||
|
||||
import com.android.build.gradle.api.AndroidSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||
|
||||
internal object MultiplatformLayoutV1SourceDirConfigurator : KotlinAndroidSourceSetConfigurator {
|
||||
override fun configure(target: KotlinAndroidTarget, kotlinSourceSet: KotlinSourceSet, androidSourceSet: AndroidSourceSet) {
|
||||
/*
|
||||
Mitigate ambiguity!
|
||||
Example: disambiguationClassifier="android"
|
||||
Source Directory "src/androidTest/kotlin"
|
||||
-- could be claimed by kotlin {android}Test (unit test)
|
||||
-- could be claimed by Android androidTest (instrumented test)
|
||||
|
||||
The Kotlin source set would win in this scenario.
|
||||
*/
|
||||
if (!androidSourceSet.name.startsWith(target.disambiguationClassifier)) {
|
||||
kotlinSourceSet.kotlin.srcDir("src/${androidSourceSet.name}/kotlin")
|
||||
}
|
||||
|
||||
kotlinSourceSet.kotlin.srcDir(target.project.provider { androidSourceSet.java.srcDirs })
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android.configurator
|
||||
|
||||
import com.android.build.gradle.api.AndroidSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||
|
||||
internal object MultiplatformLayoutV2DefaultManifestLocationConfigurator : KotlinAndroidSourceSetConfigurator {
|
||||
override fun configure(target: KotlinAndroidTarget, kotlinSourceSet: KotlinSourceSet, androidSourceSet: AndroidSourceSet) {
|
||||
/* Default can only be set when the entity is created 'fresh'. Changes here in afterEvaluate might overwrite user setup */
|
||||
if (!target.project.state.executed) {
|
||||
androidSourceSet.manifest.srcFile("src/${kotlinSourceSet.name}/AndroidManifest.xml")
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android.configurator
|
||||
|
||||
import com.android.build.gradle.api.AndroidSourceSet
|
||||
import com.android.build.gradle.api.BaseVariant
|
||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet.Companion.COMMON_MAIN_SOURCE_SET_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet.Companion.COMMON_TEST_SOURCE_SET_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.android.AndroidBaseSourceSetName
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.android.AndroidVariantType
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.android.type
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.android.variantType
|
||||
|
||||
internal object MultiplatformLayoutV2DependsOnConfigurator : KotlinAndroidSourceSetConfigurator {
|
||||
override fun configure(target: KotlinAndroidTarget, kotlinSourceSet: KotlinSourceSet, androidSourceSet: AndroidSourceSet) {
|
||||
val androidBaseSourceSetName = AndroidBaseSourceSetName.byName(androidSourceSet.name) ?: return
|
||||
setDefaultDependsOn(target, kotlinSourceSet, androidBaseSourceSetName.variantType)
|
||||
}
|
||||
|
||||
override fun configureWithVariant(target: KotlinAndroidTarget, kotlinSourceSet: KotlinSourceSet, variant: BaseVariant) {
|
||||
setDefaultDependsOn(target, kotlinSourceSet, variant.type)
|
||||
}
|
||||
|
||||
private fun setDefaultDependsOn(target: KotlinAndroidTarget, kotlinSourceSet: KotlinSourceSet, variantType: AndroidVariantType) {
|
||||
/* Add default dependency on 'commonMain' or 'commonTest' */
|
||||
val commonMain = target.project.kotlinExtension.sourceSets.getByName(COMMON_MAIN_SOURCE_SET_NAME)
|
||||
val commonTest = target.project.kotlinExtension.sourceSets.getByName(COMMON_TEST_SOURCE_SET_NAME)
|
||||
|
||||
when (variantType) {
|
||||
AndroidVariantType.Main -> kotlinSourceSet.dependsOn(commonMain)
|
||||
AndroidVariantType.UnitTest -> kotlinSourceSet.dependsOn(commonTest)
|
||||
AndroidVariantType.InstrumentedTest, AndroidVariantType.Unknown -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android.configurator
|
||||
|
||||
import com.android.build.gradle.api.AndroidSourceDirectorySet
|
||||
import com.android.build.gradle.api.AndroidSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||
|
||||
internal object MultiplatformLayoutV2SourceDirConfigurator : KotlinAndroidSourceSetConfigurator {
|
||||
override fun configure(target: KotlinAndroidTarget, kotlinSourceSet: KotlinSourceSet, androidSourceSet: AndroidSourceSet) {
|
||||
val androidKotlinSourceDirectorySet = androidSourceSet.javaClass.getMethod("getKotlin")
|
||||
.invoke(androidSourceSet) as AndroidSourceDirectorySet
|
||||
|
||||
androidKotlinSourceDirectorySet.srcDirs(target.project.provider { kotlinSourceSet.kotlin.srcDirs })
|
||||
kotlinSourceSet.kotlin.srcDir(target.project.provider { androidSourceSet.java.srcDirs })
|
||||
kotlinSourceSet.kotlin.srcDir("src/${androidSourceSet.name}/kotlin")
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android.configurator
|
||||
|
||||
import com.android.build.gradle.api.AndroidSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||
|
||||
internal object SingleTargetSourceDirConfigurator : KotlinAndroidSourceSetConfigurator {
|
||||
override fun configure(target: KotlinAndroidTarget, kotlinSourceSet: KotlinSourceSet, androidSourceSet: AndroidSourceSet) {
|
||||
kotlinSourceSet.kotlin.srcDir("src/${androidSourceSet.name}/kotlin")
|
||||
kotlinSourceSet.kotlin.srcDir(target.project.provider { androidSourceSet.java.srcDirs })
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.plugin.sources.android
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
|
||||
|
||||
internal val Project.kotlinAndroidSourceSetLayout: KotlinAndroidSourceSetLayout
|
||||
get() {
|
||||
return if (kotlinExtension is KotlinMultiplatformExtension) {
|
||||
when (val version = kotlinPropertiesProvider.mppAndroidSourceSetLayoutVersion) {
|
||||
null, 1 -> multiplatformAndroidSourceSetLayoutV1
|
||||
2 -> multiplatformAndroidSourceSetLayoutV2
|
||||
else -> throw IllegalArgumentException(
|
||||
"Unsupported '${PropertiesProvider.PropertyNames.KOTLIN_MPP_ANDROID_SOURCE_SET_LAYOUT_VERSION}=$version' Supported versions: {1, 2}"
|
||||
)
|
||||
}
|
||||
} else singleTargetAndroidSourceSetLayout
|
||||
}
|
||||
+14
-31
@@ -28,7 +28,6 @@ import org.gradle.api.tasks.bundling.AbstractArchiveTask
|
||||
import org.gradle.api.tasks.compile.AbstractCompile
|
||||
import org.gradle.api.tasks.compile.JavaCompile
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin
|
||||
import org.jetbrains.kotlin.gradle.internal.checkAndroidAnnotationProcessorDependencyUsage
|
||||
@@ -36,7 +35,8 @@ import org.jetbrains.kotlin.gradle.logging.kotlinDebug
|
||||
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.syncKotlinAndAndroidSourceSets
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.android.KotlinAndroidSourceSets.setupKotlinAndroidSourceSets
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.android.findKotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
|
||||
import org.jetbrains.kotlin.gradle.tasks.configuration.KotlinCompileConfig
|
||||
@@ -55,19 +55,14 @@ import java.util.concurrent.Callable
|
||||
internal class AndroidProjectHandler(
|
||||
private val kotlinConfigurationTools: KotlinConfigurationTools
|
||||
) {
|
||||
companion object {
|
||||
fun kotlinSourceSetNameForAndroidSourceSet(kotlinAndroidTarget: KotlinAndroidTarget, androidSourceSetName: String) =
|
||||
lowerCamelCaseName(kotlinAndroidTarget.disambiguationClassifier, androidSourceSetName)
|
||||
}
|
||||
|
||||
private val logger = Logging.getLogger(this.javaClass)
|
||||
|
||||
fun configureTarget(kotlinAndroidTarget: KotlinAndroidTarget) {
|
||||
syncKotlinAndAndroidSourceSets(kotlinAndroidTarget)
|
||||
|
||||
val project = kotlinAndroidTarget.project
|
||||
val ext = project.extensions.getByName("android") as BaseExtension
|
||||
|
||||
setupKotlinAndroidSourceSets(kotlinAndroidTarget)
|
||||
|
||||
val kotlinOptions = KotlinJvmOptionsImpl()
|
||||
kotlinOptions.noJdk = true
|
||||
ext.addExtension(KOTLIN_OPTIONS_DSL_NAME, kotlinOptions)
|
||||
@@ -109,7 +104,7 @@ internal class AndroidProjectHandler(
|
||||
}
|
||||
checkAndroidAnnotationProcessorDependencyUsage(project)
|
||||
|
||||
addKotlinDependenciesToAndroidSourceSets(project, kotlinAndroidTarget)
|
||||
addKotlinDependenciesToAndroidSourceSets(project)
|
||||
}
|
||||
|
||||
project.includeKotlinToolingMetadataInApk()
|
||||
@@ -123,10 +118,7 @@ internal class AndroidProjectHandler(
|
||||
* source set dependencies as well, we need to add them to the Android source sets' api/implementation-like configurations,
|
||||
* not just the classpath-like configurations of the variants.
|
||||
*/
|
||||
private fun addKotlinDependenciesToAndroidSourceSets(
|
||||
project: Project,
|
||||
kotlinAndroidTarget: KotlinAndroidTarget
|
||||
) {
|
||||
private fun addKotlinDependenciesToAndroidSourceSets(project: Project) {
|
||||
fun addDependenciesToAndroidSourceSet(
|
||||
androidSourceSet: AndroidSourceSet,
|
||||
apiConfigurationName: String,
|
||||
@@ -154,8 +146,7 @@ internal class AndroidProjectHandler(
|
||||
* see [org.jetbrains.kotlin.gradle.plugin.AndroidProjectHandler.configureTarget]
|
||||
*/
|
||||
(project.extensions.getByName("android") as BaseExtension).sourceSets.forEach { androidSourceSet ->
|
||||
val kotlinSourceSetName = kotlinSourceSetNameForAndroidSourceSet(kotlinAndroidTarget, androidSourceSet.name)
|
||||
project.kotlinExtension.sourceSets.findByName(kotlinSourceSetName)?.let { kotlinSourceSet ->
|
||||
project.findKotlinSourceSet(androidSourceSet)?.let { kotlinSourceSet ->
|
||||
addDependenciesToAndroidSourceSet(
|
||||
androidSourceSet,
|
||||
kotlinSourceSet.apiConfigurationName,
|
||||
@@ -212,10 +203,7 @@ internal class AndroidProjectHandler(
|
||||
// Register the source only after the task is created, because the task is required for that:
|
||||
compilation.source(defaultSourceSet)
|
||||
|
||||
compilation.androidVariant.forEachKotlinSourceSet(
|
||||
compilation.target as KotlinAndroidTarget,
|
||||
project.kotlinExtension
|
||||
) { kotlinSourceSet ->
|
||||
compilation.androidVariant.forEachKotlinSourceSet(project) { kotlinSourceSet ->
|
||||
compilation.source(kotlinSourceSet)
|
||||
}
|
||||
}
|
||||
@@ -464,22 +452,17 @@ class AndroidTestedVariantArtifactsFilter(
|
||||
}
|
||||
|
||||
internal inline fun BaseVariant.forEachKotlinSourceSet(
|
||||
kotlinAndroidTarget: KotlinAndroidTarget,
|
||||
kotlinExtension: KotlinProjectExtension,
|
||||
action: (KotlinSourceSet) -> Unit
|
||||
project: Project, action: (KotlinSourceSet) -> Unit
|
||||
) {
|
||||
sourceSets
|
||||
.mapNotNull { provider ->
|
||||
val kotlinSourceSetName = AndroidProjectHandler.kotlinSourceSetNameForAndroidSourceSet(kotlinAndroidTarget, provider.name)
|
||||
kotlinExtension.sourceSets.findByName(kotlinSourceSetName)
|
||||
}
|
||||
.forEach(action)
|
||||
.forEach { provider -> action(project.findKotlinSourceSet(provider) ?: return@forEach) }
|
||||
}
|
||||
|
||||
internal inline fun BaseVariant.forEachKotlinSourceDirectorySet(action: (SourceDirectorySet) -> Unit) {
|
||||
internal inline fun BaseVariant.forEachKotlinSourceDirectorySet(
|
||||
project: Project, action: (SourceDirectorySet) -> Unit
|
||||
) {
|
||||
sourceSets
|
||||
.mapNotNull { it.getExtension<SourceDirectorySet>(KOTLIN_DSL_NAME) }
|
||||
.forEach(action)
|
||||
.forEach { androidSourceSet -> action(project.findKotlinSourceSet(androidSourceSet)?.kotlin ?: return@forEach) }
|
||||
}
|
||||
|
||||
internal inline fun BaseVariant.forEachJavaSourceDir(action: (ConfigurableFileTree) -> Unit) {
|
||||
|
||||
+12
-1
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.gradle.utils
|
||||
|
||||
import org.gradle.api.DomainObjectCollection
|
||||
import org.gradle.api.NamedDomainObjectContainer
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.tasks.TaskCollection
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
@@ -13,8 +14,18 @@ import org.gradle.api.tasks.TaskProvider
|
||||
internal inline fun <reified S> DomainObjectCollection<in S>.withType(): DomainObjectCollection<S> =
|
||||
withType(S::class.java)
|
||||
|
||||
|
||||
@Suppress("extension_shadowed_by_member", "UNCHECKED_CAST")
|
||||
inline fun <reified T : Task> TaskCollection<out Task>.named(name: String): TaskProvider<T> =
|
||||
(this as TaskCollection<T>).named(name, T::class.java)
|
||||
|
||||
internal fun <T> NamedDomainObjectContainer<T>.getOrCreate(
|
||||
name: String,
|
||||
invokeWhenCreated: ((T) -> Unit)? = null,
|
||||
configure: ((T) -> Unit)? = null
|
||||
): T {
|
||||
return if (name in names) named(name).also { provider ->
|
||||
if (configure != null) provider.configure(configure)
|
||||
}.get() else (if (configure != null) create(name, configure) else create(name)).also { value ->
|
||||
if (invokeWhenCreated != null) invokeWhenCreated(value)
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.utils
|
||||
|
||||
import com.android.build.gradle.BaseExtension
|
||||
import org.gradle.api.Project
|
||||
|
||||
internal val Project.androidExtensionOrNull: BaseExtension? get() = extensions.findByName("android")?.let { it as? BaseExtension }
|
||||
|
||||
internal val Project.androidExtension: BaseExtension get() = extensions.getByName("android") as BaseExtension
|
||||
+5
@@ -15,6 +15,7 @@ import org.gradle.testfixtures.ProjectBuilder
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_KPM_EXPERIMENTAL_MODEL_MAPPING
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ANDROID_SOURCE_SET_LAYOUT_VERSION
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ENABLE_CINTEROP_COMMONIZATION
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_HIERARCHICAL_STRUCTURE_BY_DEFAULT
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_STDLIB_DEFAULT_DEPENDENCY
|
||||
@@ -111,3 +112,7 @@ fun Project.enableKpmModelMapping(enabled: Boolean = true) {
|
||||
fun Project.enableDefaultStdlibDependency(enabled: Boolean = true) {
|
||||
project.propertiesExtension.set(KOTLIN_STDLIB_DEFAULT_DEPENDENCY, enabled.toString())
|
||||
}
|
||||
|
||||
fun Project.setAndroidMultiplatformSourceSetLayoutVersion(version: Int) {
|
||||
project.propertiesExtension.set(KOTLIN_MPP_ANDROID_SOURCE_SET_LAYOUT_VERSION, version.toString())
|
||||
}
|
||||
+30
-21
@@ -1,23 +1,27 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2022 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.
|
||||
*/
|
||||
|
||||
/* Associate compilations are not yet supported by the IDE. KT-34102 */
|
||||
@file:Suppress("invisible_reference", "invisible_member", "FunctionName", "DuplicatedCode")
|
||||
@file:Suppress("DEPRECATION", "DuplicatedCode", "FunctionName")
|
||||
|
||||
package org.jetbrains.kotlin.gradle
|
||||
package org.jetbrains.kotlin.gradle.sources.android
|
||||
|
||||
import com.android.build.gradle.LibraryExtension
|
||||
import com.android.build.gradle.api.AndroidSourceSet
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.internal.HasConvention
|
||||
import org.gradle.api.internal.project.ProjectInternal
|
||||
import org.gradle.testfixtures.ProjectBuilder
|
||||
import org.jetbrains.kotlin.gradle.addBuildEventsListenerRegistryMock
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.kotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.android.findKotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.setAndroidMultiplatformSourceSetLayoutVersion
|
||||
import kotlin.test.*
|
||||
|
||||
class SyncKotlinAndAndroidSourceSetsTest {
|
||||
class MultiplatformAndroidSourceSetLayoutV1Test {
|
||||
|
||||
private lateinit var project: ProjectInternal
|
||||
private lateinit var kotlin: KotlinMultiplatformExtension
|
||||
@@ -27,6 +31,8 @@ class SyncKotlinAndAndroidSourceSetsTest {
|
||||
fun setup() {
|
||||
project = ProjectBuilder.builder().build() as ProjectInternal
|
||||
addBuildEventsListenerRegistryMock(project)
|
||||
project.setAndroidMultiplatformSourceSetLayoutVersion(1)
|
||||
|
||||
project.plugins.apply("kotlin-multiplatform")
|
||||
project.plugins.apply("android-library")
|
||||
|
||||
@@ -36,7 +42,6 @@ class SyncKotlinAndAndroidSourceSetsTest {
|
||||
|
||||
/* Kotlin Setup */
|
||||
kotlin = project.multiplatformExtension
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -93,21 +98,19 @@ class SyncKotlinAndAndroidSourceSetsTest {
|
||||
@Test
|
||||
fun `two product flavor dimensions`() {
|
||||
android.flavorDimensions("pricing", "releaseType")
|
||||
android.productFlavors(
|
||||
Action {
|
||||
it.create("beta").dimension = "releaseType"
|
||||
it.create("production").dimension = "releaseType"
|
||||
it.create("free").dimension = "pricing"
|
||||
it.create("paid").dimension = "pricing"
|
||||
}
|
||||
)
|
||||
android.productFlavors {
|
||||
it.create("beta").dimension = "releaseType"
|
||||
it.create("production").dimension = "releaseType"
|
||||
it.create("free").dimension = "pricing"
|
||||
it.create("paid").dimension = "pricing"
|
||||
}
|
||||
kotlin.android()
|
||||
project.evaluate()
|
||||
|
||||
fun assertSourceSetsExist(androidName: String, kotlinName: String) {
|
||||
val androidSourceSet = assertNotNull(android.sourceSets.findByName(androidName), "Expected Android source set '$androidName'")
|
||||
val kotlinSourceSet = assertNotNull(kotlin.sourceSets.findByName(kotlinName), "Expected Kotlin source set '$kotlinName'")
|
||||
assertSame(kotlinSourceSet.kotlin, androidSourceSet.kotlinSourceSet)
|
||||
assertSame(kotlinSourceSet, androidSourceSet.kotlinSourceSet)
|
||||
}
|
||||
|
||||
assertSourceSetsExist("freeBetaDebug", "androidFreeBetaDebug")
|
||||
@@ -178,18 +181,24 @@ class SyncKotlinAndAndroidSourceSetsTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `AndroidSourceSet#kotlinSourceSet extension`() {
|
||||
fun `AndroidSourceSet#kotlinSourceSet convention`() {
|
||||
kotlin.android()
|
||||
|
||||
fun AndroidSourceSet.kotlinSourceSetByConvention(): KotlinSourceSet =
|
||||
(this as HasConvention).convention.plugins["kotlin"] as KotlinSourceSet
|
||||
|
||||
val main = android.sourceSets.getByName("main")
|
||||
assertSame(kotlin.sourceSets.getByName("androidMain").kotlin, main.kotlinSourceSet)
|
||||
assertSame(kotlin.sourceSets.getByName("androidMain"), main.kotlinSourceSetByConvention())
|
||||
|
||||
val test = android.sourceSets.getByName("test")
|
||||
assertSame(kotlin.sourceSets.getByName("androidTest").kotlin, test.kotlinSourceSet)
|
||||
assertSame(kotlin.sourceSets.getByName("androidTest"), test.kotlinSourceSetByConvention())
|
||||
|
||||
val androidTest = android.sourceSets.getByName("androidTest")
|
||||
assertSame(kotlin.sourceSets.getByName("androidAndroidTest").kotlin, androidTest.kotlinSourceSet)
|
||||
assertSame(kotlin.sourceSets.getByName("androidAndroidTest"), androidTest.kotlinSourceSetByConvention())
|
||||
}
|
||||
|
||||
private val AndroidSourceSet.kotlinSourceSet
|
||||
get() = project.findKotlinSourceSet(this) ?: fail("Missing KotlinSourceSet for AndroidSourceSet: $name")
|
||||
}
|
||||
|
||||
private fun <T> Set<T>.allPairs(): Sequence<Pair<T, T>> {
|
||||
@@ -203,4 +212,4 @@ private fun <T> Set<T>.allPairs(): Sequence<Pair<T, T>> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user