diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/KotlinDependenciesManagement.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/KotlinDependenciesManagement.kt index c5c856c4f48..e6cf516a816 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/KotlinDependenciesManagement.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/KotlinDependenciesManagement.kt @@ -216,7 +216,7 @@ private fun chooseAndAddStdlibDependency( private fun androidMainSourceSetName(project: Project): String { val target = project.findAndroidTarget() ?: error("No Android target found") - return AbstractAndroidProjectHandler.kotlinSourceSetNameForAndroidSourceSet(target, "main") + return AndroidProjectHandler.kotlinSourceSetNameForAndroidSourceSet(target, "main") } private fun isRelatedToAndroidTestSourceSet(project: Project, kotlinSourceSet: KotlinSourceSet): Boolean { @@ -230,7 +230,7 @@ private fun isRelatedToAndroidTestSourceSet(project: Project, kotlinSourceSet: K (androidExtension.testVariants + androidExtension.unitTestVariants).forEach { variant -> if (variant.sourceSets.any { - kotlinSourceSet.name == AbstractAndroidProjectHandler.kotlinSourceSetNameForAndroidSourceSet(androidTarget, it.name) + kotlinSourceSet.name == AndroidProjectHandler.kotlinSourceSetNameForAndroidSourceSet(androidTarget, it.name) } ) return true } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt index 1c5b8d493da..8ef16769744 100755 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt @@ -6,19 +6,14 @@ package org.jetbrains.kotlin.gradle.plugin import com.android.build.gradle.* -import com.android.build.gradle.api.AndroidSourceSet import com.android.build.gradle.api.BaseVariant -import com.android.build.gradle.api.SourceKind -import com.android.build.gradle.api.UnitTestVariant import org.gradle.api.* import org.gradle.api.attributes.Category import org.gradle.api.attributes.Usage -import org.gradle.api.file.ConfigurableFileTree import org.gradle.api.file.Directory import org.gradle.api.file.FileCollection import org.gradle.api.file.SourceDirectorySet import org.gradle.api.logging.Logging -import org.gradle.api.plugins.InvalidPluginException import org.gradle.api.plugins.JavaPlugin import org.gradle.api.provider.Provider import org.gradle.api.publish.PublishingExtension @@ -31,11 +26,8 @@ import org.gradle.jvm.tasks.Jar import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin -import org.jetbrains.kotlin.gradle.internal.checkAndroidAnnotationProcessorDependencyUsage import org.jetbrains.kotlin.gradle.internal.customizeKotlinDependencies -import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.model.builder.KotlinModelBuilder -import org.jetbrains.kotlin.gradle.plugin.AbstractAndroidProjectHandler.Companion.kotlinSourceSetNameForAndroidSourceSet import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider import org.jetbrains.kotlin.gradle.plugin.internal.JavaSourceSetsAccessor import org.jetbrains.kotlin.gradle.plugin.internal.MavenPluginConfigurator @@ -48,8 +40,6 @@ import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.configuration.* -import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry -import org.jetbrains.kotlin.gradle.tooling.includeKotlinToolingMetadataInApk import org.jetbrains.kotlin.gradle.utils.* import java.io.File import java.net.URL @@ -720,7 +710,7 @@ internal open class KotlinAndroidPlugin( companion object { const val MINIMAL_SUPPORTED_AGP_VERSION = "3.6.4" - fun androidTargetHandler(): AbstractAndroidProjectHandler { + fun androidTargetHandler(): AndroidProjectHandler { val tasksProvider = KotlinTasksProvider() if (androidPluginVersion != null) { @@ -732,11 +722,7 @@ internal open class KotlinAndroidPlugin( } } - val kotlinTools = KotlinConfigurationTools( - tasksProvider - ) - - return Android25ProjectHandler(kotlinTools) + return AndroidProjectHandler(KotlinConfigurationTools(tasksProvider)) } internal fun Project.dynamicallyApplyWhenAndroidPluginIsApplied( @@ -774,240 +760,6 @@ class KotlinConfigurationTools internal constructor( val kotlinTasksProvider: KotlinTasksProvider ) -abstract class AbstractAndroidProjectHandler(private val kotlinConfigurationTools: KotlinConfigurationTools) { - companion object { - fun kotlinSourceSetNameForAndroidSourceSet(kotlinAndroidTarget: KotlinAndroidTarget, androidSourceSetName: String) = - lowerCamelCaseName(kotlinAndroidTarget.disambiguationClassifier, androidSourceSetName) - } - - protected val logger = Logging.getLogger(this.javaClass) - - abstract fun getFlavorNames(variant: BaseVariant): List - abstract fun getBuildTypeName(variant: BaseVariant): String - abstract fun getLibraryOutputTask(variant: BaseVariant): Any? - - protected open fun checkVariantIsValid(variant: BaseVariant) = Unit - - protected open fun setUpDependencyResolution(variant: BaseVariant, compilation: KotlinJvmAndroidCompilation) = Unit - - protected abstract fun wireKotlinTasks( - project: Project, - compilation: KotlinJvmAndroidCompilation, - androidPlugin: BasePlugin, - androidExt: BaseExtension, - variantData: BaseVariant, - javaTask: TaskProvider, - kotlinTask: TaskProvider - ) - - fun configureTarget(kotlinAndroidTarget: KotlinAndroidTarget) { - syncKotlinAndAndroidSourceSets(kotlinAndroidTarget) - - val project = kotlinAndroidTarget.project - val ext = project.extensions.getByName("android") as BaseExtension - - val kotlinOptions = KotlinJvmOptionsImpl() - kotlinOptions.noJdk = true - ext.addExtension(KOTLIN_OPTIONS_DSL_NAME, kotlinOptions) - - val plugin = androidPluginIds - .asSequence() - .mapNotNull { project.plugins.findPlugin(it) as? BasePlugin } - .firstOrNull() - ?: throw InvalidPluginException("'kotlin-android' expects one of the Android Gradle " + - "plugins to be applied to the project:\n\t" + - androidPluginIds.joinToString("\n\t") { "* $it" }) - - project.forEachVariant { variant -> - val variantName = getVariantName(variant) - - // Create the compilation and configure it first, then add to the compilations container. As this code is executed - // in afterEvaluate, a user's build script might have already attached item handlers to the compilations container, and those - // handlers might break when fired on a compilation that is not yet properly configured (e.g. KT-29964): - kotlinAndroidTarget.compilationFactory.create(variantName).let { compilation -> - compilation.androidVariant = variant - - setUpDependencyResolution(variant, compilation) - - preprocessVariant(variant, compilation, project, kotlinOptions, kotlinConfigurationTools.kotlinTasksProvider) - - @Suppress("UNCHECKED_CAST") - (kotlinAndroidTarget.compilations as NamedDomainObjectCollection).add(compilation) - } - - } - - project.whenEvaluated { - forEachVariant { variant -> - val compilation = kotlinAndroidTarget.compilations.getByName(getVariantName(variant)) - postprocessVariant(variant, compilation, project, ext, plugin) - - val subpluginEnvironment = SubpluginEnvironment.loadSubplugins(project) - subpluginEnvironment.addSubpluginOptions(project, compilation) - } - checkAndroidAnnotationProcessorDependencyUsage(project) - - addKotlinDependenciesToAndroidSourceSets(project, kotlinAndroidTarget) - } - - project.includeKotlinToolingMetadataInApk() - - addAndroidUnitTestTasksAsDependenciesToAllTest(project) - } - - /** - * The Android variants have their configurations extendsFrom relation set up in a way that only some of the configurations of the - * variants propagate the dependencies from production variants to test ones. To make this dependency propagation work for the Kotlin - * 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 - ) { - fun addDependenciesToAndroidSourceSet( - androidSourceSet: AndroidSourceSet, - apiConfigurationName: String, - implementationConfigurationName: String, - compileOnlyConfigurationName: String, - runtimeOnlyConfigurationName: String - ) { - if (project.configurations.findByName(androidSourceSet.apiConfigurationName) != null) { - project.addExtendsFromRelation(androidSourceSet.apiConfigurationName, apiConfigurationName) - } else { - // If any dependency is added to this configuration, report an error: - project.configurations.getByName(apiConfigurationName).dependencies.all { - throw InvalidUserCodeException( - "API dependencies are not allowed for Android source set ${androidSourceSet.name}. " + - "Please use an implementation dependency instead." - ) - } - } - project.addExtendsFromRelation(androidSourceSet.implementationConfigurationName, implementationConfigurationName) - project.addExtendsFromRelation(androidSourceSet.compileOnlyConfigurationName, compileOnlyConfigurationName) - project.addExtendsFromRelation(androidSourceSet.runtimeOnlyConfigurationName, runtimeOnlyConfigurationName) - } - - /** First, just add the dependencies from Kotlin source sets created for the Android source sets, - * see [org.jetbrains.kotlin.gradle.plugin.AbstractAndroidProjectHandler.configureTarget] - */ - (project.extensions.getByName("android") as BaseExtension).sourceSets.forEach { androidSourceSet -> - val kotlinSourceSetName = kotlinSourceSetNameForAndroidSourceSet(kotlinAndroidTarget, androidSourceSet.name) - project.kotlinExtension.sourceSets.findByName(kotlinSourceSetName)?.let { kotlinSourceSet -> - addDependenciesToAndroidSourceSet( - androidSourceSet, - kotlinSourceSet.apiConfigurationName, - kotlinSourceSet.implementationConfigurationName, - kotlinSourceSet.compileOnlyConfigurationName, - kotlinSourceSet.runtimeOnlyConfigurationName - ) - } - } - } - - private fun addAndroidUnitTestTasksAsDependenciesToAllTest(project: Project) { - val allTestTaskName = project.kotlinTestRegistry.allTestsTaskName - project.tasks.matching { it.name == allTestTaskName }.configureEach { task -> - task.dependsOn(project.provider { - val androidUnitTestTasks = mutableListOf() - forEachVariant(project) { variant -> - if (variant is UnitTestVariant) { - // There's no API for getting the Android unit test tasks from the variant, so match them by name: - androidUnitTestTasks.add(project.provider { - project.tasks.matching { it.name == lowerCamelCaseName("test", variant.name) } - }) - } - } - androidUnitTestTasks - }) - } - } - - private fun preprocessVariant( - variantData: BaseVariant, - compilation: KotlinJvmAndroidCompilation, - project: Project, - rootKotlinOptions: KotlinJvmOptionsImpl, - tasksProvider: KotlinTasksProvider - ) { - // This function is called before the variantData is completely filled by the Android plugin. - // The fine details of variantData, such as AP options or Java sources, should not be trusted here. - - checkVariantIsValid(variantData) - val variantDataName = getVariantName(variantData) - logger.kotlinDebug("Process variant [$variantDataName]") - - val defaultSourceSet = project.kotlinExtension.sourceSets.maybeCreate(compilation.defaultSourceSetName) - - val configAction = KotlinCompileConfig(compilation) - configAction.configureTask { task -> - task.parentKotlinOptions.value(rootKotlinOptions).disallowChanges() - task.useModuleDetection.value(true).disallowChanges() - // store kotlin classes in separate directory. They will serve as class-path to java compiler - task.destinationDirectory.set(project.layout.buildDirectory.dir("tmp/kotlin-classes/$variantDataName")) - task.description = "Compiles the $variantDataName kotlin." - } - tasksProvider.registerKotlinJVMTask(project, compilation.compileKotlinTaskName, compilation.kotlinOptions, configAction) - - // 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.source(kotlinSourceSet) - } - } - - private fun postprocessVariant( - variantData: BaseVariant, - compilation: KotlinJvmAndroidCompilation, - project: Project, - androidExt: BaseExtension, - androidPlugin: BasePlugin - ) { - - getTestedVariantData(variantData)?.let { testedVariant -> - val testedVariantName = getVariantName(testedVariant) - val testedCompilation = compilation.target.compilations.getByName(testedVariantName) - compilation.associateWith(testedCompilation) - } - - val javaTask = variantData.getJavaTaskProvider() - val kotlinTask = compilation.compileKotlinTaskProvider - compilation.androidVariant.forEachJavaSourceDir { sources -> - kotlinTask.configure { - it.setSource(sources.dir) - it.dependsOn(sources) - } - } - wireKotlinTasks(project, compilation, androidPlugin, androidExt, variantData, javaTask, kotlinTask) - } -} - -internal inline fun BaseVariant.forEachKotlinSourceSet( - kotlinAndroidTarget: KotlinAndroidTarget, - kotlinExtension: KotlinProjectExtension, - action: (KotlinSourceSet) -> Unit -) { - sourceSets - .mapNotNull { provider -> - val kotlinSourceSetName = kotlinSourceSetNameForAndroidSourceSet(kotlinAndroidTarget, provider.name) - kotlinExtension.sourceSets.findByName(kotlinSourceSetName) - } - .forEach(action) -} - -internal inline fun BaseVariant.forEachKotlinSourceDirectorySet(action: (SourceDirectorySet) -> Unit) { - sourceSets - .mapNotNull { it.getExtension(KOTLIN_DSL_NAME) } - .forEach(action) -} - -internal inline fun BaseVariant.forEachJavaSourceDir(action: (ConfigurableFileTree) -> Unit) { - getSourceFolders(SourceKind.JAVA).forEach(action) -} internal fun ifKaptEnabled(project: Project, block: () -> Unit) { var triggered = false diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/syncKotlinAndAndroidSourceSets.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/syncKotlinAndAndroidSourceSets.kt index 3e3f59ba643..fd8339d0b52 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/syncKotlinAndAndroidSourceSets.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/syncKotlinAndAndroidSourceSets.kt @@ -12,8 +12,7 @@ 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.AbstractAndroidProjectHandler.Companion.kotlinSourceSetNameForAndroidSourceSet -import org.jetbrains.kotlin.gradle.plugin.addConvention +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" diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/Android25ProjectHandler.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/Android25ProjectHandler.kt deleted file mode 100644 index 9a71c3a3c15..00000000000 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/Android25ProjectHandler.kt +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright 2010-2019 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("PackageDirectoryMismatch") // Old package for compatibility -package org.jetbrains.kotlin.gradle.plugin - -import com.android.build.api.attributes.BuildTypeAttr -import com.android.build.gradle.* -import com.android.build.gradle.api.* -import com.android.build.gradle.tasks.MergeResources -import org.gradle.api.Project -import org.gradle.api.artifacts.ArtifactCollection -import org.gradle.api.artifacts.component.ProjectComponentIdentifier -import org.gradle.api.attributes.Attribute -import org.gradle.api.attributes.Category -import org.gradle.api.file.FileCollection -import org.gradle.api.specs.Spec -import org.gradle.api.tasks.TaskProvider -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.internal.Kapt3GradleSubplugin -import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import org.jetbrains.kotlin.gradle.tasks.thisTaskProvider -import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation -import java.io.File -import java.io.ObjectInputStream -import java.io.ObjectOutputStream -import java.io.Serializable -import java.util.concurrent.Callable - -class Android25ProjectHandler( - kotlinConfigurationTools: KotlinConfigurationTools -) : AbstractAndroidProjectHandler(kotlinConfigurationTools) { - - override fun wireKotlinTasks( - project: Project, - compilation: KotlinJvmAndroidCompilation, - androidPlugin: BasePlugin, - androidExt: BaseExtension, - variantData: BaseVariant, - javaTask: TaskProvider, - kotlinTask: TaskProvider - ) { - val preJavaKotlinOutput = project.files(project.provider { - mutableListOf().apply { - add(kotlinTask.get().destinationDirectory.get().asFile) - if (Kapt3GradleSubplugin.isEnabled(project)) { - // Add Kapt3 output as well, since there's no SyncOutputTask with the new API - val kaptClasssesDir = Kapt3GradleSubplugin.getKaptGeneratedClassesDir(project, getVariantName(variantData)) - add(kaptClasssesDir) - } - } - }).builtBy(kotlinTask) - - val preJavaClasspathKey = variantData.registerPreJavacGeneratedBytecode(preJavaKotlinOutput) - kotlinTask.configure { kotlinTaskInstance -> - kotlinTaskInstance.libraries - .from(variantData.getCompileClasspath(preJavaClasspathKey)) - .from(Callable { AndroidGradleWrapper.getRuntimeJars(androidPlugin, androidExt) }) - - kotlinTaskInstance.javaOutputDir.set(javaTask.flatMap { it.destinationDirectory }) - } - - // Find the classpath entries that come from the tested variant and register them as the friend paths, lazily - val originalArtifactCollection = variantData.getCompileClasspathArtifacts(preJavaClasspathKey) - val testedVariantDataIsNotNull = getTestedVariantData(variantData) != null - val projectPath = project.path - compilation.testedVariantArtifacts.set( - originalArtifactCollection.artifactFiles.filter( - AndroidTestedVariantArtifactsFilter( - originalArtifactCollection, - testedVariantDataIsNotNull, - projectPath - ) - ) - ) - - compilation.output.classesDirs.from( - kotlinTask.flatMap { it.destinationDirectory }, - javaTask.flatMap { it.destinationDirectory } - ) - } - - override fun getFlavorNames(variant: BaseVariant): List = variant.productFlavors.map { it.name } - - override fun getBuildTypeName(variant: BaseVariant): String = variant.buildType.name - - // TODO the return type is actually `AbstractArchiveTask | TaskProvider`; - // change the signature once the Android Gradle plugin versions that don't support task providers are dropped - override fun getLibraryOutputTask(variant: BaseVariant): Any? { - val getPackageLibraryProvider = variant.javaClass.methods - .find { it.name == "getPackageLibraryProvider" && it.parameterCount == 0 } - - return if (getPackageLibraryProvider != null) { - @Suppress("UNCHECKED_CAST") - getPackageLibraryProvider(variant) as TaskProvider - } else { - (variant as? LibraryVariant)?.packageLibrary - } - } - - override fun setUpDependencyResolution(variant: BaseVariant, compilation: KotlinJvmAndroidCompilation) { - val project = compilation.target.project - - AbstractKotlinTargetConfigurator.defineConfigurationsForCompilation(compilation) - - compilation.compileDependencyFiles = variant.compileConfiguration.apply { - usesPlatformOf(compilation.target) - project.addExtendsFromRelation(name, compilation.compileDependencyConfigurationName) - } - - compilation.runtimeDependencyFiles = variant.runtimeConfiguration.apply { - usesPlatformOf(compilation.target) - project.addExtendsFromRelation(name, compilation.runtimeDependencyConfigurationName) - } - - val buildTypeAttrValue = project.objects.named(BuildTypeAttr::class.java, variant.buildType.name) - listOf(compilation.compileDependencyConfigurationName, compilation.runtimeDependencyConfigurationName).forEach { - project.configurations.findByName(it)?.attributes?.attribute(Attribute.of(BuildTypeAttr::class.java), buildTypeAttrValue) - } - - // TODO this code depends on the convention that is present in the Android plugin as there's no public API - // We should request such API in the Android plugin - val apiElementsConfigurationName = "${variant.name}ApiElements" - val runtimeElementsConfigurationName = "${variant.name}RuntimeElements" - - // KT-29476, the Android *Elements configurations need Kotlin MPP dependencies: - if (project.configurations.findByName(apiElementsConfigurationName) != null) { - project.addExtendsFromRelation(apiElementsConfigurationName, compilation.apiConfigurationName) - } - if (project.configurations.findByName(runtimeElementsConfigurationName) != null) { - project.addExtendsFromRelation(runtimeElementsConfigurationName, compilation.implementationConfigurationName) - project.addExtendsFromRelation(runtimeElementsConfigurationName, compilation.runtimeOnlyConfigurationName) - } - - listOf(apiElementsConfigurationName, runtimeElementsConfigurationName).forEach { outputConfigurationName -> - project.configurations.findByName(outputConfigurationName)?.let { configuration -> - configuration.usesPlatformOf(compilation.target) - configuration.attributes.attribute(Category.CATEGORY_ATTRIBUTE, project.categoryByName(Category.LIBRARY)) - } - } - } -} - -internal fun getTestedVariantData(variantData: BaseVariant): BaseVariant? = when (variantData) { - is TestVariant -> variantData.testedVariant - is UnitTestVariant -> variantData.testedVariant as? BaseVariant - else -> null -} - -internal fun getVariantName(variant: BaseVariant): String = variant.name - -@Suppress("UNCHECKED_CAST") -internal fun BaseVariant.getJavaTaskProvider(): TaskProvider = - this::class.java.methods.firstOrNull { it.name == "getJavaCompileProvider" } - ?.invoke(this) as? TaskProvider - ?: @Suppress("DEPRECATION") javaCompile.thisTaskProvider - -internal fun forEachVariant(project: Project, action: (BaseVariant) -> Unit) { - val androidExtension = project.extensions.getByName("android") - when (androidExtension) { - is AppExtension -> androidExtension.applicationVariants.all(action) - is LibraryExtension -> { - androidExtension.libraryVariants.all(action) - if (androidExtension is FeatureExtension) { - androidExtension.featureVariants.all(action) - } - } - is TestExtension -> androidExtension.applicationVariants.all(action) - } - if (androidExtension is TestedExtension) { - androidExtension.testVariants.all(action) - androidExtension.unitTestVariants.all(action) - } -} - -internal fun BaseVariant.getResDirectories(): FileCollection { - val getAllResourcesMethod = - this::class.java.methods.firstOrNull { it.name == "getAllRawAndroidResources" } - if (getAllResourcesMethod != null) { - val allResources = getAllResourcesMethod.invoke(this) as FileCollection - return allResources - } - - val project = mergeResources.project - return project.files(Callable { mergeResources?.computeResourceSetList0() ?: emptyList() }) -} - -//TODO A public API is expected for this purpose. Once it is available, use the public API -private fun MergeResources.computeResourceSetList0(): List? { - val computeResourceSetListMethod = MergeResources::class.java.declaredMethods - .firstOrNull { it.name == "computeResourceSetList" && it.parameterCount == 0 } ?: return null - - val oldIsAccessible = computeResourceSetListMethod.isAccessible - try { - computeResourceSetListMethod.isAccessible = true - - val resourceSets = computeResourceSetListMethod.invoke(this) as? Iterable<*> - - return resourceSets - ?.mapNotNull { resourceSet -> - val getSourceFiles = resourceSet?.javaClass?.methods?.find { it.name == "getSourceFiles" && it.parameterCount == 0 } - val files = getSourceFiles?.invoke(resourceSet) - @Suppress("UNCHECKED_CAST") - files as? Iterable - } - ?.flatten() - - } finally { - computeResourceSetListMethod.isAccessible = oldIsAccessible - } -} - -/** Filter for the AGP test variant classpath artifacts. */ -class AndroidTestedVariantArtifactsFilter( - private val artifactCollection: ArtifactCollection, - private val testedVariantDataIsNotNull: Boolean, - private val projectPath: String -) : Serializable, Spec { - - /** Make transient as it should be derived from the [artifactCollection] property which may change in configuration cached runs. */ - @Transient - private var filteredFiles = initFilteredFiles() - - private fun initFilteredFiles(): Lazy> { - return lazy { - artifactCollection.filter { - it.id.componentIdentifier is TestedComponentIdentifier || - // If tests depend on the main classes transitively, through a test dependency on another module which - // depends on this module, then there's no artifact with a TestedComponentIdentifier, so consider the artifact of the - // current module a friend path, too: - testedVariantDataIsNotNull && - (it.id.componentIdentifier as? ProjectComponentIdentifier)?.projectPath == projectPath - } - .mapTo(mutableSetOf()) { it.file } - } - } - - private fun writeObject(objectOutputStream: ObjectOutputStream) { - objectOutputStream.defaultWriteObject() - } - - private fun readObject(objectInputStream: ObjectInputStream) { - objectInputStream.defaultReadObject() - filteredFiles = initFilteredFiles() - } - - override fun isSatisfiedBy(element: File): Boolean { - return element in filteredFiles.value - } -} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/AndroidProjectHandler.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/AndroidProjectHandler.kt new file mode 100644 index 00000000000..6590029af8b --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/AndroidProjectHandler.kt @@ -0,0 +1,487 @@ +/* + * Copyright 2010-2019 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("PackageDirectoryMismatch") // Old package for compatibility +package org.jetbrains.kotlin.gradle.plugin + +import com.android.build.api.attributes.BuildTypeAttr +import com.android.build.gradle.* +import com.android.build.gradle.api.* +import com.android.build.gradle.tasks.MergeResources +import org.gradle.api.InvalidUserCodeException +import org.gradle.api.NamedDomainObjectCollection +import org.gradle.api.Project +import org.gradle.api.artifacts.ArtifactCollection +import org.gradle.api.artifacts.component.ProjectComponentIdentifier +import org.gradle.api.attributes.Attribute +import org.gradle.api.attributes.Category +import org.gradle.api.file.ConfigurableFileTree +import org.gradle.api.file.FileCollection +import org.gradle.api.file.SourceDirectorySet +import org.gradle.api.logging.Logging +import org.gradle.api.plugins.InvalidPluginException +import org.gradle.api.specs.Spec +import org.gradle.api.tasks.TaskProvider +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 +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.tasks.KotlinCompile +import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider +import org.jetbrains.kotlin.gradle.tasks.configuration.KotlinCompileConfig +import org.jetbrains.kotlin.gradle.tasks.thisTaskProvider +import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry +import org.jetbrains.kotlin.gradle.tooling.includeKotlinToolingMetadataInApk +import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation +import org.jetbrains.kotlin.gradle.utils.androidPluginIds +import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName +import java.io.File +import java.io.ObjectInputStream +import java.io.ObjectOutputStream +import java.io.Serializable +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 + + val kotlinOptions = KotlinJvmOptionsImpl() + kotlinOptions.noJdk = true + ext.addExtension(KOTLIN_OPTIONS_DSL_NAME, kotlinOptions) + + val plugin = androidPluginIds + .asSequence() + .mapNotNull { project.plugins.findPlugin(it) as? BasePlugin } + .firstOrNull() + ?: throw InvalidPluginException("'kotlin-android' expects one of the Android Gradle " + + "plugins to be applied to the project:\n\t" + + androidPluginIds.joinToString("\n\t") { "* $it" }) + + project.forEachVariant { variant -> + val variantName = getVariantName(variant) + + // Create the compilation and configure it first, then add to the compilations container. As this code is executed + // in afterEvaluate, a user's build script might have already attached item handlers to the compilations container, and those + // handlers might break when fired on a compilation that is not yet properly configured (e.g. KT-29964): + kotlinAndroidTarget.compilationFactory.create(variantName).let { compilation -> + compilation.androidVariant = variant + + setUpDependencyResolution(variant, compilation) + + preprocessVariant(variant, compilation, project, kotlinOptions, kotlinConfigurationTools.kotlinTasksProvider) + + @Suppress("UNCHECKED_CAST") + (kotlinAndroidTarget.compilations as NamedDomainObjectCollection).add(compilation) + } + + } + + project.whenEvaluated { + forEachVariant { variant -> + val compilation = kotlinAndroidTarget.compilations.getByName(getVariantName(variant)) + postprocessVariant(variant, compilation, project, ext, plugin) + + val subpluginEnvironment = SubpluginEnvironment.loadSubplugins(project) + subpluginEnvironment.addSubpluginOptions(project, compilation) + } + checkAndroidAnnotationProcessorDependencyUsage(project) + + addKotlinDependenciesToAndroidSourceSets(project, kotlinAndroidTarget) + } + + project.includeKotlinToolingMetadataInApk() + + addAndroidUnitTestTasksAsDependenciesToAllTest(project) + } + + /** + * The Android variants have their configurations extendsFrom relation set up in a way that only some of the configurations of the + * variants propagate the dependencies from production variants to test ones. To make this dependency propagation work for the Kotlin + * 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 + ) { + fun addDependenciesToAndroidSourceSet( + androidSourceSet: AndroidSourceSet, + apiConfigurationName: String, + implementationConfigurationName: String, + compileOnlyConfigurationName: String, + runtimeOnlyConfigurationName: String + ) { + if (project.configurations.findByName(androidSourceSet.apiConfigurationName) != null) { + project.addExtendsFromRelation(androidSourceSet.apiConfigurationName, apiConfigurationName) + } else { + // If any dependency is added to this configuration, report an error: + project.configurations.getByName(apiConfigurationName).dependencies.all { + throw InvalidUserCodeException( + "API dependencies are not allowed for Android source set ${androidSourceSet.name}. " + + "Please use an implementation dependency instead." + ) + } + } + project.addExtendsFromRelation(androidSourceSet.implementationConfigurationName, implementationConfigurationName) + project.addExtendsFromRelation(androidSourceSet.compileOnlyConfigurationName, compileOnlyConfigurationName) + project.addExtendsFromRelation(androidSourceSet.runtimeOnlyConfigurationName, runtimeOnlyConfigurationName) + } + + /** First, just add the dependencies from Kotlin source sets created for the Android source sets, + * 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 -> + addDependenciesToAndroidSourceSet( + androidSourceSet, + kotlinSourceSet.apiConfigurationName, + kotlinSourceSet.implementationConfigurationName, + kotlinSourceSet.compileOnlyConfigurationName, + kotlinSourceSet.runtimeOnlyConfigurationName + ) + } + } + } + + private fun addAndroidUnitTestTasksAsDependenciesToAllTest(project: Project) { + val allTestTaskName = project.kotlinTestRegistry.allTestsTaskName + project.tasks.matching { it.name == allTestTaskName }.configureEach { task -> + task.dependsOn(project.provider { + val androidUnitTestTasks = mutableListOf() + forEachVariant(project) { variant -> + if (variant is UnitTestVariant) { + // There's no API for getting the Android unit test tasks from the variant, so match them by name: + androidUnitTestTasks.add(project.provider { + project.tasks.matching { it.name == lowerCamelCaseName("test", variant.name) } + }) + } + } + androidUnitTestTasks + }) + } + } + + private fun preprocessVariant( + variantData: BaseVariant, + compilation: KotlinJvmAndroidCompilation, + project: Project, + rootKotlinOptions: KotlinJvmOptionsImpl, + tasksProvider: KotlinTasksProvider + ) { + // This function is called before the variantData is completely filled by the Android plugin. + // The fine details of variantData, such as AP options or Java sources, should not be trusted here. + val variantDataName = getVariantName(variantData) + logger.kotlinDebug("Process variant [$variantDataName]") + + val defaultSourceSet = project.kotlinExtension.sourceSets.maybeCreate(compilation.defaultSourceSetName) + + val configAction = KotlinCompileConfig(compilation) + configAction.configureTask { task -> + task.parentKotlinOptions.value(rootKotlinOptions).disallowChanges() + task.useModuleDetection.value(true).disallowChanges() + // store kotlin classes in separate directory. They will serve as class-path to java compiler + task.destinationDirectory.set(project.layout.buildDirectory.dir("tmp/kotlin-classes/$variantDataName")) + task.description = "Compiles the $variantDataName kotlin." + } + tasksProvider.registerKotlinJVMTask(project, compilation.compileKotlinTaskName, compilation.kotlinOptions, configAction) + + // 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.source(kotlinSourceSet) + } + } + + private fun postprocessVariant( + variantData: BaseVariant, + compilation: KotlinJvmAndroidCompilation, + project: Project, + androidExt: BaseExtension, + androidPlugin: BasePlugin + ) { + + getTestedVariantData(variantData)?.let { testedVariant -> + val testedVariantName = getVariantName(testedVariant) + val testedCompilation = compilation.target.compilations.getByName(testedVariantName) + compilation.associateWith(testedCompilation) + } + + val javaTask = variantData.getJavaTaskProvider() + val kotlinTask = compilation.compileKotlinTaskProvider + compilation.androidVariant.forEachJavaSourceDir { sources -> + kotlinTask.configure { + it.setSource(sources.dir) + it.dependsOn(sources) + } + } + wireKotlinTasks(project, compilation, androidPlugin, androidExt, variantData, javaTask, kotlinTask) + } + + private fun wireKotlinTasks( + project: Project, + compilation: KotlinJvmAndroidCompilation, + androidPlugin: BasePlugin, + androidExt: BaseExtension, + variantData: BaseVariant, + javaTask: TaskProvider, + kotlinTask: TaskProvider + ) { + val preJavaKotlinOutput = project.files(project.provider { + mutableListOf().apply { + add(kotlinTask.get().destinationDirectory.get().asFile) + if (Kapt3GradleSubplugin.isEnabled(project)) { + // Add Kapt3 output as well, since there's no SyncOutputTask with the new API + val kaptClasssesDir = Kapt3GradleSubplugin.getKaptGeneratedClassesDir(project, getVariantName(variantData)) + add(kaptClasssesDir) + } + } + }).builtBy(kotlinTask) + + val preJavaClasspathKey = variantData.registerPreJavacGeneratedBytecode(preJavaKotlinOutput) + kotlinTask.configure { kotlinTaskInstance -> + kotlinTaskInstance.libraries + .from(variantData.getCompileClasspath(preJavaClasspathKey)) + .from(Callable { AndroidGradleWrapper.getRuntimeJars(androidPlugin, androidExt) }) + + kotlinTaskInstance.javaOutputDir.set(javaTask.flatMap { it.destinationDirectory }) + } + + // Find the classpath entries that come from the tested variant and register them as the friend paths, lazily + val originalArtifactCollection = variantData.getCompileClasspathArtifacts(preJavaClasspathKey) + val testedVariantDataIsNotNull = getTestedVariantData(variantData) != null + val projectPath = project.path + compilation.testedVariantArtifacts.set( + originalArtifactCollection.artifactFiles.filter( + AndroidTestedVariantArtifactsFilter( + originalArtifactCollection, + testedVariantDataIsNotNull, + projectPath + ) + ) + ) + + compilation.output.classesDirs.from( + kotlinTask.flatMap { it.destinationDirectory }, + javaTask.flatMap { it.destinationDirectory } + ) + } + + fun getFlavorNames(variant: BaseVariant): List = variant.productFlavors.map { it.name } + + fun getBuildTypeName(variant: BaseVariant): String = variant.buildType.name + + // TODO the return type is actually `AbstractArchiveTask | TaskProvider`; + // change the signature once the Android Gradle plugin versions that don't support task providers are dropped + fun getLibraryOutputTask(variant: BaseVariant): Any? { + val getPackageLibraryProvider = variant.javaClass.methods + .find { it.name == "getPackageLibraryProvider" && it.parameterCount == 0 } + + return if (getPackageLibraryProvider != null) { + @Suppress("UNCHECKED_CAST") + getPackageLibraryProvider(variant) as TaskProvider + } else { + (variant as? LibraryVariant)?.packageLibrary + } + } + + fun setUpDependencyResolution(variant: BaseVariant, compilation: KotlinJvmAndroidCompilation) { + val project = compilation.target.project + + AbstractKotlinTargetConfigurator.defineConfigurationsForCompilation(compilation) + + compilation.compileDependencyFiles = variant.compileConfiguration.apply { + usesPlatformOf(compilation.target) + project.addExtendsFromRelation(name, compilation.compileDependencyConfigurationName) + } + + compilation.runtimeDependencyFiles = variant.runtimeConfiguration.apply { + usesPlatformOf(compilation.target) + project.addExtendsFromRelation(name, compilation.runtimeDependencyConfigurationName) + } + + val buildTypeAttrValue = project.objects.named(BuildTypeAttr::class.java, variant.buildType.name) + listOf(compilation.compileDependencyConfigurationName, compilation.runtimeDependencyConfigurationName).forEach { + project.configurations.findByName(it)?.attributes?.attribute(Attribute.of(BuildTypeAttr::class.java), buildTypeAttrValue) + } + + // TODO this code depends on the convention that is present in the Android plugin as there's no public API + // We should request such API in the Android plugin + val apiElementsConfigurationName = "${variant.name}ApiElements" + val runtimeElementsConfigurationName = "${variant.name}RuntimeElements" + + // KT-29476, the Android *Elements configurations need Kotlin MPP dependencies: + if (project.configurations.findByName(apiElementsConfigurationName) != null) { + project.addExtendsFromRelation(apiElementsConfigurationName, compilation.apiConfigurationName) + } + if (project.configurations.findByName(runtimeElementsConfigurationName) != null) { + project.addExtendsFromRelation(runtimeElementsConfigurationName, compilation.implementationConfigurationName) + project.addExtendsFromRelation(runtimeElementsConfigurationName, compilation.runtimeOnlyConfigurationName) + } + + listOf(apiElementsConfigurationName, runtimeElementsConfigurationName).forEach { outputConfigurationName -> + project.configurations.findByName(outputConfigurationName)?.let { configuration -> + configuration.usesPlatformOf(compilation.target) + configuration.attributes.attribute(Category.CATEGORY_ATTRIBUTE, project.categoryByName(Category.LIBRARY)) + } + } + } +} + +internal fun getTestedVariantData(variantData: BaseVariant): BaseVariant? = when (variantData) { + is TestVariant -> variantData.testedVariant + is UnitTestVariant -> variantData.testedVariant as? BaseVariant + else -> null +} + +internal fun getVariantName(variant: BaseVariant): String = variant.name + +@Suppress("UNCHECKED_CAST") +internal fun BaseVariant.getJavaTaskProvider(): TaskProvider = + this::class.java.methods.firstOrNull { it.name == "getJavaCompileProvider" } + ?.invoke(this) as? TaskProvider + ?: @Suppress("DEPRECATION") javaCompile.thisTaskProvider + +internal fun forEachVariant(project: Project, action: (BaseVariant) -> Unit) { + val androidExtension = project.extensions.getByName("android") + when (androidExtension) { + is AppExtension -> androidExtension.applicationVariants.all(action) + is LibraryExtension -> { + androidExtension.libraryVariants.all(action) + if (androidExtension is FeatureExtension) { + androidExtension.featureVariants.all(action) + } + } + is TestExtension -> androidExtension.applicationVariants.all(action) + } + if (androidExtension is TestedExtension) { + androidExtension.testVariants.all(action) + androidExtension.unitTestVariants.all(action) + } +} + +internal fun BaseVariant.getResDirectories(): FileCollection { + val getAllResourcesMethod = + this::class.java.methods.firstOrNull { it.name == "getAllRawAndroidResources" } + if (getAllResourcesMethod != null) { + val allResources = getAllResourcesMethod.invoke(this) as FileCollection + return allResources + } + + val project = mergeResources.project + return project.files(Callable { mergeResources?.computeResourceSetList0() ?: emptyList() }) +} + +//TODO A public API is expected for this purpose. Once it is available, use the public API +private fun MergeResources.computeResourceSetList0(): List? { + val computeResourceSetListMethod = MergeResources::class.java.declaredMethods + .firstOrNull { it.name == "computeResourceSetList" && it.parameterCount == 0 } ?: return null + + val oldIsAccessible = computeResourceSetListMethod.isAccessible + try { + computeResourceSetListMethod.isAccessible = true + + val resourceSets = computeResourceSetListMethod.invoke(this) as? Iterable<*> + + return resourceSets + ?.mapNotNull { resourceSet -> + val getSourceFiles = resourceSet?.javaClass?.methods?.find { it.name == "getSourceFiles" && it.parameterCount == 0 } + val files = getSourceFiles?.invoke(resourceSet) + @Suppress("UNCHECKED_CAST") + files as? Iterable + } + ?.flatten() + + } finally { + computeResourceSetListMethod.isAccessible = oldIsAccessible + } +} + +/** Filter for the AGP test variant classpath artifacts. */ +class AndroidTestedVariantArtifactsFilter( + private val artifactCollection: ArtifactCollection, + private val testedVariantDataIsNotNull: Boolean, + private val projectPath: String +) : Serializable, Spec { + + /** Make transient as it should be derived from the [artifactCollection] property which may change in configuration cached runs. */ + @Transient + private var filteredFiles = initFilteredFiles() + + private fun initFilteredFiles(): Lazy> { + return lazy { + artifactCollection.filter { + it.id.componentIdentifier is TestedComponentIdentifier || + // If tests depend on the main classes transitively, through a test dependency on another module which + // depends on this module, then there's no artifact with a TestedComponentIdentifier, so consider the artifact of the + // current module a friend path, too: + testedVariantDataIsNotNull && + (it.id.componentIdentifier as? ProjectComponentIdentifier)?.projectPath == projectPath + } + .mapTo(mutableSetOf()) { it.file } + } + } + + private fun writeObject(objectOutputStream: ObjectOutputStream) { + objectOutputStream.defaultWriteObject() + } + + private fun readObject(objectInputStream: ObjectInputStream) { + objectInputStream.defaultReadObject() + filteredFiles = initFilteredFiles() + } + + override fun isSatisfiedBy(element: File): Boolean { + return element in filteredFiles.value + } +} + +internal inline fun BaseVariant.forEachKotlinSourceSet( + kotlinAndroidTarget: KotlinAndroidTarget, + kotlinExtension: KotlinProjectExtension, + action: (KotlinSourceSet) -> Unit +) { + sourceSets + .mapNotNull { provider -> + val kotlinSourceSetName = AndroidProjectHandler.kotlinSourceSetNameForAndroidSourceSet(kotlinAndroidTarget, provider.name) + kotlinExtension.sourceSets.findByName(kotlinSourceSetName) + } + .forEach(action) +} + +internal inline fun BaseVariant.forEachKotlinSourceDirectorySet(action: (SourceDirectorySet) -> Unit) { + sourceSets + .mapNotNull { it.getExtension(KOTLIN_DSL_NAME) } + .forEach(action) +} + +internal inline fun BaseVariant.forEachJavaSourceDir(action: (ConfigurableFileTree) -> Unit) { + getSourceFolders(SourceKind.JAVA).forEach(action) +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTarget.kt index 0355114f795..497037715fc 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTarget.kt @@ -67,7 +67,7 @@ abstract class KotlinAndroidTarget @Inject constructor( var publishLibraryVariantsGroupedByFlavor = false private fun checkPublishLibraryVariantsExist() { - fun AbstractAndroidProjectHandler.getLibraryVariantNames() = + fun AndroidProjectHandler.getLibraryVariantNames() = mutableSetOf().apply { project.forEachVariant { if (getLibraryOutputTask(it) != null) @@ -99,7 +99,7 @@ abstract class KotlinAndroidTarget @Inject constructor( return publishLibraryVariants?.contains(getVariantName(variant)) ?: true } - private fun AbstractAndroidProjectHandler.doCreateComponents(): Set { + private fun AndroidProjectHandler.doCreateComponents(): Set { val publishableVariants = mutableListOf() .apply { project.forEachVariant { add(it) } } @@ -173,7 +173,7 @@ abstract class KotlinAndroidTarget @Inject constructor( }.toSet() } - private fun AbstractAndroidProjectHandler.createAndroidUsageContexts( + private fun AndroidProjectHandler.createAndroidUsageContexts( variant: BaseVariant, compilation: KotlinCompilation<*>, artifactClassifier: String?,