diff --git a/libraries/examples/kotlin-gradle-subplugin-example/src/main/kotlin/example/ExampleSubplugin.kt b/libraries/examples/kotlin-gradle-subplugin-example/src/main/kotlin/example/ExampleSubplugin.kt index 7c980c0d1ef..0034f23984c 100644 --- a/libraries/examples/kotlin-gradle-subplugin-example/src/main/kotlin/example/ExampleSubplugin.kt +++ b/libraries/examples/kotlin-gradle-subplugin-example/src/main/kotlin/example/ExampleSubplugin.kt @@ -16,13 +16,9 @@ package example -import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin import org.gradle.api.Project -import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.compile.AbstractCompile -import org.jetbrains.kotlin.gradle.plugin.JetBrainsSubpluginArtifact -import org.jetbrains.kotlin.gradle.plugin.SubpluginArtifact -import org.jetbrains.kotlin.gradle.plugin.SubpluginOption +import org.jetbrains.kotlin.gradle.plugin.* class ExampleSubplugin : KotlinGradleSubplugin { @@ -31,12 +27,12 @@ class ExampleSubplugin : KotlinGradleSubplugin { } override fun apply( - project: Project, - kotlinCompile: AbstractCompile, - javaCompile: AbstractCompile, - variantData: Any?, - androidProjectHandler: Any?, - javaSourceSet: SourceSet? + project: Project, + kotlinCompile: AbstractCompile, + javaCompile: AbstractCompile?, + variantData: Any?, + androidProjectHandler: Any?, + kotlinCompilation: KotlinCompilation? ): List { println("ExampleSubplugin loaded") return listOf(SubpluginOption("exampleKey", "exampleValue")) diff --git a/libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/AllOpenSubplugin.kt b/libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/AllOpenSubplugin.kt index 638c24014e9..1f300124674 100644 --- a/libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/AllOpenSubplugin.kt +++ b/libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/AllOpenSubplugin.kt @@ -18,16 +18,10 @@ package org.jetbrains.kotlin.allopen.gradle import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.artifacts.ResolvedArtifact -import org.gradle.api.internal.AbstractTask -import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry import org.jetbrains.kotlin.allopen.gradle.model.builder.AllOpenModelBuilder -import org.jetbrains.kotlin.gradle.plugin.JetBrainsSubpluginArtifact -import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin -import org.jetbrains.kotlin.gradle.plugin.SubpluginArtifact -import org.jetbrains.kotlin.gradle.plugin.SubpluginOption +import org.jetbrains.kotlin.gradle.plugin.* import javax.inject.Inject class AllOpenGradleSubplugin @Inject internal constructor(private val registry: ToolingModelBuilderRegistry) : Plugin { @@ -56,12 +50,12 @@ class AllOpenKotlinGradleSubplugin : KotlinGradleSubplugin { override fun isApplicable(project: Project, task: AbstractCompile) = AllOpenGradleSubplugin.isEnabled(project) override fun apply( - project: Project, - kotlinCompile: AbstractCompile, - javaCompile: AbstractCompile, - variantData: Any?, - androidProjectHandler: Any?, - javaSourceSet: SourceSet? + project: Project, + kotlinCompile: AbstractCompile, + javaCompile: AbstractCompile?, + variantData: Any?, + androidProjectHandler: Any?, + kotlinCompilation: KotlinCompilation? ): List { if (!AllOpenGradleSubplugin.isEnabled(project)) return emptyList() diff --git a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleSubplugin.kt index d44cd82d9e2..32b3b42b764 100644 --- a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleSubplugin.kt @@ -17,7 +17,6 @@ package org.jetbrains.kotlin.gradle.plugin import org.gradle.api.Project -import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.compile.AbstractCompile import java.io.File @@ -52,12 +51,12 @@ interface KotlinGradleSubplugin { fun isApplicable(project: Project, task: AbstractCompile): Boolean fun apply( - project: Project, - kotlinCompile: KotlinCompile, - javaCompile: AbstractCompile, - variantData: Any?, - androidProjectHandler: Any?, - javaSourceSet: SourceSet? + project: Project, + kotlinCompile: KotlinCompile, + javaCompile: AbstractCompile?, + variantData: Any?, + androidProjectHandler: Any?, + kotlinCompilation: KotlinCompilation? ): List fun getSubpluginKotlinTasks( diff --git a/libraries/tools/kotlin-gradle-plugin/src/agp25/kotlin/org/jetbrains/kotlin/gradle/plugin/android/Android25ProjectHandler.kt b/libraries/tools/kotlin-gradle-plugin/src/agp25/kotlin/org/jetbrains/kotlin/gradle/plugin/android/Android25ProjectHandler.kt index 8fcb65f0f5b..476995e2e0e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/agp25/kotlin/org/jetbrains/kotlin/gradle/plugin/android/Android25ProjectHandler.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/agp25/kotlin/org/jetbrains/kotlin/gradle/plugin/android/Android25ProjectHandler.kt @@ -11,7 +11,9 @@ import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin import org.jetbrains.kotlin.gradle.internal.KaptTask import org.jetbrains.kotlin.gradle.internal.KaptVariantData 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.utils.addExtendsFromRelation import java.io.File @Suppress("unused") @@ -36,13 +38,15 @@ class Android25ProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools } } - override fun wireKotlinTasks(project: Project, - androidPlugin: BasePlugin, - androidExt: BaseExtension, - variantData: BaseVariant, - javaTask: AbstractCompile, - kotlinTask: KotlinCompile) { - + override fun wireKotlinTasks( + project: Project, + compilation: KotlinJvmAndroidCompilation, + androidPlugin: BasePlugin, + androidExt: BaseExtension, + variantData: BaseVariant, + javaTask: AbstractCompile, + kotlinTask: KotlinCompile + ) { val preJavaKotlinOutputFiles = mutableListOf().apply { add(kotlinTask.destinationDir) if (Kapt3GradleSubplugin.isEnabled(project)) { @@ -95,6 +99,20 @@ class Android25ProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools return variantData.mergeResources?.computeResourceSetList0() ?: emptyList() } + override fun setUpDependencyResolution(variant: BaseVariant, compilation: KotlinJvmAndroidCompilation) { + val project = compilation.target.project + + 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) + } + } + private inner class KaptVariant(variantData: BaseVariant) : KaptVariantData(variantData) { override val name: String = getVariantName(variantData) override val sourceProviders: Iterable = getSourceProviders(variantData) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinProjectExtension.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinProjectExtension.kt index ad092e79571..fd5d84268c7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinProjectExtension.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinProjectExtension.kt @@ -16,13 +16,19 @@ package org.jetbrains.kotlin.gradle.dsl +import org.gradle.api.NamedDomainObjectContainer import org.gradle.api.Project import org.gradle.api.internal.plugins.DslObject +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaTarget +import org.jetbrains.kotlin.gradle.plugin.source.KotlinSourceSet import kotlin.reflect.KClass -internal fun Project.createKotlinExtension(extensionClass: KClass) { - val kotlinExt = extensions.create("kotlin", extensionClass.java) +private const val KOTLIN_PROJECT_EXTENSION_NAME = "kotlin" + +internal fun Project.createKotlinExtension(extensionClass: KClass): KotlinProjectExtension { + val kotlinExt = extensions.create(KOTLIN_PROJECT_EXTENSION_NAME, extensionClass.java) DslObject(kotlinExt).extensions.create("experimental", ExperimentalExtension::class.java) + return kotlinExtension } internal val Project.kotlinExtension: KotlinProjectExtension @@ -38,7 +44,11 @@ open class KotlinProjectExtension { internal set(value) { DslObject(this).extensions.add("sourceSets", value) } } -open class KotlinJvmProjectExtension : KotlinProjectExtension() { +open class KotlinSingleJavaTargetExtension : KotlinProjectExtension() { + internal lateinit var target: KotlinWithJavaTarget +} + +open class KotlinJvmProjectExtension : KotlinSingleJavaTargetExtension() { /** * With Gradle 4.0+, disables the separate output directory for Kotlin, falling back to sharing the deprecated * single classes directory per source set. With Gradle < 4.0, has no effect. diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidSubplugin.kt index 9da70ab4b2e..5e27c4e0e5e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidSubplugin.kt @@ -25,7 +25,6 @@ import com.android.build.gradle.internal.variant.TestVariantData import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.UnknownDomainObjectException -import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry import org.jetbrains.kotlin.gradle.model.builder.KotlinAndroidExtensionModelBuilder @@ -90,12 +89,12 @@ class AndroidSubplugin : KotlinGradleSubplugin { } override fun apply( - project: Project, - kotlinCompile: KotlinCompile, - javaCompile: AbstractCompile, - variantData: Any?, - androidProjectHandler: Any?, - javaSourceSet: SourceSet? + project: Project, + kotlinCompile: KotlinCompile, + javaCompile: AbstractCompile?, + variantData: Any?, + androidProjectHandler: Any?, + kotlinCompilation: KotlinCompilation? ): List { val androidExtension = project.extensions.getByName("android") as? BaseExtension ?: return emptyList() val androidExtensionsExtension = project.extensions.getByType(AndroidExtensionsExtension::class.java) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt index 7bde3e33ae7..4dc68e096e5 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt @@ -158,10 +158,10 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { private inner class Kapt3SubpluginContext( val project: Project, val kotlinCompile: KotlinCompile, - val javaCompile: AbstractCompile, + val javaCompile: AbstractCompile?, val kaptVariantData: KaptVariantData<*>?, val sourceSetName: String, - val javaSourceSet: SourceSet?, + val kotlinCompilation: KotlinCompilation?, val kaptExtension: KaptExtension, val kaptClasspathConfigurations: List ) { @@ -171,14 +171,14 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { } override fun apply( - project: Project, - kotlinCompile: KotlinCompile, - javaCompile: AbstractCompile, - variantData: Any?, - androidProjectHandler: Any?, - javaSourceSet: SourceSet? + project: Project, + kotlinCompile: KotlinCompile, + javaCompile: AbstractCompile?, + variantData: Any?, + androidProjectHandler: Any?, + kotlinCompilation: KotlinCompilation? ): List { - assert((variantData != null) xor (javaSourceSet != null)) + assert((variantData != null) xor (kotlinCompilation != null)) val buildDependencies = arrayListOf() val kaptConfigurations = arrayListOf() @@ -200,10 +200,10 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { kaptVariantData.name } else { - if (javaSourceSet == null) error("Java source set should not be null") + if (kotlinCompilation == null) error("In non-Android projects, Kotlin compilation should not be null") - handleSourceSet(javaSourceSet.name) - javaSourceSet.name + handleSourceSet(kotlinCompilation.compilationName) + kotlinCompilation.compilationName } val kaptExtension = project.extensions.getByType(KaptExtension::class.java) @@ -212,7 +212,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { val context = Kapt3SubpluginContext( project, kotlinCompile, javaCompile, - kaptVariantData, sourceSetName, javaSourceSet, kaptExtension, nonEmptyKaptConfigurations + kaptVariantData, sourceSetName, kotlinCompilation, kaptExtension, nonEmptyKaptConfigurations ) val kaptGenerateStubsTask = context.createKaptGenerateStubsTask() @@ -245,7 +245,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { pluginOptions += SubpluginOption("aptMode", aptMode) disableAnnotationProcessingInJavaTask() - javaCompile.source(generatedFilesDir) + javaCompile?.source(generatedFilesDir) pluginOptions += FilesSubpluginOption("sources", listOf(generatedFilesDir)) pluginOptions += FilesSubpluginOption("classes", listOf(getKaptGeneratedClassesDir(project, sourceSetName))) @@ -362,18 +362,22 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { kaptTask.kotlinSourcesDestinationDir = kotlinSourcesOutputDir kaptTask.classesDir = classesOutputDir - javaSourceSet?.output?.apply { - if (tryAddClassesDir { project.files(classesOutputDir).builtBy(kaptTask) }) { - kotlinCompile.attachClassesDir { classesOutputDir } + kotlinCompilation?.run { + output.apply { + if (tryAddClassesDir { project.files(classesOutputDir).builtBy(kaptTask) }) { + kotlinCompile.attachClassesDir { classesOutputDir } + } } } kotlinCompile.source(sourcesOutputDir, kotlinSourcesOutputDir) - if (kaptVariantData != null) { - kaptVariantData.registerGeneratedJavaSource(project, kaptTask, javaCompile) - } else { - registerGeneratedJavaSource(kaptTask, javaCompile) + if (javaCompile != null) { + if (kaptVariantData != null) { + kaptVariantData.registerGeneratedJavaSource(project, kaptTask, javaCompile) + } else { + registerGeneratedJavaSource(kaptTask, javaCompile) + } } kaptTask.kaptClasspathConfigurations = kaptClasspathConfigurations diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinMultiplatformPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinMultiplatformPlugin.kt index 03c7f0360b6..2fc20741273 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinMultiplatformPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinMultiplatformPlugin.kt @@ -21,9 +21,8 @@ import org.gradle.api.* import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.ProjectDependency import org.gradle.api.file.SourceDirectorySet -import org.gradle.api.plugins.JavaPluginConvention -import org.gradle.api.tasks.SourceSet -import org.gradle.api.tasks.SourceSetContainer +import org.jetbrains.kotlin.gradle.dsl.kotlinExtension +import org.jetbrains.kotlin.gradle.plugin.source.KotlinSourceSet import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile abstract class KotlinPlatformPluginBase(protected val platformName: String) : Plugin { @@ -110,7 +109,10 @@ open class KotlinPlatformImplementationPluginBase(platformName: String) : Kotlin // Since the two projects may add source sets in arbitrary order, and both may do that after the plugin is applied, // we need to handle all source sets of the two projects and connect them once we get a match: // todo warn if no match found - matchSymmetricallyByNames(commonProject.sourceSets, namedSourceSetsContainer(platformProject)) { commonSourceSet, _ -> + matchSymmetricallyByNames( + getKotlinSourceSetsSafe(commonProject), + namedSourceSetsContainer(platformProject) + ) { commonSourceSet: Named, _ -> addCommonSourceSetToPlatformSourceSet(commonSourceSet, platformProject) } } @@ -121,13 +123,13 @@ open class KotlinPlatformImplementationPluginBase(platformName: String) : Kotlin * regardless of the order in which they are added to the containers. */ private fun matchSymmetricallyByNames( - containerA: NamedDomainObjectContainer, - containerB: NamedDomainObjectContainer, + containerA: NamedDomainObjectCollection, + containerB: NamedDomainObjectCollection, whenMatched: (A, B) -> Unit ) { val matchedNames = mutableSetOf() - fun NamedDomainObjectContainer.matchAllWith(other: NamedDomainObjectContainer, match: (T, R) -> Unit) { + fun NamedDomainObjectCollection.matchAllWith(other: NamedDomainObjectCollection, match: (T, R) -> Unit) { this@matchAllWith.all { item -> val itemName = this@matchAllWith.namer.determineName(item) if (itemName !in matchedNames) { @@ -144,36 +146,38 @@ open class KotlinPlatformImplementationPluginBase(platformName: String) : Kotlin } protected open fun namedSourceSetsContainer(project: Project): NamedDomainObjectContainer<*> = - project.sourceSets + project.kotlinExtension.sourceSets - protected open fun addCommonSourceSetToPlatformSourceSet(commonSourceSet: SourceSet, platformProject: Project) { - val platformTask = platformProject.tasks - .filterIsInstance>() - .firstOrNull { it.sourceSetName == commonSourceSet.name } + protected open fun addCommonSourceSetToPlatformSourceSet(commonSourceSet: Named, platformProject: Project) { + platformProject.whenEvaluated { // At the point when the source set in the platform module is created, the task does not exist + val platformTask = platformProject.tasks + .filterIsInstance>() + .single { it.sourceSetName == commonSourceSet.name } - platformTask?.source(commonSourceSet.kotlin!!) + platformTask.source(getKotlinSourceDirectorySetSafe(commonSourceSet)) + } } - protected val SourceSet.kotlin: SourceDirectorySet? - get() { - // Access through reflection, because another project's KotlinSourceSet might be loaded - // by a different class loader: - val convention = (getConvention("kotlin") ?: getConvention("kotlin2js")) ?: return null - val kotlinSourceSetIface = convention.javaClass.interfaces.find { it.name == KotlinSourceSet::class.qualifiedName } - val getKotlin = kotlinSourceSetIface?.methods?.find { it.name == "getKotlin" } ?: return null - return getKotlin(convention) as? SourceDirectorySet - } + private fun getKotlinSourceSetsSafe(project: Project): NamedDomainObjectCollection { + // Access through reflection, because another project's KotlinProjectExtension might be loaded by a different class loader: + val kotlinExt = project.extensions.getByName("kotlin") + @Suppress("UNCHECKED_CAST") + val sourceSets = kotlinExt.javaClass.getMethod("getSourceSets").invoke(kotlinExt) as NamedDomainObjectCollection + return sourceSets + } - companion object { - @JvmStatic - protected fun Project.whenEvaluated(fn: Project.() -> T) { - if (state.executed) { - fn() - } - else { - afterEvaluate { it.fn() } - } - } + protected fun getKotlinSourceDirectorySetSafe(from: Any): SourceDirectorySet? { + val getKotlin = from.javaClass.getMethod("getKotlin") + return getKotlin(from) as? SourceDirectorySet + } +} + +internal fun Project.whenEvaluated(fn: Project.() -> T) { + if (state.executed) { + fn() + } + else { + afterEvaluate { it.fn() } } } @@ -190,11 +194,12 @@ open class KotlinPlatformAndroidPlugin : KotlinPlatformImplementationPluginBase( override fun namedSourceSetsContainer(project: Project): NamedDomainObjectContainer<*> = (project.extensions.getByName("android") as BaseExtension).sourceSets - override fun addCommonSourceSetToPlatformSourceSet(commonSourceSet: SourceSet, platformProject: Project) { + override fun addCommonSourceSetToPlatformSourceSet(commonSourceSet: Named, platformProject: Project) { val androidExtension = platformProject.extensions.getByName("android") as BaseExtension val androidSourceSet = androidExtension.sourceSets.findByName(commonSourceSet.name) ?: return - val kotlinSourceSet = androidSourceSet.getConvention(KOTLIN_DSL_NAME) as? KotlinSourceSet ?: return - kotlinSourceSet.kotlin.source(commonSourceSet.kotlin!!) + val kotlinSourceSet = androidSourceSet.getConvention(KOTLIN_DSL_NAME) as? KotlinSourceSet + ?: return + kotlinSourceSet.kotlin.source(getKotlinSourceDirectorySetSafe(commonSourceSet)!!) } } @@ -210,7 +215,4 @@ open class KotlinPlatformJsPlugin : KotlinPlatformImplementationPluginBase("js") project.applyPlugin() super.apply(project) } -} - -private val Project.sourceSets: SourceSetContainer - get() = convention.getPlugin(JavaPluginConvention::class.java).sourceSets +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt index a7870c74c82..dc6588e90c3 100755 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt @@ -5,7 +5,6 @@ import com.android.build.gradle.BasePlugin import com.android.builder.model.SourceProvider import groovy.lang.Closure import org.gradle.api.* -import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.ExternalDependency import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.FileCollection @@ -13,7 +12,6 @@ import org.gradle.api.file.SourceDirectorySet import org.gradle.api.logging.Logger import org.gradle.api.logging.Logging import org.gradle.api.plugins.InvalidPluginException -import org.gradle.api.plugins.JavaBasePlugin import org.gradle.api.plugins.JavaPlugin import org.gradle.api.plugins.JavaPluginConvention import org.gradle.api.tasks.CompileClasspathNormalizer @@ -26,11 +24,15 @@ import org.gradle.jvm.tasks.Jar import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl +import org.jetbrains.kotlin.gradle.dsl.KotlinSingleJavaTargetExtension +import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.getKaptGeneratedClassesDir import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin import org.jetbrains.kotlin.gradle.internal.KaptVariantData import org.jetbrains.kotlin.gradle.internal.checkAndroidAnnotationProcessorDependencyUsage import org.jetbrains.kotlin.gradle.model.builder.KotlinModelBuilder +import org.jetbrains.kotlin.gradle.plugin.mpp.* +import org.jetbrains.kotlin.gradle.plugin.source.KotlinSourceSet import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubplugin import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlin.gradle.utils.* @@ -47,58 +49,90 @@ val KOTLIN_JS_DSL_NAME = "kotlin2js" val KOTLIN_OPTIONS_DSL_NAME = "kotlinOptions" internal abstract class KotlinSourceSetProcessor>( - val project: Project, - val javaBasePlugin: JavaBasePlugin, - val sourceSet: SourceSet, - val tasksProvider: KotlinTasksProvider, - val kotlinSourceSetProvider: KotlinSourceSetProvider, - val dslExtensionName: String, - val compileTaskNameSuffix: String, - val taskDescription: String + val project: Project, + val tasksProvider: KotlinTasksProvider, + val taskDescription: String, + val kotlinCompilation: KotlinCompilation ) { abstract protected fun doTargetSpecificProcessing() protected val logger = Logging.getLogger(this.javaClass)!! protected val isSeparateClassesDirSupported: Boolean by lazy { !CopyClassesToJavaOutputStatus.isEnabled(project) && - sourceSet.output.javaClass.methods.any { it.name == "getClassesDirs" } + kotlinCompilation.output.javaClass.methods.any { it.name == "getClassesDirs" } } - protected val sourceSetName: String = sourceSet.name - protected val sourceRootDir: String = "src/$sourceSetName/kotlin" - protected val kotlinSourceSet: KotlinSourceSet = createKotlinSourceSet() + protected val sourceSetName: String = kotlinCompilation.compilationName + protected val kotlinTask: T = createKotlinCompileTask() protected open val defaultKotlinDestinationDir: File - get() = if (isSeparateClassesDirSupported) - File(project.buildDir, "classes/kotlin/${sourceSet.name}") else - sourceSet.output.classesDir + get() { + return if (isSeparateClassesDirSupported) { + val kotlinExt = project.kotlinExtension + val targetSubDirectory = + if (kotlinExt is KotlinSingleJavaTargetExtension) + "" // In single-target projects, don't add the target name part to this path + else + kotlinCompilation.target.disambiguationClassifier?.let { "$it/" }.orEmpty() + File(project.buildDir, "classes/kotlin/$targetSubDirectory${kotlinCompilation.compilationName}") + } else { + kotlinCompilation.output.classesDir + } + } - fun run() { - addKotlinDirSetToSources() + private fun createKotlinCompileTask(): T { + val name = kotlinCompilation.compileKotlinTaskName + logger.kotlinDebug("Creating kotlin compile task $name") + val kotlinCompile = doCreateTask(project, name) + kotlinCompile.description = taskDescription + kotlinCompile.mapClasspath { kotlinCompilation.compileDependencyFiles } + kotlinCompile.setDestinationDir { defaultKotlinDestinationDir } + kotlinCompilation.output.tryAddClassesDir { project.files(kotlinTask.destinationDir).builtBy(kotlinTask) } + return kotlinCompile + } + + open fun run() { doTargetSpecificProcessing() } - private fun createKotlinSourceSet(): KotlinSourceSet { - logger.kotlinDebug("Creating KotlinSourceSet for $sourceSet") - val kotlinSourceSet = kotlinSourceSetProvider.create(sourceSet.name) - kotlinSourceSet.kotlin.srcDir(project.file(sourceRootDir)) - sourceSet.addConvention(dslExtensionName, kotlinSourceSet) - return kotlinSourceSet + protected abstract fun doCreateTask(project: Project, taskName: String): T +} + +internal abstract class KotlinJavaSourceSetProcessor>( + project: Project, + tasksProvider: KotlinTasksProvider, + taskDescription: String, + val javaSourceSet: SourceSet?, + kotlinCompilation: KotlinCompilation +): KotlinSourceSetProcessor( + project, tasksProvider, taskDescription, kotlinCompilation +) { + override fun run() { + addKotlinDirSetToSources() + super.run() } private fun addKotlinDirSetToSources() { - val kotlinDirSet = kotlinSourceSet.kotlin + if (javaSourceSet == null) + return + + val kotlinDirSets = kotlinCompilation.kotlinSourceSets.map(KotlinSourceSet::kotlin) // Try to avoid duplicate Java sources in allSource: - val kotlinSrcDirsToAdd = filterOutJavaSrcDirsIfPossible(kotlinDirSet) + val kotlinSrcDirsToAdd = kotlinDirSets.map { filterOutJavaSrcDirsIfPossible(it) } - sourceSet.allJava.srcDirs(kotlinSrcDirsToAdd) - sourceSet.allSource.srcDirs(kotlinSrcDirsToAdd) - sourceSet.resources.filter.exclude { it.file in kotlinDirSet } + kotlinSrcDirsToAdd.forEach { kotlinSrcDirs -> + javaSourceSet.allJava.srcDirs(kotlinSrcDirs) + javaSourceSet.allSource.srcDirs(kotlinSrcDirs) + javaSourceSet.resources.filter.exclude { it.file in kotlinSrcDirs } + } } private fun filterOutJavaSrcDirsIfPossible(sourceDirectorySet: SourceDirectorySet): FileCollection { + if (javaSourceSet == null) + return sourceDirectorySet + // If the API used below is not available, fall back to not filtering the Java sources. if (SourceDirectorySet::class.java.methods.none { it.name == "getSourceDirectories" }) { return sourceDirectorySet @@ -110,35 +144,19 @@ internal abstract class KotlinSourceSetProcessor>( } // Build a lazily-resolved file collection that filters out Java sources from sources of this sourceDirectorySet - return getSourceDirectories(sourceDirectorySet).minus(getSourceDirectories(sourceSet.java)) + return getSourceDirectories(sourceDirectorySet).minus(getSourceDirectories(javaSourceSet.java)) } - - private fun createKotlinCompileTask(): T { - val name = sourceSet.getCompileTaskName(compileTaskNameSuffix) - logger.kotlinDebug("Creating kotlin compile task $name") - val kotlinCompile = doCreateTask(project, name) - kotlinCompile.description = taskDescription - kotlinCompile.mapClasspath { sourceSet.compileClasspath } - kotlinCompile.setDestinationDir { defaultKotlinDestinationDir } - sourceSet.output.tryAddClassesDir { project.files(kotlinTask.destinationDir).builtBy(kotlinTask) } - return kotlinCompile - } - - protected abstract fun doCreateTask(project: Project, taskName: String): T } internal class Kotlin2JvmSourceSetProcessor( - project: Project, - javaBasePlugin: JavaBasePlugin, - sourceSet: SourceSet, - tasksProvider: KotlinTasksProvider, - kotlinSourceSetProvider: KotlinSourceSetProvider, - private val kotlinPluginVersion: String -) : KotlinSourceSetProcessor( - project, javaBasePlugin, sourceSet, tasksProvider, kotlinSourceSetProvider, - dslExtensionName = KOTLIN_DSL_NAME, - compileTaskNameSuffix = "kotlin", - taskDescription = "Compiles the $sourceSet.kotlin." + project: Project, + tasksProvider: KotlinTasksProvider, + kotlinCompilation: KotlinCompilation, + private val kotlinPluginVersion: String +) : KotlinJavaSourceSetProcessor( + project, tasksProvider, taskDescription = "Compiles the $kotlinCompilation.", + javaSourceSet = if (kotlinCompilation is KotlinWithJavaCompilation) kotlinCompilation.javaSourceSet else null, + kotlinCompilation = kotlinCompilation ) { override val defaultKotlinDestinationDir: File get() = if (!isSeparateClassesDirSupported) @@ -146,44 +164,38 @@ internal class Kotlin2JvmSourceSetProcessor( super.defaultKotlinDestinationDir override fun doCreateTask(project: Project, taskName: String): KotlinCompile = - tasksProvider.createKotlinJVMTask(project, taskName, sourceSet.name) + tasksProvider.createKotlinJVMTask(project, taskName, kotlinCompilation.compilationName) override fun doTargetSpecificProcessing() { - kotlinSourceSet.kotlin.source(sourceSet.java) - Kapt3KotlinGradleSubplugin.createAptConfigurationIfNeeded(project, sourceSet.name) + Kapt3KotlinGradleSubplugin.createAptConfigurationIfNeeded(project, kotlinCompilation.compilationName) project.afterEvaluate { project -> - if (project != null) { - val javaTask = project.tasks.findByName(sourceSet.compileJavaTaskName) + val javaTask = javaSourceSet?.let { project.tasks.findByName(it.compileJavaTaskName) as JavaCompile } - val subpluginEnvironment = loadSubplugins(project, kotlinPluginVersion) - val appliedPlugins = subpluginEnvironment.addSubpluginOptions( - project, kotlinTask, javaTask as JavaCompile, null, null, sourceSet) + val subpluginEnvironment = loadSubplugins(project, kotlinPluginVersion) + val appliedPlugins = subpluginEnvironment.addSubpluginOptions( + project, kotlinTask, javaTask, null, null, kotlinCompilation + ) - // KotlinCompile.source(kotlinDirSet) should be called only after all java roots are added to kotlinDirSet - // otherwise some java roots can be ignored - kotlinTask.source(kotlinSourceSet.kotlin) - appliedPlugins - .flatMap { it.getSubpluginKotlinTasks(project, kotlinTask) } - .forEach { it.source(kotlinSourceSet.kotlin) } + appliedPlugins + .flatMap { it.getSubpluginKotlinTasks(project, kotlinTask) } + .forEach { plugin -> kotlinCompilation.kotlinSourceSets.forEach { sourceSet -> plugin.source(sourceSet.kotlin) } } - configureJavaTask(kotlinTask, javaTask, logger) + javaTask?.let { configureJavaTask(kotlinTask, it, logger) } - var syncOutputTask: SyncOutputTask? = null + var syncOutputTask: SyncOutputTask? = null - if (!isSeparateClassesDirSupported) { - syncOutputTask = createSyncOutputTask(project, kotlinTask, javaTask, sourceSetName) - } - - if (project.pluginManager.hasPlugin("java-library") && sourceSetName == SourceSet.MAIN_SOURCE_SET_NAME) { - val (classesProviderTask, classesDirectory) = when { - isSeparateClassesDirSupported -> kotlinTask.let { it to it.destinationDir } - else -> syncOutputTask!!.let { it to it.javaOutputDir } - } - - registerKotlinOutputForJavaLibrary(classesDirectory, classesProviderTask) + if (!isSeparateClassesDirSupported && javaTask != null) { + syncOutputTask = createSyncOutputTask(project, kotlinTask, javaTask, sourceSetName) + } + + if (project.pluginManager.hasPlugin("java-library") && sourceSetName == SourceSet.MAIN_SOURCE_SET_NAME) { + val (classesProviderTask, classesDirectory) = when { + isSeparateClassesDirSupported -> kotlinTask.let { it to it.destinationDir } + else -> syncOutputTask!!.let { it to it.javaOutputDir } } + registerKotlinOutputForJavaLibrary(classesDirectory, classesProviderTask) } } } @@ -233,37 +245,35 @@ internal fun SourceSetOutput.tryAddClassesDir( } internal class Kotlin2JsSourceSetProcessor( - project: Project, - javaBasePlugin: JavaBasePlugin, - sourceSet: SourceSet, - tasksProvider: KotlinTasksProvider, - kotlinSourceSetProvider: KotlinSourceSetProvider, - private val kotlinPluginVersion: String + project: Project, + tasksProvider: KotlinTasksProvider, + kotlinCompilation: KotlinCompilation, + private val kotlinPluginVersion: String ) : KotlinSourceSetProcessor( - project, javaBasePlugin, sourceSet, tasksProvider, kotlinSourceSetProvider, - dslExtensionName = KOTLIN_JS_DSL_NAME, - taskDescription = "Compiles the kotlin sources in $sourceSet to JavaScript.", - compileTaskNameSuffix = "kotlin2Js" + project, tasksProvider, taskDescription = "Compiles the Kotlin sources in $kotlinCompilation to JavaScript.", + kotlinCompilation = kotlinCompilation ) { override fun doCreateTask(project: Project, taskName: String): Kotlin2JsCompile = - tasksProvider.createKotlinJSTask(project, taskName, sourceSet.name) + tasksProvider.createKotlinJSTask(project, taskName, kotlinCompilation.compilationName) override fun doTargetSpecificProcessing() { - project.tasks.findByName(sourceSet.classesTaskName)!!.dependsOn(kotlinTask) - kotlinTask.source(kotlinSourceSet.kotlin) + project.tasks.findByName(kotlinCompilation.compileAllTaskName)!!.dependsOn(kotlinTask) + createCleanSourceMapTask() - sourceSet.clearJavaSrcDirs() + if (kotlinCompilation is KotlinWithJavaCompilation) { + kotlinCompilation.javaSourceSet.clearJavaSrcDirs() + } // outputFile can be set later during the configuration phase, get it only after the phase: project.afterEvaluate { project -> - val subpluginEnvironment: SubpluginEnvironment = loadSubplugins(project, kotlinPluginVersion) - val appliedPlugins = subpluginEnvironment.addSubpluginOptions( - project, kotlinTask, kotlinTask, null, null, sourceSet) - kotlinTask.kotlinOptions.outputFile = kotlinTask.outputFile.absolutePath val outputDir = kotlinTask.outputFile.parentFile + val subpluginEnvironment: SubpluginEnvironment = loadSubplugins(project, kotlinPluginVersion) + val appliedPlugins = subpluginEnvironment.addSubpluginOptions( + project, kotlinTask, null, null, null, kotlinCompilation) + if (outputDir.isParentOf(project.rootDir)) throw InvalidUserDataException( "The output directory '$outputDir' (defined by outputFile of $kotlinTask) contains or " + @@ -274,17 +284,17 @@ internal class Kotlin2JsSourceSetProcessor( kotlinTask.destinationDir = outputDir if (!isSeparateClassesDirSupported) { - sourceSet.output.setClassesDirCompatible(kotlinTask.destinationDir) + kotlinCompilation.output.setClassesDirCompatible(kotlinTask.destinationDir) } appliedPlugins .flatMap { it.getSubpluginKotlinTasks(project, kotlinTask) } - .forEach { it.source(kotlinSourceSet.kotlin) } + .forEach { task -> kotlinCompilation.kotlinSourceSets.forEach { sourceSet -> task.source(sourceSet.kotlin) } } } } private fun createCleanSourceMapTask() { - val taskName = sourceSet.getTaskName("clean", "sourceMap") + val taskName = kotlinCompilation.composeName("clean", "sourceMap") val task = project.tasks.create(taskName, Delete::class.java) task.onlyIf { kotlinTask.kotlinOptions.sourceMap } task.delete(object : Closure(this) { @@ -295,189 +305,274 @@ internal class Kotlin2JsSourceSetProcessor( } internal class KotlinCommonSourceSetProcessor( - project: Project, - javaBasePlugin: JavaBasePlugin, - sourceSet: SourceSet, - tasksProvider: KotlinTasksProvider, - kotlinSourceSetProvider: KotlinSourceSetProvider, - private val kotlinPluginVersion: String + project: Project, + compilation: KotlinCompilation, + tasksProvider: KotlinTasksProvider, + private val kotlinPluginVersion: String ) : KotlinSourceSetProcessor( - project, javaBasePlugin, sourceSet, tasksProvider, kotlinSourceSetProvider, - dslExtensionName = KOTLIN_DSL_NAME, - taskDescription = "Compiles the kotlin sources in $sourceSet to Metadata.", - compileTaskNameSuffix = "kotlinCommon" + project, tasksProvider, taskDescription = "Compiles the kotlin sources in $compilation to Metadata.", + kotlinCompilation = compilation ) { override fun doTargetSpecificProcessing() { - sourceSet.clearJavaSrcDirs() + project.tasks.findByName(kotlinCompilation.compileAllTaskName)!!.dependsOn(kotlinTask) + // can be missing (e.g. in case of tests) + if (kotlinCompilation.compilationName == KotlinCompilation.MAIN_COMPILATION_NAME) { + project.tasks.findByName(kotlinCompilation.target.artifactsTaskName)?.dependsOn(kotlinTask) + } project.afterEvaluate { project -> - kotlinTask.source(kotlinSourceSet.kotlin) - val subpluginEnvironment: SubpluginEnvironment = loadSubplugins(project, kotlinPluginVersion) val appliedPlugins = subpluginEnvironment.addSubpluginOptions( - project, kotlinTask, kotlinTask, null, null, sourceSet) - - project.tasks.findByName(sourceSet.classesTaskName)!!.dependsOn(kotlinTask) - // can be missing (e.g. in case of tests) - project.tasks.findByName(sourceSet.jarTaskName)?.dependsOn(kotlinTask) - + project, kotlinTask, null, null, null, kotlinCompilation + ) appliedPlugins - .flatMap { it.getSubpluginKotlinTasks(project, kotlinTask) } - .forEach { it.source(kotlinSourceSet.kotlin) } + .flatMap { it.getSubpluginKotlinTasks(project, kotlinTask) } + .forEach { kotlinCompilation.kotlinSourceSets.forEach { sourceSet -> it.source(sourceSet.kotlin) } } } } override fun doCreateTask(project: Project, taskName: String): KotlinCompileCommon = - tasksProvider.createKotlinCommonTask(project, taskName, sourceSet.name) + tasksProvider.createKotlinCommonTask(project, taskName, kotlinCompilation.compilationName) } - internal abstract class AbstractKotlinPlugin( - val tasksProvider: KotlinTasksProvider, - val kotlinSourceSetProvider: KotlinSourceSetProvider, - protected val kotlinPluginVersion: String, + val tasksProvider: KotlinTasksProvider, + protected val kotlinPluginVersion: String, val registry: ToolingModelBuilderRegistry ) : Plugin { - internal abstract fun buildSourceSetProcessor(project: Project, javaBasePlugin: JavaBasePlugin, sourceSet: SourceSet, kotlinPluginVersion: String): KotlinSourceSetProcessor<*> + + internal abstract fun buildSourceSetProcessor(project: Project, compilation: KotlinCompilation, kotlinPluginVersion: String): KotlinSourceSetProcessor<*> override fun apply(project: Project) { - val javaBasePlugin = project.plugins.apply(JavaBasePlugin::class.java) - val javaPluginConvention = project.convention.getPlugin(JavaPluginConvention::class.java) - project.plugins.apply(JavaPlugin::class.java) - configureSourceSetDefaults(project, javaBasePlugin, javaPluginConvention) - configureDefaultVersionsResolutionStrategy(project) - configureClassInspectionForIC(project) + configureTarget( + (project.kotlinExtension as KotlinSingleJavaTargetExtension).target, + { compilation -> buildSourceSetProcessor(project, compilation, kotlinPluginVersion) } + ) + + configureProjectGlobalSettings(project, kotlinPluginVersion) registry.register(KotlinModelBuilder(kotlinPluginVersion)) } - open protected fun configureSourceSetDefaults( - project: Project, - javaBasePlugin: JavaBasePlugin, - javaPluginConvention: JavaPluginConvention - ) { - javaPluginConvention.sourceSets?.all { sourceSet -> - buildSourceSetProcessor(project, javaBasePlugin, sourceSet, kotlinPluginVersion).run() - } + companion object { + fun configureProjectGlobalSettings(project: Project, kotlinPluginVersion: String) { + configureDefaultVersionsResolutionStrategy(project, kotlinPluginVersion) + configureClassInspectionForIC(project) } - private fun configureDefaultVersionsResolutionStrategy(project: Project) { - project.configurations.all { configuration -> - if (isGradleVersionAtLeast(4, 4)) { - // Use the API introduced in Gradle 4.4 to modify the dependencies directly before they are resolved: - configuration.withDependencies { dependencySet -> - dependencySet.filterIsInstance() - .filter { it.group == "org.jetbrains.kotlin" && it.version.isNullOrEmpty() } - .forEach { it.version { constraint -> constraint.prefer(kotlinPluginVersion) } } - } + fun configureTarget( + target: KotlinWithJavaTarget, + buildSourceSetProcessor: (KotlinCompilation) -> KotlinSourceSetProcessor<*> + ) { + setUpJavaSourceSets(target) + configureSourceSetDefaults(target, buildSourceSetProcessor) + } + + private fun configureClassInspectionForIC(project: Project) { + val classesTask = project.tasks.findByName(JavaPlugin.CLASSES_TASK_NAME) + val jarTask = project.tasks.findByName(JavaPlugin.JAR_TASK_NAME) + + if (classesTask == null || jarTask !is Jar) { + project.logger.info( + "Could not configure class inspection task " + + "(classes task = ${classesTask?.javaClass?.canonicalName}, " + + "jar task = ${classesTask?.javaClass?.canonicalName}" + ) + return } - else { - configuration.resolutionStrategy.eachDependency { details -> - val requested = details.requested - if (requested.group == "org.jetbrains.kotlin" && requested.version.isEmpty()) { - details.useVersion(kotlinPluginVersion) - } - } + val inspectTask = project.tasks.create("inspectClassesForKotlinIC", InspectClassesForMultiModuleIC::class.java) + inspectTask.sourceSetName = SourceSet.MAIN_SOURCE_SET_NAME + inspectTask.jarTask = jarTask + inspectTask.dependsOn(classesTask) + jarTask.dependsOn(inspectTask) + } + + private fun setUpJavaSourceSets( + kotlinTarget: KotlinWithJavaTarget + ) { + val project = kotlinTarget.project + val javaSourceSets = project.convention.getPlugin(JavaPluginConvention::class.java).sourceSets + + val kotlinSourceSetDslName = when (kotlinTarget.platformType) { + KotlinPlatformType.js -> KOTLIN_JS_DSL_NAME + else -> KOTLIN_DSL_NAME + } + + // Workaround for indirect mutual recursion between the two `all { ... }` handlers: + val compilationsUnderConstruction = mutableMapOf() + + javaSourceSets.all { javaSourceSet -> + val kotlinCompilation = compilationsUnderConstruction[javaSourceSet.name] ?: kotlinTarget.compilations.maybeCreate(javaSourceSet.name) + kotlinCompilation.javaSourceSet = javaSourceSet + val kotlinSourceSet = project.kotlinExtension.sourceSets.maybeCreate(kotlinCompilation.name) + javaSourceSet.addConvention(kotlinSourceSetDslName, kotlinSourceSet) + kotlinSourceSet.kotlin.source(javaSourceSet.java) + kotlinCompilation.source(kotlinSourceSet) + } + + kotlinTarget.compilations.all { kotlinCompilation -> + val sourceSetName = kotlinCompilation.name + compilationsUnderConstruction[sourceSetName] = kotlinCompilation + kotlinCompilation.javaSourceSet = javaSourceSets.maybeCreate(sourceSetName) + + // Another Kotlin source set following the other convention, named according to the compilation, not the Java source set: + val kotlinSourceSet = project.kotlinExtension.sourceSets.maybeCreate(kotlinCompilation.fullName) + kotlinCompilation.source(kotlinSourceSet) + } + } + + fun configureSourceSetDefaults( + kotlinTarget: KotlinTarget, + buildSourceSetProcessor: (KotlinCompilation) -> KotlinSourceSetProcessor<*> + ) { + kotlinTarget.compilations.all { compilation -> + buildSourceSetProcessor(compilation).run() } } } +} - private fun configureClassInspectionForIC(project: Project) { - val classesTask = project.tasks.findByName(JavaPlugin.CLASSES_TASK_NAME) - val jarTask = project.tasks.findByName(JavaPlugin.JAR_TASK_NAME) - - if (classesTask == null || jarTask !is Jar) { - project.logger.info( - "Could not configure class inspection task " + - "(classes task = ${classesTask?.javaClass?.canonicalName}, " + - "jar task = ${classesTask?.javaClass?.canonicalName}" - ) - return +internal fun configureDefaultVersionsResolutionStrategy(project: Project, kotlinPluginVersion: String) { + project.configurations.all { configuration -> + if (isGradleVersionAtLeast(4, 4)) { + // Use the API introduced in Gradle 4.4 to modify the dependencies directly before they are resolved: + configuration.withDependencies { dependencySet -> + dependencySet.filterIsInstance() + .filter { it.group == "org.jetbrains.kotlin" && it.version.isNullOrEmpty() } + .forEach { it.version { constraint -> constraint.prefer(kotlinPluginVersion) } } + } + } else { + configuration.resolutionStrategy.eachDependency { details -> + val requested = details.requested + if (requested.group == "org.jetbrains.kotlin" && requested.version.isEmpty()) { + details.useVersion(kotlinPluginVersion) + } + } } - val inspectTask = project.tasks.create("inspectClassesForKotlinIC", InspectClassesForMultiModuleIC::class.java) - inspectTask.sourceSetName = SourceSet.MAIN_SOURCE_SET_NAME - inspectTask.jarTask = jarTask - inspectTask.dependsOn(classesTask) - jarTask.dependsOn(inspectTask) } } internal open class KotlinPlugin( - tasksProvider: KotlinTasksProvider, - kotlinSourceSetProvider: KotlinSourceSetProvider, - kotlinPluginVersion: String, + tasksProvider: KotlinTasksProvider, + kotlinPluginVersion: String, registry: ToolingModelBuilderRegistry -) : AbstractKotlinPlugin(tasksProvider, kotlinSourceSetProvider, kotlinPluginVersion, registry) { - override fun buildSourceSetProcessor(project: Project, javaBasePlugin: JavaBasePlugin, sourceSet: SourceSet, kotlinPluginVersion: String) = - Kotlin2JvmSourceSetProcessor(project, javaBasePlugin, sourceSet, tasksProvider, kotlinSourceSetProvider, kotlinPluginVersion) +) : AbstractKotlinPlugin(tasksProvider, kotlinPluginVersion, registry) { + + override fun buildSourceSetProcessor(project: Project, compilation: KotlinCompilation, kotlinPluginVersion: String) = + Kotlin2JvmSourceSetProcessor(project, tasksProvider, compilation, kotlinPluginVersion) override fun apply(project: Project) { + val target = KotlinWithJavaTarget(project, KotlinPlatformType.jvm, "").apply { + disambiguationClassifier = null // don't add anything to the task names + } + (project.kotlinExtension as KotlinSingleJavaTargetExtension).target = target + project.pluginManager.apply(ScriptingGradleSubplugin::class.java) super.apply(project) } } internal open class KotlinCommonPlugin( - tasksProvider: KotlinTasksProvider, - kotlinSourceSetProvider: KotlinSourceSetProvider, - kotlinPluginVersion: String, + tasksProvider: KotlinTasksProvider, + kotlinPluginVersion: String, registry: ToolingModelBuilderRegistry -) : AbstractKotlinPlugin(tasksProvider, kotlinSourceSetProvider, kotlinPluginVersion, registry) { - override fun buildSourceSetProcessor(project: Project, javaBasePlugin: JavaBasePlugin, sourceSet: SourceSet, kotlinPluginVersion: String) = - KotlinCommonSourceSetProcessor(project, javaBasePlugin, sourceSet, tasksProvider, kotlinSourceSetProvider, kotlinPluginVersion) -} +) : AbstractKotlinPlugin(tasksProvider, kotlinPluginVersion, registry) { -internal open class Kotlin2JsPlugin( - tasksProvider: KotlinTasksProvider, - kotlinSourceSetProvider: KotlinSourceSetProvider, - kotlinPluginVersion: String, - registry: ToolingModelBuilderRegistry -) : AbstractKotlinPlugin(tasksProvider, kotlinSourceSetProvider, kotlinPluginVersion, registry) { - override fun buildSourceSetProcessor(project: Project, javaBasePlugin: JavaBasePlugin, sourceSet: SourceSet, kotlinPluginVersion: String) = - Kotlin2JsSourceSetProcessor(project, javaBasePlugin, sourceSet, tasksProvider, kotlinSourceSetProvider, kotlinPluginVersion) -} - -internal open class KotlinAndroidPlugin( - val tasksProvider: KotlinTasksProvider, - private val kotlinSourceSetProvider: KotlinSourceSetProvider, - private val kotlinPluginVersion: String -) : Plugin { + override fun buildSourceSetProcessor( + project: Project, + compilation: KotlinCompilation, + kotlinPluginVersion: String + ): KotlinSourceSetProcessor<*> = + KotlinCommonSourceSetProcessor(project, compilation, tasksProvider, kotlinPluginVersion) override fun apply(project: Project) { - val version = loadAndroidPluginVersion() - if (version != null) { - val minimalVersion = "1.1.0" - if (compareVersionNumbers(version, minimalVersion) < 0) { - throw IllegalStateException("Kotlin: Unsupported version of com.android.tools.build:gradle plugin: version $minimalVersion or higher should be used with kotlin-android plugin") - } - } + val target = KotlinWithJavaTarget(project, KotlinPlatformType.common, "common") + (project.kotlinExtension as KotlinSingleJavaTargetExtension).target = target - val kotlinTools = KotlinConfigurationTools( - kotlinSourceSetProvider, - tasksProvider, - kotlinPluginVersion) - - val legacyVersionThreshold = "2.5.0" - - val variantProcessor = if (compareVersionNumbers(version, legacyVersionThreshold) < 0) { - LegacyAndroidAndroidProjectHandler(kotlinTools) - } - else { - val android25ProjectHandlerClass = Class.forName("org.jetbrains.kotlin.gradle.plugin.Android25ProjectHandler") - val ctor = android25ProjectHandlerClass.constructors.single { - it.parameterTypes.contentEquals(arrayOf(kotlinTools.javaClass)) - } - ctor.newInstance(kotlinTools) as AbstractAndroidProjectHandler<*> - } - - variantProcessor.handleProject(project) + super.apply(project) } } -class KotlinConfigurationTools internal constructor(val kotlinSourceSetProvider: KotlinSourceSetProvider, - val kotlinTasksProvider: KotlinTasksProvider, - val kotlinPluginVersion: String) +internal open class Kotlin2JsPlugin( + tasksProvider: KotlinTasksProvider, + kotlinPluginVersion: String, + registry: ToolingModelBuilderRegistry +) : AbstractKotlinPlugin(tasksProvider, kotlinPluginVersion, registry) { + + override fun buildSourceSetProcessor( + project: Project, + compilation: KotlinCompilation, + kotlinPluginVersion: String + ): KotlinSourceSetProcessor<*> = + Kotlin2JsSourceSetProcessor( + project, tasksProvider, compilation, kotlinPluginVersion + ) + + override fun apply(project: Project) { + val target = KotlinWithJavaTarget(project, KotlinPlatformType.js, "2Js") + + (project.kotlinExtension as KotlinSingleJavaTargetExtension).target = target + super.apply(project) + } +} + +internal open class KotlinAndroidPlugin( + val tasksProvider: KotlinTasksProvider, + private val kotlinPluginVersion: String +) : Plugin { + + override fun apply(project: Project) { + val androidTarget = KotlinAndroidTarget("", project) + + applyToTarget( + project, androidTarget, tasksProvider, + kotlinPluginVersion + ) + } + + companion object { + fun applyToTarget( + project: Project, + kotlinTarget: KotlinAndroidTarget, + tasksProvider: KotlinTasksProvider, + kotlinPluginVersion: String + ) { + + val version = loadAndroidPluginVersion() + if (version != null) { + val minimalVersion = "1.1.0" + if (compareVersionNumbers(version, minimalVersion) < 0) { + throw IllegalStateException("Kotlin: Unsupported version of com.android.tools.build:gradle plugin: version $minimalVersion or higher should be used with kotlin-android plugin") + } + } + + val kotlinTools = KotlinConfigurationTools( + tasksProvider, + kotlinPluginVersion + ) + + val legacyVersionThreshold = "2.5.0" + + val variantProcessor = if (compareVersionNumbers(version, legacyVersionThreshold) < 0) { + LegacyAndroidAndroidProjectHandler(kotlinTools) + } else { + val android25ProjectHandlerClass = Class.forName("org.jetbrains.kotlin.gradle.plugin.Android25ProjectHandler") + val ctor = android25ProjectHandlerClass.constructors.single { + it.parameterTypes.contentEquals(arrayOf(kotlinTools.javaClass)) + } + ctor.newInstance(kotlinTools) as AbstractAndroidProjectHandler<*> + } + + variantProcessor.handleProject(project, kotlinTarget) + } + } +} + +class KotlinConfigurationTools internal constructor( + val kotlinTasksProvider: KotlinTasksProvider, + val kotlinPluginVersion: String +) /** Part of Android configuration, that works only with the old public API. * @see [LegacyAndroidAndroidProjectHandler] that is implemented with the old internal API and [AndroidGradle25VariantProcessor] that works @@ -497,18 +592,22 @@ abstract class AbstractAndroidProjectHandler(private val kotlinConfigurationT protected open fun checkVariantIsValid(variant: V) = Unit - protected abstract fun wireKotlinTasks(project: Project, - androidPlugin: BasePlugin, - androidExt: BaseExtension, - variantData: V, - javaTask: AbstractCompile, - kotlinTask: KotlinCompile) + protected open fun setUpDependencyResolution(variant: V, compilation: KotlinJvmAndroidCompilation) = Unit + + protected abstract fun wireKotlinTasks( + project: Project, + compilation: KotlinJvmAndroidCompilation, + androidPlugin: BasePlugin, + androidExt: BaseExtension, + variantData: V, + javaTask: AbstractCompile, + kotlinTask: KotlinCompile + ) protected abstract fun wrapVariantDataForKapt(variantData: V): KaptVariantData - fun handleProject(project: Project) { + fun handleProject(project: Project, kotlinAndroidTarget: KotlinAndroidTarget) { val ext = project.extensions.getByName("android") as BaseExtension - val aptConfigurations = hashMapOf() ext.sourceSets.all { sourceSet -> logger.kotlinDebug("Creating KotlinBaseSourceSet for source set $sourceSet") @@ -527,42 +626,49 @@ abstract class AbstractAndroidProjectHandler(private val kotlinConfigurationT ext.addExtension(KOTLIN_OPTIONS_DSL_NAME, kotlinOptions) project.afterEvaluate { project -> - if (project != null) { - val androidPluginIds = listOf("android", "com.android.application", "android-library", "com.android.library", - "com.android.test", "com.android.feature", "com.android.dynamic-feature", "com.android.instantapp") - 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" }) + val androidPluginIds = listOf("android", "com.android.application", "android-library", "com.android.library", + "com.android.test", "com.android.feature", "com.android.dynamic-feature", "com.android.instantapp") + 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" }) - val subpluginEnvironment = loadSubplugins(project, kotlinConfigurationTools.kotlinPluginVersion) + val subpluginEnvironment = loadSubplugins(project, kotlinConfigurationTools.kotlinPluginVersion) - checkAndroidAnnotationProcessorDependencyUsage(project) + checkAndroidAnnotationProcessorDependencyUsage(project) - forEachVariant(project) { - processVariant(it, project, ext, plugin, aptConfigurations, kotlinOptions, - kotlinConfigurationTools.kotlinTasksProvider, subpluginEnvironment) - } + forEachVariant(project) { + processVariant( + it, kotlinAndroidTarget, project, ext, plugin, kotlinOptions, kotlinConfigurationTools.kotlinTasksProvider, + subpluginEnvironment + ) } } } - private fun processVariant(variantData: V, - project: Project, - androidExt: BaseExtension, - androidPlugin: BasePlugin, - aptConfigurations: Map, - rootKotlinOptions: KotlinJvmOptionsImpl, - tasksProvider: KotlinTasksProvider, - subpluginEnvironment: SubpluginEnvironment) { + private fun processVariant( + variantData: V, + target: KotlinAndroidTarget, + project: Project, + androidExt: BaseExtension, + androidPlugin: BasePlugin, + rootKotlinOptions: KotlinJvmOptionsImpl, + tasksProvider: KotlinTasksProvider, + subpluginEnvironment: SubpluginEnvironment + ) { checkVariantIsValid(variantData) - val variantDataName = getVariantName(variantData) logger.kotlinDebug("Process variant [$variantDataName]") + val compilation = target.compilations.create(variantDataName).apply { + KotlinTargetConfigurator.defineConfigurationsForCompilation(this, target, project.configurations) + } + + setUpDependencyResolution(variantData, compilation) + val javaTask = getJavaTask(variantData) if (javaTask == null) { @@ -570,7 +676,7 @@ abstract class AbstractAndroidProjectHandler(private val kotlinConfigurationT return } - val kotlinTaskName = "compile${variantDataName.capitalize()}Kotlin" + val kotlinTaskName = compilation.compileKotlinTaskName // todo: Investigate possibility of creating and configuring kotlinTask before evaluation val kotlinTask = tasksProvider.createKotlinJVMTask(project, kotlinTaskName, variantDataName) kotlinTask.parentKotlinOptionsImpl = rootKotlinOptions @@ -579,22 +685,35 @@ abstract class AbstractAndroidProjectHandler(private val kotlinConfigurationT kotlinTask.destinationDir = File(project.buildDir, "tmp/kotlin-classes/$variantDataName") kotlinTask.description = "Compiles the $variantDataName kotlin." - configureSources(kotlinTask, variantData) - wireKotlinTasks(project, androidPlugin, androidExt, variantData, javaTask, kotlinTask) + configureSources(kotlinTask, variantData, compilation) + + // In MPPs, add the common main Kotlin sources to non-test variants, the common test sources to test variants + val commonSourceSetName = if (getTestedVariantData(variantData) == null) + KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME else + KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME + project.kotlinExtension.sourceSets.findByName(commonSourceSetName)?.let { + compilation.source(it) + } + + wireKotlinTasks(project, compilation, androidPlugin, androidExt, variantData, javaTask, kotlinTask) val appliedPlugins = subpluginEnvironment.addSubpluginOptions( project, kotlinTask, javaTask, wrapVariantDataForKapt(variantData), this, null) appliedPlugins.flatMap { it.getSubpluginKotlinTasks(project, kotlinTask) } - .forEach { configureSources(it, variantData) } + .forEach { configureSources(it, variantData, null) } } - private fun configureSources(compileTask: AbstractCompile, variantData: V) { + private fun configureSources(compileTask: AbstractCompile, variantData: V, compilation: KotlinCompilation?) { val logger = compileTask.project.logger for (provider in getSourceProviders(variantData)) { val kotlinSourceSet = provider.getConvention(KOTLIN_DSL_NAME) as? KotlinSourceSet ?: continue - compileTask.source(kotlinSourceSet.kotlin) + if (compilation != null) { + compilation.source(kotlinSourceSet) + } else { + compileTask.source(kotlinSourceSet.kotlin) + } } for (javaSrcDir in getAllJavaSources(variantData)) { @@ -696,10 +815,10 @@ internal class SubpluginEnvironment( fun addSubpluginOptions( project: Project, kotlinTask: AbstractKotlinCompile, - javaTask: AbstractCompile, + javaTask: AbstractCompile?, variantData: Any?, androidProjectHandler: AbstractAndroidProjectHandler?, - javaSourceSet: SourceSet? + kotlinCompilation: KotlinCompilation? ): List>> { val pluginOptions = kotlinTask.pluginOptions @@ -716,7 +835,7 @@ internal class SubpluginEnvironment( project.logger.kotlinDebug { "Adding '$mavenCoordinate' to '$PLUGIN_CLASSPATH_CONFIGURATION_NAME' configuration" } project.dependencies.add(PLUGIN_CLASSPATH_CONFIGURATION_NAME, mavenCoordinate) - val subpluginOptions = subplugin.apply(project, kotlinTask, javaTask, variantData, androidProjectHandler, javaSourceSet) + val subpluginOptions = subplugin.apply(project, kotlinTask, javaTask, variantData, androidProjectHandler, kotlinCompilation) val subpluginId = subplugin.getCompilerPluginId() kotlinTask.registerSubpluginOptionsAsInputs(subpluginId, subpluginOptions) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt index e59c891838c..4b7379dddc0 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt @@ -21,11 +21,14 @@ import org.gradle.api.Project import org.gradle.api.internal.file.FileResolver import org.gradle.api.logging.Logger import org.gradle.api.logging.Logging +import org.gradle.internal.cleanup.BuildOutputCleanupRegistry +import org.gradle.internal.reflect.Instantiator import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry -import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension -import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension -import org.jetbrains.kotlin.gradle.dsl.createKotlinExtension -import org.jetbrains.kotlin.gradle.internal.KotlinSourceSetProviderImpl +import org.jetbrains.kotlin.gradle.dsl.* +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin +import org.jetbrains.kotlin.gradle.plugin.source.KotlinSourceSet +import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSetFactory +import org.jetbrains.kotlin.gradle.plugin.sources.KotlinSourceSetFactory import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import java.io.FileNotFoundException @@ -33,7 +36,9 @@ import java.util.* import javax.inject.Inject import kotlin.reflect.KClass -abstract class KotlinBasePluginWrapper(protected val fileResolver: FileResolver): Plugin { +abstract class KotlinBasePluginWrapper( + protected val fileResolver: FileResolver +): Plugin { private val log = Logging.getLogger(this.javaClass) val kotlinPluginVersion = loadKotlinVersionFromResource(log) @@ -66,32 +71,54 @@ abstract class KotlinBasePluginWrapper(protected val fileResolver: FileResolver) plugin.apply(project) } - internal abstract fun getPlugin(kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin - - open val projectExtensionClass: KClass get() = KotlinProjectExtension::class + internal abstract fun getPlugin( + project: Project, + kotlinGradleBuildServices: KotlinGradleBuildServices + ): Plugin } -open class KotlinPluginWrapper @Inject internal constructor(fileResolver: FileResolver, protected val registry: ToolingModelBuilderRegistry): KotlinBasePluginWrapper(fileResolver) { - override fun getPlugin(kotlinGradleBuildServices: KotlinGradleBuildServices) = - KotlinPlugin(KotlinTasksProvider(), KotlinSourceSetProviderImpl(fileResolver), kotlinPluginVersion, registry) +open class KotlinPluginWrapper @Inject constructor( + fileResolver: FileResolver, + protected val registry: ToolingModelBuilderRegistry +): KotlinBasePluginWrapper(fileResolver) { + override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin = + KotlinPlugin(KotlinTasksProvider(), kotlinPluginVersion, registry) override val projectExtensionClass: KClass get() = KotlinJvmProjectExtension::class } -open class KotlinCommonPluginWrapper @Inject internal constructor(fileResolver: FileResolver, protected val registry: ToolingModelBuilderRegistry): KotlinBasePluginWrapper(fileResolver) { - override fun getPlugin(kotlinGradleBuildServices: KotlinGradleBuildServices) = - KotlinCommonPlugin(KotlinCommonTasksProvider(), KotlinSourceSetProviderImpl(fileResolver), kotlinPluginVersion, registry) +open class KotlinCommonPluginWrapper @Inject constructor( + fileResolver: FileResolver, + protected val registry: ToolingModelBuilderRegistry +): KotlinBasePluginWrapper(fileResolver) { + override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin = + KotlinCommonPlugin(KotlinCommonTasksProvider(), kotlinPluginVersion, registry) + + override val projectExtensionClass: KClass + get() = KotlinSingleJavaTargetExtension::class } -open class KotlinAndroidPluginWrapper @Inject internal constructor(fileResolver: FileResolver, protected val registry: ToolingModelBuilderRegistry): KotlinBasePluginWrapper(fileResolver) { - override fun getPlugin(kotlinGradleBuildServices: KotlinGradleBuildServices) = - KotlinAndroidPlugin(AndroidTasksProvider(), KotlinSourceSetProviderImpl(fileResolver), kotlinPluginVersion) +open class KotlinAndroidPluginWrapper @Inject constructor( + fileResolver: FileResolver, + protected val registry: ToolingModelBuilderRegistry +): KotlinBasePluginWrapper(fileResolver) { + override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin = + KotlinAndroidPlugin( + AndroidTasksProvider(), + kotlinPluginVersion + ) } -open class Kotlin2JsPluginWrapper @Inject internal constructor(fileResolver: FileResolver, protected val registry: ToolingModelBuilderRegistry): KotlinBasePluginWrapper(fileResolver) { - override fun getPlugin(kotlinGradleBuildServices: KotlinGradleBuildServices) = - Kotlin2JsPlugin(Kotlin2JsTasksProvider(), KotlinSourceSetProviderImpl(fileResolver), kotlinPluginVersion, registry) +open class Kotlin2JsPluginWrapper @Inject constructor( + fileResolver: FileResolver, + protected val registry: ToolingModelBuilderRegistry +): KotlinBasePluginWrapper(fileResolver) { + override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin = + Kotlin2JsPlugin(Kotlin2JsTasksProvider(), kotlinPluginVersion, registry) + + override val projectExtensionClass: KClass + get() = KotlinSingleJavaTargetExtension::class } fun Project.getKotlinPluginVersion(): String? = diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/LegacyAndroidAndroidProjectHandler.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/LegacyAndroidAndroidProjectHandler.kt index 418b295056c..f1d8572be5a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/LegacyAndroidAndroidProjectHandler.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/LegacyAndroidAndroidProjectHandler.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.gradle.internal.KaptTask import org.jetbrains.kotlin.gradle.internal.KaptVariantData import org.jetbrains.kotlin.gradle.internal.registerGeneratedJavaSource 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.utils.checkedReflection import java.io.File @@ -40,12 +41,14 @@ internal class LegacyAndroidAndroidProjectHandler(kotlinConfigurationTools: Kotl variantManager.variantDataList.forEach(action) } - override fun wireKotlinTasks(project: Project, - androidPlugin: BasePlugin, - androidExt: BaseExtension, - variantData: BaseVariantData, - javaTask: AbstractCompile, - kotlinTask: KotlinCompile + override fun wireKotlinTasks( + project: Project, + compilation: KotlinJvmAndroidCompilation, + androidPlugin: BasePlugin, + androidExt: BaseExtension, + variantData: BaseVariantData, + javaTask: AbstractCompile, + kotlinTask: KotlinCompile ) { kotlinTask.dependsOn(*javaTask.dependsOn.toTypedArray()) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/HierarchyAttributeContainer.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/HierarchyAttributeContainer.kt new file mode 100644 index 00000000000..2eda20c3d72 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/HierarchyAttributeContainer.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +/* + * Copyright 2010-2018 JetBrains s.r.o. 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 org.gradle.api.attributes.Attribute +import org.gradle.api.attributes.AttributeContainer +import java.util.* + +// TODO better implementation: attribute invariants (no attrs with same name and different types allowed), thread safety? +class HierarchyAttributeContainer(val parent: AttributeContainer?) : AttributeContainer { + private val attributesMap = Collections.synchronizedMap(mutableMapOf, Any>()) + + override fun contains(key: Attribute<*>): Boolean = + attributesMap.contains(key) || parent?.contains(key) ?: false + + @Suppress("UNCHECKED_CAST") + override fun getAttribute(key: Attribute?): T? = + attributesMap.get(key as Attribute<*>) as T? ?: parent?.getAttribute(key) + + override fun isEmpty(): Boolean = attributesMap.isEmpty() && parent?.isEmpty ?: false + + override fun keySet(): Set> = attributesMap.keys + parent?.keySet().orEmpty() + + override fun attribute(key: Attribute?, value: T): AttributeContainer { + val checkedValue = requireNotNull(value as Any?) { "null values for attributes are not supported" } + attributesMap[key as Attribute<*>] = checkedValue + return this + } + + override fun getAttributes(): AttributeContainer = this +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinCompilationFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinCompilationFactory.kt new file mode 100644 index 00000000000..4b6f8f69351 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinCompilationFactory.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +/* + * Copyright 2010-2018 JetBrains s.r.o. 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 org.gradle.api.NamedDomainObjectFactory +import org.gradle.api.Project +import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.KotlinTarget + +interface KotlinCompilationFactory : NamedDomainObjectFactory { + val itemClass: Class +} + +private fun KotlinTarget.createCompilationOutput(name: String) = + KotlinCompilationOutput(project, project.buildDir.resolve("processedResources/$name")) + +class KotlinCommonCompilationFactory( + val target: KotlinOnlyTarget +) : KotlinCompilationFactory { + override val itemClass: Class + get() = KotlinCommonCompilation::class.java + + override fun create(name: String): KotlinCommonCompilation = + KotlinCommonCompilation(target, name, target.createCompilationOutput(name)) +} + +class KotlinJvmCompilationFactory( + val target: KotlinOnlyTarget +) : KotlinCompilationFactory { + override val itemClass: Class + get() = KotlinJvmCompilation::class.java + + override fun create(name: String): KotlinJvmCompilation = + KotlinJvmCompilation(target, name, target.createCompilationOutput(name)) +} + +class KotlinWithJavaCompilationFactory( + val project: Project, + val target: KotlinWithJavaTarget +) : KotlinCompilationFactory { + + override val itemClass: Class + get() = KotlinWithJavaCompilation::class.java + + override fun create(name: String): KotlinWithJavaCompilation { + val result = KotlinWithJavaCompilation(target, name) + return result + } +} + +class KotlinJvmAndroidCompilationFactory( + val project: Project, + val target: KotlinAndroidTarget +) : KotlinCompilationFactory { + + override val itemClass: Class + get() = KotlinJvmAndroidCompilation::class.java + + override fun create(name: String): KotlinJvmAndroidCompilation = + KotlinJvmAndroidCompilation(target, name, target.createCompilationOutput(name)) +} + +class KotlinJsCompilationFactory( + val project: Project, + val target: KotlinOnlyTarget +) : KotlinCompilationFactory { + override val itemClass: Class + get() = KotlinJsCompilation::class.java + + override fun create(name: String): KotlinJsCompilation = + KotlinJsCompilation(target, name, target.createCompilationOutput(name)) +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinCompilationOutput.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinCompilationOutput.kt new file mode 100644 index 00000000000..76df3e6afe4 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinCompilationOutput.kt @@ -0,0 +1,77 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +/* + * Copyright 2010-2018 JetBrains s.r.o. 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 org.gradle.api.Project +import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.FileCollection +import org.gradle.api.internal.file.FileCollectionInternal +import org.gradle.api.internal.file.FileCollectionVisitor +import org.gradle.api.internal.file.FileSystemSubset +import org.gradle.api.tasks.SourceSetOutput +import java.io.File +import java.util.concurrent.Callable + +class KotlinCompilationOutput constructor( + private val project: Project, + private var resourcesDir: Any, + private var backingFileCollection: ConfigurableFileCollection = project.files() // must be a parameter since it is used in delegation +) : SourceSetOutput, ConfigurableFileCollection by backingFileCollection, FileCollectionInternal { + + /* TODO report Gradle bug: cannot implement SourceSetOutput without also implementing FileCollectionInternal, there's a cast to the latter + inside the Gradle logic for resolving file collections */ + override fun registerWatchPoints(p0: FileSystemSubset.Builder) = (backingFileCollection as FileCollectionInternal).registerWatchPoints(p0) + override fun visitRootElements(p0: FileCollectionVisitor) = (backingFileCollection as FileCollectionInternal).visitRootElements(p0) + + private val classesDirs: FileCollection = project.files() + private val otherDirs: ConfigurableFileCollection = project.files() + + init { + this.from(classesDirs) + this.from(Callable { resourcesDir }) + } + + override fun setResourcesDir(dirNotation: Any) { + resourcesDir = dirNotation + } + + override fun setResourcesDir(dir: File): Unit = setResourcesDir(dir as Any) + + override fun getDirs(): FileCollection = otherDirs + + override fun isLegacyLayout(): Boolean = false + + override fun getResourcesDir(): File = project.file(resourcesDir) + + @Suppress("OverridingDeprecatedMember") + override fun setClassesDir(file: File?) = @Suppress("deprecation") setClassesDir(file as Any) + + @Suppress("OverridingDeprecatedMember") + override fun setClassesDir(fileNotation: Any?) = throw UnsupportedOperationException("Setting classesDir is not supported, use classesDirs.") + + @Suppress("OverridingDeprecatedMember") + override fun getClassesDir(): File = classesDirs.singleFile + + override fun getClassesDirs(): FileCollection = classesDirs + + override fun dir(args: Map, dir: Any?) { + val dirFileCollection = project.files(dir) + args["builtBy"]?.let { dirFileCollection.builtBy(it) } + otherDirs.from(dirFileCollection) + } + + override fun dir(dirNotation: Any?): Unit = dir(emptyMap(), dirNotation) +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt new file mode 100644 index 00000000000..5cc29a43532 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt @@ -0,0 +1,228 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +/* + * Copyright 2010-2018 JetBrains s.r.o. 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 groovy.lang.Closure +import org.gradle.api.Project +import org.gradle.api.attributes.AttributeContainer +import org.gradle.api.file.FileCollection +import org.gradle.api.tasks.SourceSet +import org.gradle.api.tasks.SourceSetOutput +import org.gradle.util.ConfigureUtil +import org.jetbrains.kotlin.gradle.plugin.* +import org.jetbrains.kotlin.gradle.plugin.source.KotlinSourceSet +import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile +import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation +import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName + +internal fun KotlinCompilation.composeName(prefix: String? = null, suffix: String? = null): String { + val compilationNamePart = compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME } + val targetNamePart = target.disambiguationClassifier + + return lowerCamelCaseName(prefix, targetNamePart, compilationNamePart, suffix) +} + +internal val KotlinCompilation.fullName: String + get() = fullCompilationName(target, compilationName) + +internal fun fullCompilationName(target: KotlinTarget, simpleName: String) = lowerCamelCaseName(target.disambiguationClassifier, simpleName) + +internal class DefaultKotlinDependencyHandler( + val parent: HasKotlinDependencies, + val project: Project +) : KotlinDependencyHandler { + override fun api(dependencyNotation: Any) = addDependency(parent.apiConfigurationName, dependencyNotation) + + override fun implementation(dependencyNotation: Any) = addDependency(parent.implementationConfigurationName, dependencyNotation) + + override fun compileOnly(dependencyNotation: Any) = addDependency(parent.compileOnlyConfigurationName, dependencyNotation) + + override fun runtimeOnly(dependencyNotation: Any) = addDependency(parent.runtimeOnlyConfigurationName, dependencyNotation) + + private fun addDependency(configurationName: String, dependencyNotation: Any) { + project.dependencies.add(configurationName, dependencyNotation) + } +} + +abstract class AbstractKotlinCompilation( + final override val target: KotlinTarget, + override val compilationName: String +) : KotlinCompilation, HasKotlinDependencies { + private val attributeContainer = HierarchyAttributeContainer(target.attributes) + + override fun getAttributes(): AttributeContainer = attributeContainer + + override val kotlinSourceSets: MutableSet = mutableSetOf() + + override fun source(sourceSet: KotlinSourceSet) { + if (kotlinSourceSets.add(sourceSet)) { + with(target.project) { + whenEvaluated { + (target.project.tasks.getByName(compileKotlinTaskName) as AbstractKotlinCompile<*>).source(sourceSet.kotlin) + } + addExtendsFromRelation(apiConfigurationName, sourceSet.apiConfigurationName) + addExtendsFromRelation(implementationConfigurationName, sourceSet.implementationConfigurationName) + addExtendsFromRelation(compileOnlyConfigurationName, sourceSet.compileOnlyConfigurationName) + if (this is KotlinCompilationToRunnableFiles) { + addExtendsFromRelation(runtimeOnlyConfigurationName, sourceSet.runtimeOnlyConfigurationName) + } + } + } + } + + override val compileDependencyConfigurationName: String + get() = lowerCamelCaseName( + target.disambiguationClassifier, + compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(), + "compileClasspath" + ) + + override val compileKotlinTaskName: String + get() = lowerCamelCaseName( + "compile", + compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }, + "Kotlin", + target.targetName + ) + + override val compileAllTaskName: String + get() = lowerCamelCaseName( + target.disambiguationClassifier, + compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }, + "classes" + ) + + override lateinit var compileDependencyFiles: FileCollection + + override val apiConfigurationName: String + get() = disambiguateName("api") + + override val implementationConfigurationName: String + get() = disambiguateName("implementation") + + override val compileOnlyConfigurationName: String + get() = disambiguateName("compileOnly") + + override val runtimeOnlyConfigurationName: String + get() = disambiguateName("runtimeOnly") + + override fun dependencies(configure: KotlinDependencyHandler.() -> Unit): Unit = + DefaultKotlinDependencyHandler(this, target.project).run(configure) + + override fun dependencies(configureClosure: Closure) = + dependencies f@{ ConfigureUtil.configure(configureClosure, this@f) } + + override fun toString(): String = "compilation '$compilationName' ($target)" +} + +abstract class AbstractKotlinCompilationToRunnableFiles( + target: KotlinTarget, + name: String +) : AbstractKotlinCompilation(target, name), KotlinCompilationToRunnableFiles { + override val runtimeDependencyConfigurationName: String + get() = lowerCamelCaseName( + target.disambiguationClassifier, + compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }, + "runtimeClasspath" + ) + + override lateinit var runtimeDependencyFiles: FileCollection +} + +internal fun KotlinCompilation.disambiguateName(simpleName: String): String { + return lowerCamelCaseName( + target.disambiguationClassifier, + compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }, + simpleName + ) +} + +open class KotlinJvmCompilation( + target: KotlinTarget, + name: String, + override val output: SourceSetOutput +) : AbstractKotlinCompilationToRunnableFiles(target, name), KotlinCompilationWithResources { + override val processResourcesTaskName: String + get() = disambiguateName("processResources") +} + +class KotlinWithJavaCompilation( + target: KotlinWithJavaTarget, + name: String +) : AbstractKotlinCompilationToRunnableFiles(target, name), KotlinCompilationWithResources { + lateinit var javaSourceSet: SourceSet + + override val output: SourceSetOutput + get() = javaSourceSet.output + + override val processResourcesTaskName: String + get() = javaSourceSet.processResourcesTaskName + + override var runtimeDependencyFiles: FileCollection + get() = javaSourceSet.runtimeClasspath + set(value) { javaSourceSet.runtimeClasspath = value } + + override val runtimeDependencyConfigurationName: String + get() = javaSourceSet.runtimeClasspathConfigurationName + + override val compileDependencyConfigurationName: String + get() = javaSourceSet.compileClasspathConfigurationName + + override val runtimeOnlyConfigurationName: String + get() = javaSourceSet.runtimeOnlyConfigurationName + + override val implementationConfigurationName: String + get() = javaSourceSet.implementationConfigurationName + + override val apiConfigurationName: String + get() = javaSourceSet.apiConfigurationName + + override val compileOnlyConfigurationName: String + get() = javaSourceSet.compileOnlyConfigurationName + + override val compileAllTaskName: String + get() = javaSourceSet.classesTaskName + + override var compileDependencyFiles: FileCollection + get() = javaSourceSet.compileClasspath + set(value) { javaSourceSet.compileClasspath = value } + + fun source(javaSourceSet: SourceSet) { + with(target.project) { + afterEvaluate { + (tasks.getByName(compileKotlinTaskName) as AbstractKotlinCompile<*>).source(javaSourceSet.java) + } + } + } +} + +class KotlinJvmAndroidCompilation( + target: KotlinAndroidTarget, + name: String, + override val output: SourceSetOutput +): AbstractKotlinCompilationToRunnableFiles(target, name) + +class KotlinJsCompilation( + target: KotlinTarget, + name: String, + override val output: SourceSetOutput +) : AbstractKotlinCompilation(target, name) + +class KotlinCommonCompilation( + target: KotlinTarget, + name: String, + override val output: SourceSetOutput +) : AbstractKotlinCompilation(target, name) \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargets.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargets.kt new file mode 100644 index 00000000000..146369031e8 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargets.kt @@ -0,0 +1,109 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. 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 org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.Project +import org.gradle.api.artifacts.Dependency +import org.gradle.api.attributes.AttributeContainer +import org.gradle.api.internal.component.UsageContext +import org.gradle.api.plugins.JavaPlugin +import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType +import org.jetbrains.kotlin.gradle.plugin.KotlinTarget +import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName + +abstract class AbstractKotlinTarget ( + override val project: Project +) : KotlinTarget { + private val attributeContainer = HierarchyAttributeContainer(parent = null) + + override fun getAttributes(): AttributeContainer = attributeContainer + + override val defaultConfigurationName: String + get() = disambiguateName("default") + + override val apiElementsConfigurationName: String + get() = disambiguateName("apiElements") + + override val runtimeElementsConfigurationName: String + get() = disambiguateName("runtimeElements") + + override val artifactsTaskName: String + get() = disambiguateName("jar") + + override fun toString(): String = "target $name ($platformType)" + + override fun createUsageContexts(): Set = setOf( + KotlinPlatformUsageContext(project, this, KotlinSoftwareComponent.kotlinApiUsage(project), apiElementsConfigurationName), + KotlinPlatformUsageContext(project, this, KotlinSoftwareComponent.kotlinRuntimeUsage(project), runtimeElementsConfigurationName) + ) +} + +internal fun KotlinTarget.disambiguateName(simpleName: String) = + lowerCamelCaseName(targetName, simpleName) + +open class KotlinAndroidTarget( + override val targetName: String, + project: Project +) : AbstractKotlinTarget(project) { + + override var disambiguationClassifier: String? = null + internal set + + override val platformType: KotlinPlatformType + get() = KotlinPlatformType.jvm + + private val compilationFactory = KotlinJvmAndroidCompilationFactory(project, this) + + override val compilations: NamedDomainObjectContainer = + project.container(compilationFactory.itemClass, compilationFactory) + + override fun createUsageContexts(): Set { + //TODO setup Android libraries publishing. This will likely require new API in the Android Gradle plugin + return emptySet() + } +} + +open class KotlinWithJavaTarget( + project: Project, + override val platformType: KotlinPlatformType, + override val targetName: String +) : AbstractKotlinTarget(project) { + override var disambiguationClassifier: String? = null + internal set + + override val defaultConfigurationName: String + get() = Dependency.DEFAULT_CONFIGURATION + + override val apiElementsConfigurationName: String + get() = JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME + + override val runtimeElementsConfigurationName: String + get() = JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME + + override val artifactsTaskName: String + get() = JavaPlugin.JAR_TASK_NAME + + override val compilations: NamedDomainObjectContainer = + project.container(KotlinWithJavaCompilation::class.java, + KotlinWithJavaCompilationFactory(project, this) + ) +} + +open class KotlinOnlyTarget( + project: Project, + override val platformType: KotlinPlatformType +) : AbstractKotlinTarget(project) { + + override lateinit var compilations: NamedDomainObjectContainer + internal set + + override lateinit var targetName: String + internal set + + override var disambiguationClassifier: String? = null + internal set +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/scripting/internal/ScriptingGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/scripting/internal/ScriptingGradleSubplugin.kt index 1af52fa5e3b..862b32662e3 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/scripting/internal/ScriptingGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/scripting/internal/ScriptingGradleSubplugin.kt @@ -7,12 +7,8 @@ package org.jetbrains.kotlin.gradle.scripting.internal import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.compile.AbstractCompile -import org.jetbrains.kotlin.gradle.plugin.JetBrainsSubpluginArtifact -import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin -import org.jetbrains.kotlin.gradle.plugin.SubpluginArtifact -import org.jetbrains.kotlin.gradle.plugin.SubpluginOption +import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.scripting.ScriptingExtension class ScriptingGradleSubplugin : Plugin { @@ -39,10 +35,10 @@ class ScriptingKotlinGradleSubplugin : KotlinGradleSubplugin { override fun apply( project: Project, kotlinCompile: AbstractCompile, - javaCompile: AbstractCompile, + javaCompile: AbstractCompile?, variantData: Any?, androidProjectHandler: Any?, - javaSourceSet: SourceSet? + kotlinCompilation: KotlinCompilation? ): List { if (!ScriptingGradleSubplugin.isEnabled(project)) return emptyList() diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/gradleConfigurationUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/gradleConfigurationUtils.kt new file mode 100644 index 00000000000..40100e183b8 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/gradleConfigurationUtils.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. 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 org.gradle.api.Project + +fun Project.addExtendsFromRelation(extendingConfigurationName: String, extendsFromConfigurationName: String) { + if (extendingConfigurationName != extendsFromConfigurationName) { + project.dependencies.add(extendingConfigurationName, project.configurations.getByName(extendsFromConfigurationName)) + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/stringUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/stringUtils.kt new file mode 100644 index 00000000000..6037743c889 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/stringUtils.kt @@ -0,0 +1,15 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. 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 + +internal fun lowerCamelCaseName(vararg nameParts: String?): String { + val nonEmptyParts = nameParts.mapNotNull { it?.takeIf(String::isNotEmpty) } + return nonEmptyParts.drop(1).joinToString( + separator = "", + prefix = nonEmptyParts.firstOrNull().orEmpty(), + transform = String::capitalize + ) +} diff --git a/libraries/tools/kotlin-noarg/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/NoArgSubplugin.kt b/libraries/tools/kotlin-noarg/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/NoArgSubplugin.kt index e7c5b1ba567..435a73f7b06 100644 --- a/libraries/tools/kotlin-noarg/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/NoArgSubplugin.kt +++ b/libraries/tools/kotlin-noarg/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/NoArgSubplugin.kt @@ -18,16 +18,9 @@ package org.jetbrains.kotlin.noarg.gradle import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.internal.AbstractTask -import org.gradle.api.artifacts.ResolvedArtifact -import org.gradle.api.internal.ConventionTask -import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry -import org.jetbrains.kotlin.gradle.plugin.JetBrainsSubpluginArtifact -import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin -import org.jetbrains.kotlin.gradle.plugin.SubpluginArtifact -import org.jetbrains.kotlin.gradle.plugin.SubpluginOption +import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.noarg.gradle.model.builder.NoArgModelBuilder import javax.inject.Inject @@ -58,12 +51,12 @@ class NoArgKotlinGradleSubplugin : KotlinGradleSubplugin { override fun isApplicable(project: Project, task: AbstractCompile) = NoArgGradleSubplugin.isEnabled(project) override fun apply( - project: Project, - kotlinCompile: AbstractCompile, - javaCompile: AbstractCompile, - variantData: Any?, - androidProjectHandler: Any?, - javaSourceSet: SourceSet? + project: Project, + kotlinCompile: AbstractCompile, + javaCompile: AbstractCompile?, + variantData: Any?, + androidProjectHandler: Any?, + kotlinCompilation: KotlinCompilation? ): List { if (!NoArgGradleSubplugin.isEnabled(project)) return emptyList() diff --git a/libraries/tools/kotlin-sam-with-receiver/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/SamWithReceiverSubplugin.kt b/libraries/tools/kotlin-sam-with-receiver/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/SamWithReceiverSubplugin.kt index 8b5550aaf8f..6a36921fa35 100644 --- a/libraries/tools/kotlin-sam-with-receiver/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/SamWithReceiverSubplugin.kt +++ b/libraries/tools/kotlin-sam-with-receiver/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/SamWithReceiverSubplugin.kt @@ -18,16 +18,9 @@ package org.jetbrains.kotlin.samWithReceiver.gradle import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.internal.AbstractTask -import org.gradle.api.artifacts.ResolvedArtifact -import org.gradle.api.internal.ConventionTask -import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry -import org.jetbrains.kotlin.gradle.plugin.JetBrainsSubpluginArtifact -import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin -import org.jetbrains.kotlin.gradle.plugin.SubpluginArtifact -import org.jetbrains.kotlin.gradle.plugin.SubpluginOption +import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.noarg.gradle.model.builder.SamWithReceiverModelBuilder import javax.inject.Inject @@ -53,12 +46,12 @@ class SamWithReceiverKotlinGradleSubplugin : KotlinGradleSubplugin { if (!SamWithReceiverGradleSubplugin.isEnabled(project)) return emptyList()