[Gradle] Associate Android java sources with related Kotlin Source Set

Java sources can be produced by the task or can be configured with
task dependencies. Previously sources were included into task directly
now they are properly configured with Kotlin Android Source Set.

^KT-63753 Verification Pending
^KT-65426 Verification Pending
This commit is contained in:
Anton Lakotka
2024-02-14 11:27:43 +01:00
committed by Space Team
parent b5ed2326e7
commit 020bb72d2b
8 changed files with 45 additions and 21 deletions
@@ -973,11 +973,6 @@ class KotlinAndroidMppIT : KGPBaseTest() {
defaultBuildOptions.copy(androidVersion = agpVersion), defaultBuildOptions.copy(androidVersion = agpVersion),
buildJdk = jdkVersion.location buildJdk = jdkVersion.location
) { ) {
// Hacks for TODO: KT-65426
val appPath = subProject("app").projectPath
appPath.resolve("src/main/java/app/example/com/app_sample").deleteRecursively()
appPath.resolve("src/commonMain/kotlin/A.kt").replaceText("expect fun f(): Unit", "")
// Code copied from the reproducer from KT-63753 // Code copied from the reproducer from KT-63753
subProject("app").buildGradleKts.appendText( subProject("app").buildGradleKts.appendText(
""" """
@@ -28,7 +28,7 @@ internal val singleTargetAndroidSourceSetLayout = KotlinAndroidSourceSetLayout(
GradleConventionAddKotlinSourcesToAndroidSourceSetConfigurator, GradleConventionAddKotlinSourcesToAndroidSourceSetConfigurator,
Agp7AddKotlinSourcesToAndroidSourceSetConfigurator Agp7AddKotlinSourcesToAndroidSourceSetConfigurator
.onlyIf { AndroidGradlePluginVersion.current >= "7.0.0" }, .onlyIf { AndroidGradlePluginVersion.current >= "7.0.0" },
KotlinAndroidJavaSourceDirConfigurator,
SingleTargetSourceDirConfigurator, SingleTargetSourceDirConfigurator,
), ),
checker = KotlinAndroidSourceSetLayoutChecker() checker = KotlinAndroidSourceSetLayoutChecker()
@@ -43,6 +43,7 @@ internal val multiplatformAndroidSourceSetLayoutV1 = KotlinAndroidSourceSetLayou
GradleConventionAddKotlinSourcesToAndroidSourceSetConfigurator, GradleConventionAddKotlinSourcesToAndroidSourceSetConfigurator,
Agp7AddKotlinSourcesToAndroidSourceSetConfigurator Agp7AddKotlinSourcesToAndroidSourceSetConfigurator
.onlyIf { AndroidGradlePluginVersion.current >= "7.0.0" }, .onlyIf { AndroidGradlePluginVersion.current >= "7.0.0" },
KotlinAndroidJavaSourceDirConfigurator,
MultiplatformAndroidResourceDirConfigurator, MultiplatformAndroidResourceDirConfigurator,
MultiplatformLayoutV1DependsOnConfigurator, MultiplatformLayoutV1DependsOnConfigurator,
MultiplatformLayoutV1SourceDirConfigurator MultiplatformLayoutV1SourceDirConfigurator
@@ -62,6 +63,7 @@ internal val multiplatformAndroidSourceSetLayoutV2 = KotlinAndroidSourceSetLayou
MultiplatformLayoutV2DependsOnConfigurator, MultiplatformLayoutV2DependsOnConfigurator,
Agp7AddKotlinSourcesToAndroidSourceSetConfigurator Agp7AddKotlinSourcesToAndroidSourceSetConfigurator
.onlyIf { AndroidGradlePluginVersion.current >= "7.0.0" }, .onlyIf { AndroidGradlePluginVersion.current >= "7.0.0" },
KotlinAndroidJavaSourceDirConfigurator,
MultiplatformLayoutV2SourceDirConfigurator, MultiplatformLayoutV2SourceDirConfigurator,
MultiplatformLayoutV2DefaultManifestLocationConfigurator MultiplatformLayoutV2DefaultManifestLocationConfigurator
), ),
@@ -0,0 +1,27 @@
/*
* Copyright 2010-2024 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.
*/
@file:Suppress("TYPEALIAS_EXPANSION_DEPRECATION")
package org.jetbrains.kotlin.gradle.plugin.sources.android.configurator
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
import org.jetbrains.kotlin.gradle.utils.DeprecatedAndroidSourceSet
import org.jetbrains.kotlin.gradle.utils.fileCollectionFromConfigurableFileTree
import org.jetbrains.kotlin.gradle.utils.filesProvider
internal object KotlinAndroidJavaSourceDirConfigurator : KotlinAndroidSourceSetConfigurator {
override fun configure(target: KotlinAndroidTarget, kotlinSourceSet: KotlinSourceSet, androidSourceSet: DeprecatedAndroidSourceSet) {
val project = target.project
kotlinSourceSet.kotlin.srcDir(project.provider {
// getSourceDirectoryTrees() is not lazy, thus it should be wrapped with provider
androidSourceSet.java.getSourceDirectoryTrees().map { sources ->
project.fileCollectionFromConfigurableFileTree(sources)
}
})
}
}
@@ -27,7 +27,5 @@ internal object MultiplatformLayoutV1SourceDirConfigurator : KotlinAndroidSource
if (!androidSourceSet.name.startsWith(target.disambiguationClassifier)) { if (!androidSourceSet.name.startsWith(target.disambiguationClassifier)) {
kotlinSourceSet.kotlin.srcDir("src/${androidSourceSet.name}/kotlin") kotlinSourceSet.kotlin.srcDir("src/${androidSourceSet.name}/kotlin")
} }
kotlinSourceSet.kotlin.srcDir(target.project.provider { androidSourceSet.java.srcDirs })
} }
} }
@@ -15,7 +15,6 @@ internal object MultiplatformLayoutV2SourceDirConfigurator : KotlinAndroidSource
kotlinSourceSet: KotlinSourceSet, kotlinSourceSet: KotlinSourceSet,
@Suppress("TYPEALIAS_EXPANSION_DEPRECATION") androidSourceSet: DeprecatedAndroidSourceSet @Suppress("TYPEALIAS_EXPANSION_DEPRECATION") androidSourceSet: DeprecatedAndroidSourceSet
) { ) {
kotlinSourceSet.kotlin.srcDir(target.project.provider { androidSourceSet.java.srcDirs })
kotlinSourceSet.kotlin.srcDir("src/${androidSourceSet.name}/kotlin") kotlinSourceSet.kotlin.srcDir("src/${androidSourceSet.name}/kotlin")
} }
} }
@@ -16,6 +16,5 @@ internal object SingleTargetSourceDirConfigurator : KotlinAndroidSourceSetConfig
@Suppress("TYPEALIAS_EXPANSION_DEPRECATION") androidSourceSet: DeprecatedAndroidSourceSet @Suppress("TYPEALIAS_EXPANSION_DEPRECATION") androidSourceSet: DeprecatedAndroidSourceSet
) { ) {
kotlinSourceSet.kotlin.srcDir("src/${androidSourceSet.name}/kotlin") kotlinSourceSet.kotlin.srcDir("src/${androidSourceSet.name}/kotlin")
kotlinSourceSet.kotlin.srcDir(target.project.provider { androidSourceSet.java.srcDirs })
} }
} }
@@ -230,13 +230,11 @@ internal class AndroidProjectHandler(
val javaTask = variantData.javaCompileProvider val javaTask = variantData.javaCompileProvider
@Suppress("UNCHECKED_CAST") val kotlinTask = compilation.compileTaskProvider as TaskProvider<KotlinCompile> @Suppress("UNCHECKED_CAST") val kotlinTask = compilation.compileTaskProvider as TaskProvider<KotlinCompile>
compilation.androidVariant.forEachJavaSourceDir { sources -> kotlinTask.configure { task ->
// It is important to pass exactly `sources.dir` as provider with explicit task dependency variantData.forEachJavaSourceDir { sources ->
// Because of the following bugs: task.source(sources.dir)
// * https://github.com/gradle/gradle/issues/27881 ConfigurableFileTree.from() doesn't preserve Task Dependencies task.dependsOn(sources)
// * https://github.com/gradle/gradle/issues/27882 SourceDirectorySet doesn't accept ConfigurableFileTree }
val sourceDirWithTaskDependencies = project.filesProvider(sources) { sources.dir }
compilation.defaultSourceSet.kotlin.srcDir(sourceDirWithTaskDependencies)
} }
wireKotlinTasks(project, compilation, androidPlugin, androidExt, variantData, javaTask, kotlinTask) wireKotlinTasks(project, compilation, androidPlugin, androidExt, variantData, javaTask, kotlinTask)
} }
@@ -6,9 +6,7 @@
package org.jetbrains.kotlin.gradle.utils package org.jetbrains.kotlin.gradle.utils
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.file.Directory import org.gradle.api.file.*
import org.gradle.api.file.FileCollection
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.jetbrains.kotlin.gradle.plugin.internal.CustomPropertiesFileValueSource import org.jetbrains.kotlin.gradle.plugin.internal.CustomPropertiesFileValueSource
import org.jetbrains.kotlin.gradle.plugin.internal.configurationTimePropertiesAccessor import org.jetbrains.kotlin.gradle.plugin.internal.configurationTimePropertiesAccessor
@@ -150,3 +148,11 @@ internal val Project.localProperties: Provider<Map<String, String>>
* Returns file collection [this] excluding files from [excludes] if not null * Returns file collection [this] excluding files from [excludes] if not null
*/ */
internal fun FileCollection.exclude(excludes: FileCollection?): FileCollection = if (excludes != null) minus(excludes) else this internal fun FileCollection.exclude(excludes: FileCollection?): FileCollection = if (excludes != null) minus(excludes) else this
internal fun Project.fileCollectionFromConfigurableFileTree(fileTree: ConfigurableFileTree): ConfigurableFileCollection {
// It is important to pass exactly `fileTree.dir` as provider with explicit task dependency
// Because of the following bugs:
// * https://github.com/gradle/gradle/issues/27881 ConfigurableFileTree.from() doesn't preserve Task Dependencies
// * https://github.com/gradle/gradle/issues/27882 SourceDirectorySet doesn't accept ConfigurableFileTree
return project.filesProvider(fileTree) { fileTree.dir }
}