Update existing plugin implementations to use KotlinCompilation

Add default implementations for KotlinTarget and KotlinCompilation
(some of them are used in code added by further commits).

Refactor AbstractKotlinPlugin so that parts of its logic can be easily
applied outside the plugin (needed for MPP plugin later).

The single platform Kotlin plugins having Kotlin compiled along with
Java will now create a KotlinCompilation and a KotlinSourceSet per Java
source set or per Android variant.
The build configuration logic will use KotlinCompilation
objects rather than Java or Android plugin entities.

Subplugins API and implementations are updated to use KotlinCompilation.
This commit is contained in:
Sergey Igushkin
2018-07-13 14:42:24 +03:00
parent 25eb93b136
commit dc7d488deb
21 changed files with 1168 additions and 443 deletions
@@ -16,13 +16,9 @@
package example package example
import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.AbstractCompile
import org.jetbrains.kotlin.gradle.plugin.JetBrainsSubpluginArtifact import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.SubpluginArtifact
import org.jetbrains.kotlin.gradle.plugin.SubpluginOption
class ExampleSubplugin : KotlinGradleSubplugin<AbstractCompile> { class ExampleSubplugin : KotlinGradleSubplugin<AbstractCompile> {
@@ -31,12 +27,12 @@ class ExampleSubplugin : KotlinGradleSubplugin<AbstractCompile> {
} }
override fun apply( override fun apply(
project: Project, project: Project,
kotlinCompile: AbstractCompile, kotlinCompile: AbstractCompile,
javaCompile: AbstractCompile, javaCompile: AbstractCompile?,
variantData: Any?, variantData: Any?,
androidProjectHandler: Any?, androidProjectHandler: Any?,
javaSourceSet: SourceSet? kotlinCompilation: KotlinCompilation?
): List<SubpluginOption> { ): List<SubpluginOption> {
println("ExampleSubplugin loaded") println("ExampleSubplugin loaded")
return listOf(SubpluginOption("exampleKey", "exampleValue")) return listOf(SubpluginOption("exampleKey", "exampleValue"))
@@ -18,16 +18,10 @@ package org.jetbrains.kotlin.allopen.gradle
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project 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.api.tasks.compile.AbstractCompile
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.allopen.gradle.model.builder.AllOpenModelBuilder import org.jetbrains.kotlin.allopen.gradle.model.builder.AllOpenModelBuilder
import org.jetbrains.kotlin.gradle.plugin.JetBrainsSubpluginArtifact import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin
import org.jetbrains.kotlin.gradle.plugin.SubpluginArtifact
import org.jetbrains.kotlin.gradle.plugin.SubpluginOption
import javax.inject.Inject import javax.inject.Inject
class AllOpenGradleSubplugin @Inject internal constructor(private val registry: ToolingModelBuilderRegistry) : Plugin<Project> { class AllOpenGradleSubplugin @Inject internal constructor(private val registry: ToolingModelBuilderRegistry) : Plugin<Project> {
@@ -56,12 +50,12 @@ class AllOpenKotlinGradleSubplugin : KotlinGradleSubplugin<AbstractCompile> {
override fun isApplicable(project: Project, task: AbstractCompile) = AllOpenGradleSubplugin.isEnabled(project) override fun isApplicable(project: Project, task: AbstractCompile) = AllOpenGradleSubplugin.isEnabled(project)
override fun apply( override fun apply(
project: Project, project: Project,
kotlinCompile: AbstractCompile, kotlinCompile: AbstractCompile,
javaCompile: AbstractCompile, javaCompile: AbstractCompile?,
variantData: Any?, variantData: Any?,
androidProjectHandler: Any?, androidProjectHandler: Any?,
javaSourceSet: SourceSet? kotlinCompilation: KotlinCompilation?
): List<SubpluginOption> { ): List<SubpluginOption> {
if (!AllOpenGradleSubplugin.isEnabled(project)) return emptyList() if (!AllOpenGradleSubplugin.isEnabled(project)) return emptyList()
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.gradle.plugin package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.AbstractCompile
import java.io.File import java.io.File
@@ -52,12 +51,12 @@ interface KotlinGradleSubplugin<in KotlinCompile : AbstractCompile> {
fun isApplicable(project: Project, task: AbstractCompile): Boolean fun isApplicable(project: Project, task: AbstractCompile): Boolean
fun apply( fun apply(
project: Project, project: Project,
kotlinCompile: KotlinCompile, kotlinCompile: KotlinCompile,
javaCompile: AbstractCompile, javaCompile: AbstractCompile?,
variantData: Any?, variantData: Any?,
androidProjectHandler: Any?, androidProjectHandler: Any?,
javaSourceSet: SourceSet? kotlinCompilation: KotlinCompilation?
): List<SubpluginOption> ): List<SubpluginOption>
fun getSubpluginKotlinTasks( fun getSubpluginKotlinTasks(
@@ -11,7 +11,9 @@ import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin
import org.jetbrains.kotlin.gradle.internal.KaptTask import org.jetbrains.kotlin.gradle.internal.KaptTask
import org.jetbrains.kotlin.gradle.internal.KaptVariantData import org.jetbrains.kotlin.gradle.internal.KaptVariantData
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
import java.io.File import java.io.File
@Suppress("unused") @Suppress("unused")
@@ -36,13 +38,15 @@ class Android25ProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools
} }
} }
override fun wireKotlinTasks(project: Project, override fun wireKotlinTasks(
androidPlugin: BasePlugin, project: Project,
androidExt: BaseExtension, compilation: KotlinJvmAndroidCompilation,
variantData: BaseVariant, androidPlugin: BasePlugin,
javaTask: AbstractCompile, androidExt: BaseExtension,
kotlinTask: KotlinCompile) { variantData: BaseVariant,
javaTask: AbstractCompile,
kotlinTask: KotlinCompile
) {
val preJavaKotlinOutputFiles = mutableListOf<File>().apply { val preJavaKotlinOutputFiles = mutableListOf<File>().apply {
add(kotlinTask.destinationDir) add(kotlinTask.destinationDir)
if (Kapt3GradleSubplugin.isEnabled(project)) { if (Kapt3GradleSubplugin.isEnabled(project)) {
@@ -95,6 +99,20 @@ class Android25ProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools
return variantData.mergeResources?.computeResourceSetList0() ?: emptyList() 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<BaseVariant>(variantData) { private inner class KaptVariant(variantData: BaseVariant) : KaptVariantData<BaseVariant>(variantData) {
override val name: String = getVariantName(variantData) override val name: String = getVariantName(variantData)
override val sourceProviders: Iterable<SourceProvider> = getSourceProviders(variantData) override val sourceProviders: Iterable<SourceProvider> = getSourceProviders(variantData)
@@ -16,13 +16,19 @@
package org.jetbrains.kotlin.gradle.dsl package org.jetbrains.kotlin.gradle.dsl
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.internal.plugins.DslObject 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 import kotlin.reflect.KClass
internal fun Project.createKotlinExtension(extensionClass: KClass<out KotlinProjectExtension>) { private const val KOTLIN_PROJECT_EXTENSION_NAME = "kotlin"
val kotlinExt = extensions.create("kotlin", extensionClass.java)
internal fun Project.createKotlinExtension(extensionClass: KClass<out KotlinProjectExtension>): KotlinProjectExtension {
val kotlinExt = extensions.create(KOTLIN_PROJECT_EXTENSION_NAME, extensionClass.java)
DslObject(kotlinExt).extensions.create("experimental", ExperimentalExtension::class.java) DslObject(kotlinExt).extensions.create("experimental", ExperimentalExtension::class.java)
return kotlinExtension
} }
internal val Project.kotlinExtension: KotlinProjectExtension internal val Project.kotlinExtension: KotlinProjectExtension
@@ -38,7 +44,11 @@ open class KotlinProjectExtension {
internal set(value) { DslObject(this).extensions.add("sourceSets", value) } 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 * 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. * single classes directory per source set. With Gradle < 4.0, has no effect.
@@ -25,7 +25,6 @@ import com.android.build.gradle.internal.variant.TestVariantData
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.UnknownDomainObjectException import org.gradle.api.UnknownDomainObjectException
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.AbstractCompile
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.gradle.model.builder.KotlinAndroidExtensionModelBuilder import org.jetbrains.kotlin.gradle.model.builder.KotlinAndroidExtensionModelBuilder
@@ -90,12 +89,12 @@ class AndroidSubplugin : KotlinGradleSubplugin<KotlinCompile> {
} }
override fun apply( override fun apply(
project: Project, project: Project,
kotlinCompile: KotlinCompile, kotlinCompile: KotlinCompile,
javaCompile: AbstractCompile, javaCompile: AbstractCompile?,
variantData: Any?, variantData: Any?,
androidProjectHandler: Any?, androidProjectHandler: Any?,
javaSourceSet: SourceSet? kotlinCompilation: KotlinCompilation?
): List<SubpluginOption> { ): List<SubpluginOption> {
val androidExtension = project.extensions.getByName("android") as? BaseExtension ?: return emptyList() val androidExtension = project.extensions.getByName("android") as? BaseExtension ?: return emptyList()
val androidExtensionsExtension = project.extensions.getByType(AndroidExtensionsExtension::class.java) val androidExtensionsExtension = project.extensions.getByType(AndroidExtensionsExtension::class.java)
@@ -158,10 +158,10 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
private inner class Kapt3SubpluginContext( private inner class Kapt3SubpluginContext(
val project: Project, val project: Project,
val kotlinCompile: KotlinCompile, val kotlinCompile: KotlinCompile,
val javaCompile: AbstractCompile, val javaCompile: AbstractCompile?,
val kaptVariantData: KaptVariantData<*>?, val kaptVariantData: KaptVariantData<*>?,
val sourceSetName: String, val sourceSetName: String,
val javaSourceSet: SourceSet?, val kotlinCompilation: KotlinCompilation?,
val kaptExtension: KaptExtension, val kaptExtension: KaptExtension,
val kaptClasspathConfigurations: List<Configuration> val kaptClasspathConfigurations: List<Configuration>
) { ) {
@@ -171,14 +171,14 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
} }
override fun apply( override fun apply(
project: Project, project: Project,
kotlinCompile: KotlinCompile, kotlinCompile: KotlinCompile,
javaCompile: AbstractCompile, javaCompile: AbstractCompile?,
variantData: Any?, variantData: Any?,
androidProjectHandler: Any?, androidProjectHandler: Any?,
javaSourceSet: SourceSet? kotlinCompilation: KotlinCompilation?
): List<SubpluginOption> { ): List<SubpluginOption> {
assert((variantData != null) xor (javaSourceSet != null)) assert((variantData != null) xor (kotlinCompilation != null))
val buildDependencies = arrayListOf<TaskDependency>() val buildDependencies = arrayListOf<TaskDependency>()
val kaptConfigurations = arrayListOf<Configuration>() val kaptConfigurations = arrayListOf<Configuration>()
@@ -200,10 +200,10 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
kaptVariantData.name kaptVariantData.name
} }
else { 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) handleSourceSet(kotlinCompilation.compilationName)
javaSourceSet.name kotlinCompilation.compilationName
} }
val kaptExtension = project.extensions.getByType(KaptExtension::class.java) val kaptExtension = project.extensions.getByType(KaptExtension::class.java)
@@ -212,7 +212,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
val context = Kapt3SubpluginContext( val context = Kapt3SubpluginContext(
project, kotlinCompile, javaCompile, project, kotlinCompile, javaCompile,
kaptVariantData, sourceSetName, javaSourceSet, kaptExtension, nonEmptyKaptConfigurations kaptVariantData, sourceSetName, kotlinCompilation, kaptExtension, nonEmptyKaptConfigurations
) )
val kaptGenerateStubsTask = context.createKaptGenerateStubsTask() val kaptGenerateStubsTask = context.createKaptGenerateStubsTask()
@@ -245,7 +245,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
pluginOptions += SubpluginOption("aptMode", aptMode) pluginOptions += SubpluginOption("aptMode", aptMode)
disableAnnotationProcessingInJavaTask() disableAnnotationProcessingInJavaTask()
javaCompile.source(generatedFilesDir) javaCompile?.source(generatedFilesDir)
pluginOptions += FilesSubpluginOption("sources", listOf(generatedFilesDir)) pluginOptions += FilesSubpluginOption("sources", listOf(generatedFilesDir))
pluginOptions += FilesSubpluginOption("classes", listOf(getKaptGeneratedClassesDir(project, sourceSetName))) pluginOptions += FilesSubpluginOption("classes", listOf(getKaptGeneratedClassesDir(project, sourceSetName)))
@@ -362,18 +362,22 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
kaptTask.kotlinSourcesDestinationDir = kotlinSourcesOutputDir kaptTask.kotlinSourcesDestinationDir = kotlinSourcesOutputDir
kaptTask.classesDir = classesOutputDir kaptTask.classesDir = classesOutputDir
javaSourceSet?.output?.apply { kotlinCompilation?.run {
if (tryAddClassesDir { project.files(classesOutputDir).builtBy(kaptTask) }) { output.apply {
kotlinCompile.attachClassesDir { classesOutputDir } if (tryAddClassesDir { project.files(classesOutputDir).builtBy(kaptTask) }) {
kotlinCompile.attachClassesDir { classesOutputDir }
}
} }
} }
kotlinCompile.source(sourcesOutputDir, kotlinSourcesOutputDir) kotlinCompile.source(sourcesOutputDir, kotlinSourcesOutputDir)
if (kaptVariantData != null) { if (javaCompile != null) {
kaptVariantData.registerGeneratedJavaSource(project, kaptTask, javaCompile) if (kaptVariantData != null) {
} else { kaptVariantData.registerGeneratedJavaSource(project, kaptTask, javaCompile)
registerGeneratedJavaSource(kaptTask, javaCompile) } else {
registerGeneratedJavaSource(kaptTask, javaCompile)
}
} }
kaptTask.kaptClasspathConfigurations = kaptClasspathConfigurations kaptTask.kaptClasspathConfigurations = kaptClasspathConfigurations
@@ -21,9 +21,8 @@ import org.gradle.api.*
import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ProjectDependency import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.file.SourceDirectorySet import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.plugins.JavaPluginConvention import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.gradle.api.tasks.SourceSet import org.jetbrains.kotlin.gradle.plugin.source.KotlinSourceSet
import org.gradle.api.tasks.SourceSetContainer
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
abstract class KotlinPlatformPluginBase(protected val platformName: String) : Plugin<Project> { abstract class KotlinPlatformPluginBase(protected val platformName: String) : Plugin<Project> {
@@ -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, // 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: // 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 // todo warn if no match found
matchSymmetricallyByNames(commonProject.sourceSets, namedSourceSetsContainer(platformProject)) { commonSourceSet, _ -> matchSymmetricallyByNames(
getKotlinSourceSetsSafe(commonProject),
namedSourceSetsContainer(platformProject)
) { commonSourceSet: Named, _ ->
addCommonSourceSetToPlatformSourceSet(commonSourceSet, platformProject) 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. * regardless of the order in which they are added to the containers.
*/ */
private fun <A, B> matchSymmetricallyByNames( private fun <A, B> matchSymmetricallyByNames(
containerA: NamedDomainObjectContainer<A>, containerA: NamedDomainObjectCollection<out A>,
containerB: NamedDomainObjectContainer<B>, containerB: NamedDomainObjectCollection<out B>,
whenMatched: (A, B) -> Unit whenMatched: (A, B) -> Unit
) { ) {
val matchedNames = mutableSetOf<String>() val matchedNames = mutableSetOf<String>()
fun <T, R> NamedDomainObjectContainer<T>.matchAllWith(other: NamedDomainObjectContainer<R>, match: (T, R) -> Unit) { fun <T, R> NamedDomainObjectCollection<T>.matchAllWith(other: NamedDomainObjectCollection<R>, match: (T, R) -> Unit) {
this@matchAllWith.all { item -> this@matchAllWith.all { item ->
val itemName = this@matchAllWith.namer.determineName(item) val itemName = this@matchAllWith.namer.determineName(item)
if (itemName !in matchedNames) { if (itemName !in matchedNames) {
@@ -144,36 +146,38 @@ open class KotlinPlatformImplementationPluginBase(platformName: String) : Kotlin
} }
protected open fun namedSourceSetsContainer(project: Project): NamedDomainObjectContainer<*> = protected open fun namedSourceSetsContainer(project: Project): NamedDomainObjectContainer<*> =
project.sourceSets project.kotlinExtension.sourceSets
protected open fun addCommonSourceSetToPlatformSourceSet(commonSourceSet: SourceSet, platformProject: Project) { protected open fun addCommonSourceSetToPlatformSourceSet(commonSourceSet: Named, platformProject: Project) {
val platformTask = platformProject.tasks platformProject.whenEvaluated { // At the point when the source set in the platform module is created, the task does not exist
.filterIsInstance<AbstractKotlinCompile<*>>() val platformTask = platformProject.tasks
.firstOrNull { it.sourceSetName == commonSourceSet.name } .filterIsInstance<AbstractKotlinCompile<*>>()
.single { it.sourceSetName == commonSourceSet.name }
platformTask?.source(commonSourceSet.kotlin!!) platformTask.source(getKotlinSourceDirectorySetSafe(commonSourceSet))
}
} }
protected val SourceSet.kotlin: SourceDirectorySet? private fun getKotlinSourceSetsSafe(project: Project): NamedDomainObjectCollection<out Named> {
get() { // Access through reflection, because another project's KotlinProjectExtension might be loaded by a different class loader:
// Access through reflection, because another project's KotlinSourceSet might be loaded val kotlinExt = project.extensions.getByName("kotlin")
// by a different class loader: @Suppress("UNCHECKED_CAST")
val convention = (getConvention("kotlin") ?: getConvention("kotlin2js")) ?: return null val sourceSets = kotlinExt.javaClass.getMethod("getSourceSets").invoke(kotlinExt) as NamedDomainObjectCollection<out Named>
val kotlinSourceSetIface = convention.javaClass.interfaces.find { it.name == KotlinSourceSet::class.qualifiedName } return sourceSets
val getKotlin = kotlinSourceSetIface?.methods?.find { it.name == "getKotlin" } ?: return null }
return getKotlin(convention) as? SourceDirectorySet
}
companion object { protected fun getKotlinSourceDirectorySetSafe(from: Any): SourceDirectorySet? {
@JvmStatic val getKotlin = from.javaClass.getMethod("getKotlin")
protected fun <T> Project.whenEvaluated(fn: Project.() -> T) { return getKotlin(from) as? SourceDirectorySet
if (state.executed) { }
fn() }
}
else { internal fun <T> Project.whenEvaluated(fn: Project.() -> T) {
afterEvaluate { it.fn() } if (state.executed) {
} fn()
} }
else {
afterEvaluate { it.fn() }
} }
} }
@@ -190,11 +194,12 @@ open class KotlinPlatformAndroidPlugin : KotlinPlatformImplementationPluginBase(
override fun namedSourceSetsContainer(project: Project): NamedDomainObjectContainer<*> = override fun namedSourceSetsContainer(project: Project): NamedDomainObjectContainer<*> =
(project.extensions.getByName("android") as BaseExtension).sourceSets (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 androidExtension = platformProject.extensions.getByName("android") as BaseExtension
val androidSourceSet = androidExtension.sourceSets.findByName(commonSourceSet.name) ?: return val androidSourceSet = androidExtension.sourceSets.findByName(commonSourceSet.name) ?: return
val kotlinSourceSet = androidSourceSet.getConvention(KOTLIN_DSL_NAME) as? KotlinSourceSet ?: return val kotlinSourceSet = androidSourceSet.getConvention(KOTLIN_DSL_NAME) as? KotlinSourceSet
kotlinSourceSet.kotlin.source(commonSourceSet.kotlin!!) ?: return
kotlinSourceSet.kotlin.source(getKotlinSourceDirectorySetSafe(commonSourceSet)!!)
} }
} }
@@ -210,7 +215,4 @@ open class KotlinPlatformJsPlugin : KotlinPlatformImplementationPluginBase("js")
project.applyPlugin<Kotlin2JsPluginWrapper>() project.applyPlugin<Kotlin2JsPluginWrapper>()
super.apply(project) super.apply(project)
} }
} }
private val Project.sourceSets: SourceSetContainer
get() = convention.getPlugin(JavaPluginConvention::class.java).sourceSets
@@ -5,7 +5,6 @@ import com.android.build.gradle.BasePlugin
import com.android.builder.model.SourceProvider import com.android.builder.model.SourceProvider
import groovy.lang.Closure import groovy.lang.Closure
import org.gradle.api.* import org.gradle.api.*
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ExternalDependency import org.gradle.api.artifacts.ExternalDependency
import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.FileCollection 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.Logger
import org.gradle.api.logging.Logging import org.gradle.api.logging.Logging
import org.gradle.api.plugins.InvalidPluginException import org.gradle.api.plugins.InvalidPluginException
import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.api.plugins.JavaPlugin import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.plugins.JavaPluginConvention import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.tasks.CompileClasspathNormalizer 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.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl 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.Kapt3GradleSubplugin.Companion.getKaptGeneratedClassesDir
import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin
import org.jetbrains.kotlin.gradle.internal.KaptVariantData import org.jetbrains.kotlin.gradle.internal.KaptVariantData
import org.jetbrains.kotlin.gradle.internal.checkAndroidAnnotationProcessorDependencyUsage import org.jetbrains.kotlin.gradle.internal.checkAndroidAnnotationProcessorDependencyUsage
import org.jetbrains.kotlin.gradle.model.builder.KotlinModelBuilder 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.scripting.internal.ScriptingGradleSubplugin
import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlin.gradle.tasks.*
import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.gradle.utils.*
@@ -47,58 +49,90 @@ val KOTLIN_JS_DSL_NAME = "kotlin2js"
val KOTLIN_OPTIONS_DSL_NAME = "kotlinOptions" val KOTLIN_OPTIONS_DSL_NAME = "kotlinOptions"
internal abstract class KotlinSourceSetProcessor<T : AbstractKotlinCompile<*>>( internal abstract class KotlinSourceSetProcessor<T : AbstractKotlinCompile<*>>(
val project: Project, val project: Project,
val javaBasePlugin: JavaBasePlugin, val tasksProvider: KotlinTasksProvider,
val sourceSet: SourceSet, val taskDescription: String,
val tasksProvider: KotlinTasksProvider, val kotlinCompilation: KotlinCompilation
val kotlinSourceSetProvider: KotlinSourceSetProvider,
val dslExtensionName: String,
val compileTaskNameSuffix: String,
val taskDescription: String
) { ) {
abstract protected fun doTargetSpecificProcessing() abstract protected fun doTargetSpecificProcessing()
protected val logger = Logging.getLogger(this.javaClass)!! protected val logger = Logging.getLogger(this.javaClass)!!
protected val isSeparateClassesDirSupported: Boolean by lazy { protected val isSeparateClassesDirSupported: Boolean by lazy {
!CopyClassesToJavaOutputStatus.isEnabled(project) && !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 sourceSetName: String = kotlinCompilation.compilationName
protected val sourceRootDir: String = "src/$sourceSetName/kotlin"
protected val kotlinSourceSet: KotlinSourceSet = createKotlinSourceSet()
protected val kotlinTask: T = createKotlinCompileTask() protected val kotlinTask: T = createKotlinCompileTask()
protected open val defaultKotlinDestinationDir: File protected open val defaultKotlinDestinationDir: File
get() = if (isSeparateClassesDirSupported) get() {
File(project.buildDir, "classes/kotlin/${sourceSet.name}") else return if (isSeparateClassesDirSupported) {
sourceSet.output.classesDir 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() { private fun createKotlinCompileTask(): T {
addKotlinDirSetToSources() 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() doTargetSpecificProcessing()
} }
private fun createKotlinSourceSet(): KotlinSourceSet { protected abstract fun doCreateTask(project: Project, taskName: String): T
logger.kotlinDebug("Creating KotlinSourceSet for $sourceSet") }
val kotlinSourceSet = kotlinSourceSetProvider.create(sourceSet.name)
kotlinSourceSet.kotlin.srcDir(project.file(sourceRootDir)) internal abstract class KotlinJavaSourceSetProcessor<T : AbstractKotlinCompile<*>>(
sourceSet.addConvention(dslExtensionName, kotlinSourceSet) project: Project,
return kotlinSourceSet tasksProvider: KotlinTasksProvider,
taskDescription: String,
val javaSourceSet: SourceSet?,
kotlinCompilation: KotlinCompilation
): KotlinSourceSetProcessor<T>(
project, tasksProvider, taskDescription, kotlinCompilation
) {
override fun run() {
addKotlinDirSetToSources()
super.run()
} }
private fun addKotlinDirSetToSources() { 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: // Try to avoid duplicate Java sources in allSource:
val kotlinSrcDirsToAdd = filterOutJavaSrcDirsIfPossible(kotlinDirSet) val kotlinSrcDirsToAdd = kotlinDirSets.map { filterOutJavaSrcDirsIfPossible(it) }
sourceSet.allJava.srcDirs(kotlinSrcDirsToAdd) kotlinSrcDirsToAdd.forEach { kotlinSrcDirs ->
sourceSet.allSource.srcDirs(kotlinSrcDirsToAdd) javaSourceSet.allJava.srcDirs(kotlinSrcDirs)
sourceSet.resources.filter.exclude { it.file in kotlinDirSet } javaSourceSet.allSource.srcDirs(kotlinSrcDirs)
javaSourceSet.resources.filter.exclude { it.file in kotlinSrcDirs }
}
} }
private fun filterOutJavaSrcDirsIfPossible(sourceDirectorySet: SourceDirectorySet): FileCollection { 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 the API used below is not available, fall back to not filtering the Java sources.
if (SourceDirectorySet::class.java.methods.none { it.name == "getSourceDirectories" }) { if (SourceDirectorySet::class.java.methods.none { it.name == "getSourceDirectories" }) {
return sourceDirectorySet return sourceDirectorySet
@@ -110,35 +144,19 @@ internal abstract class KotlinSourceSetProcessor<T : AbstractKotlinCompile<*>>(
} }
// Build a lazily-resolved file collection that filters out Java sources from sources of this sourceDirectorySet // 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( internal class Kotlin2JvmSourceSetProcessor(
project: Project, project: Project,
javaBasePlugin: JavaBasePlugin, tasksProvider: KotlinTasksProvider,
sourceSet: SourceSet, kotlinCompilation: KotlinCompilation,
tasksProvider: KotlinTasksProvider, private val kotlinPluginVersion: String
kotlinSourceSetProvider: KotlinSourceSetProvider, ) : KotlinJavaSourceSetProcessor<KotlinCompile>(
private val kotlinPluginVersion: String project, tasksProvider, taskDescription = "Compiles the $kotlinCompilation.",
) : KotlinSourceSetProcessor<KotlinCompile>( javaSourceSet = if (kotlinCompilation is KotlinWithJavaCompilation) kotlinCompilation.javaSourceSet else null,
project, javaBasePlugin, sourceSet, tasksProvider, kotlinSourceSetProvider, kotlinCompilation = kotlinCompilation
dslExtensionName = KOTLIN_DSL_NAME,
compileTaskNameSuffix = "kotlin",
taskDescription = "Compiles the $sourceSet.kotlin."
) { ) {
override val defaultKotlinDestinationDir: File override val defaultKotlinDestinationDir: File
get() = if (!isSeparateClassesDirSupported) get() = if (!isSeparateClassesDirSupported)
@@ -146,44 +164,38 @@ internal class Kotlin2JvmSourceSetProcessor(
super.defaultKotlinDestinationDir super.defaultKotlinDestinationDir
override fun doCreateTask(project: Project, taskName: String): KotlinCompile = override fun doCreateTask(project: Project, taskName: String): KotlinCompile =
tasksProvider.createKotlinJVMTask(project, taskName, sourceSet.name) tasksProvider.createKotlinJVMTask(project, taskName, kotlinCompilation.compilationName)
override fun doTargetSpecificProcessing() { override fun doTargetSpecificProcessing() {
kotlinSourceSet.kotlin.source(sourceSet.java) Kapt3KotlinGradleSubplugin.createAptConfigurationIfNeeded(project, kotlinCompilation.compilationName)
Kapt3KotlinGradleSubplugin.createAptConfigurationIfNeeded(project, sourceSet.name)
project.afterEvaluate { project -> project.afterEvaluate { project ->
if (project != null) { val javaTask = javaSourceSet?.let { project.tasks.findByName(it.compileJavaTaskName) as JavaCompile }
val javaTask = project.tasks.findByName(sourceSet.compileJavaTaskName)
val subpluginEnvironment = loadSubplugins(project, kotlinPluginVersion) val subpluginEnvironment = loadSubplugins(project, kotlinPluginVersion)
val appliedPlugins = subpluginEnvironment.addSubpluginOptions( val appliedPlugins = subpluginEnvironment.addSubpluginOptions(
project, kotlinTask, javaTask as JavaCompile, null, null, sourceSet) project, kotlinTask, javaTask, null, null, kotlinCompilation
)
// KotlinCompile.source(kotlinDirSet) should be called only after all java roots are added to kotlinDirSet appliedPlugins
// otherwise some java roots can be ignored .flatMap { it.getSubpluginKotlinTasks(project, kotlinTask) }
kotlinTask.source(kotlinSourceSet.kotlin) .forEach { plugin -> kotlinCompilation.kotlinSourceSets.forEach { sourceSet -> plugin.source(sourceSet.kotlin) } }
appliedPlugins
.flatMap { it.getSubpluginKotlinTasks(project, kotlinTask) }
.forEach { it.source(kotlinSourceSet.kotlin) }
configureJavaTask(kotlinTask, javaTask, logger) javaTask?.let { configureJavaTask(kotlinTask, it, logger) }
var syncOutputTask: SyncOutputTask? = null var syncOutputTask: SyncOutputTask? = null
if (!isSeparateClassesDirSupported) { if (!isSeparateClassesDirSupported && javaTask != null) {
syncOutputTask = createSyncOutputTask(project, kotlinTask, javaTask, sourceSetName) syncOutputTask = createSyncOutputTask(project, kotlinTask, javaTask, sourceSetName)
} }
if (project.pluginManager.hasPlugin("java-library") && sourceSetName == SourceSet.MAIN_SOURCE_SET_NAME) { if (project.pluginManager.hasPlugin("java-library") && sourceSetName == SourceSet.MAIN_SOURCE_SET_NAME) {
val (classesProviderTask, classesDirectory) = when { val (classesProviderTask, classesDirectory) = when {
isSeparateClassesDirSupported -> kotlinTask.let { it to it.destinationDir } isSeparateClassesDirSupported -> kotlinTask.let { it to it.destinationDir }
else -> syncOutputTask!!.let { it to it.javaOutputDir } else -> syncOutputTask!!.let { it to it.javaOutputDir }
}
registerKotlinOutputForJavaLibrary(classesDirectory, classesProviderTask)
} }
registerKotlinOutputForJavaLibrary(classesDirectory, classesProviderTask)
} }
} }
} }
@@ -233,37 +245,35 @@ internal fun SourceSetOutput.tryAddClassesDir(
} }
internal class Kotlin2JsSourceSetProcessor( internal class Kotlin2JsSourceSetProcessor(
project: Project, project: Project,
javaBasePlugin: JavaBasePlugin, tasksProvider: KotlinTasksProvider,
sourceSet: SourceSet, kotlinCompilation: KotlinCompilation,
tasksProvider: KotlinTasksProvider, private val kotlinPluginVersion: String
kotlinSourceSetProvider: KotlinSourceSetProvider,
private val kotlinPluginVersion: String
) : KotlinSourceSetProcessor<Kotlin2JsCompile>( ) : KotlinSourceSetProcessor<Kotlin2JsCompile>(
project, javaBasePlugin, sourceSet, tasksProvider, kotlinSourceSetProvider, project, tasksProvider, taskDescription = "Compiles the Kotlin sources in $kotlinCompilation to JavaScript.",
dslExtensionName = KOTLIN_JS_DSL_NAME, kotlinCompilation = kotlinCompilation
taskDescription = "Compiles the kotlin sources in $sourceSet to JavaScript.",
compileTaskNameSuffix = "kotlin2Js"
) { ) {
override fun doCreateTask(project: Project, taskName: String): Kotlin2JsCompile = override fun doCreateTask(project: Project, taskName: String): Kotlin2JsCompile =
tasksProvider.createKotlinJSTask(project, taskName, sourceSet.name) tasksProvider.createKotlinJSTask(project, taskName, kotlinCompilation.compilationName)
override fun doTargetSpecificProcessing() { override fun doTargetSpecificProcessing() {
project.tasks.findByName(sourceSet.classesTaskName)!!.dependsOn(kotlinTask) project.tasks.findByName(kotlinCompilation.compileAllTaskName)!!.dependsOn(kotlinTask)
kotlinTask.source(kotlinSourceSet.kotlin)
createCleanSourceMapTask() 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: // outputFile can be set later during the configuration phase, get it only after the phase:
project.afterEvaluate { project -> 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 kotlinTask.kotlinOptions.outputFile = kotlinTask.outputFile.absolutePath
val outputDir = kotlinTask.outputFile.parentFile 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)) if (outputDir.isParentOf(project.rootDir))
throw InvalidUserDataException( throw InvalidUserDataException(
"The output directory '$outputDir' (defined by outputFile of $kotlinTask) contains or " + "The output directory '$outputDir' (defined by outputFile of $kotlinTask) contains or " +
@@ -274,17 +284,17 @@ internal class Kotlin2JsSourceSetProcessor(
kotlinTask.destinationDir = outputDir kotlinTask.destinationDir = outputDir
if (!isSeparateClassesDirSupported) { if (!isSeparateClassesDirSupported) {
sourceSet.output.setClassesDirCompatible(kotlinTask.destinationDir) kotlinCompilation.output.setClassesDirCompatible(kotlinTask.destinationDir)
} }
appliedPlugins appliedPlugins
.flatMap { it.getSubpluginKotlinTasks(project, kotlinTask) } .flatMap { it.getSubpluginKotlinTasks(project, kotlinTask) }
.forEach { it.source(kotlinSourceSet.kotlin) } .forEach { task -> kotlinCompilation.kotlinSourceSets.forEach { sourceSet -> task.source(sourceSet.kotlin) } }
} }
} }
private fun createCleanSourceMapTask() { private fun createCleanSourceMapTask() {
val taskName = sourceSet.getTaskName("clean", "sourceMap") val taskName = kotlinCompilation.composeName("clean", "sourceMap")
val task = project.tasks.create(taskName, Delete::class.java) val task = project.tasks.create(taskName, Delete::class.java)
task.onlyIf { kotlinTask.kotlinOptions.sourceMap } task.onlyIf { kotlinTask.kotlinOptions.sourceMap }
task.delete(object : Closure<String>(this) { task.delete(object : Closure<String>(this) {
@@ -295,189 +305,274 @@ internal class Kotlin2JsSourceSetProcessor(
} }
internal class KotlinCommonSourceSetProcessor( internal class KotlinCommonSourceSetProcessor(
project: Project, project: Project,
javaBasePlugin: JavaBasePlugin, compilation: KotlinCompilation,
sourceSet: SourceSet, tasksProvider: KotlinTasksProvider,
tasksProvider: KotlinTasksProvider, private val kotlinPluginVersion: String
kotlinSourceSetProvider: KotlinSourceSetProvider,
private val kotlinPluginVersion: String
) : KotlinSourceSetProcessor<KotlinCompileCommon>( ) : KotlinSourceSetProcessor<KotlinCompileCommon>(
project, javaBasePlugin, sourceSet, tasksProvider, kotlinSourceSetProvider, project, tasksProvider, taskDescription = "Compiles the kotlin sources in $compilation to Metadata.",
dslExtensionName = KOTLIN_DSL_NAME, kotlinCompilation = compilation
taskDescription = "Compiles the kotlin sources in $sourceSet to Metadata.",
compileTaskNameSuffix = "kotlinCommon"
) { ) {
override fun doTargetSpecificProcessing() { 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 -> project.afterEvaluate { project ->
kotlinTask.source(kotlinSourceSet.kotlin)
val subpluginEnvironment: SubpluginEnvironment = loadSubplugins(project, kotlinPluginVersion) val subpluginEnvironment: SubpluginEnvironment = loadSubplugins(project, kotlinPluginVersion)
val appliedPlugins = subpluginEnvironment.addSubpluginOptions( val appliedPlugins = subpluginEnvironment.addSubpluginOptions(
project, kotlinTask, kotlinTask, null, null, sourceSet) project, kotlinTask, null, null, null, kotlinCompilation
)
project.tasks.findByName(sourceSet.classesTaskName)!!.dependsOn(kotlinTask)
// can be missing (e.g. in case of tests)
project.tasks.findByName(sourceSet.jarTaskName)?.dependsOn(kotlinTask)
appliedPlugins appliedPlugins
.flatMap { it.getSubpluginKotlinTasks(project, kotlinTask) } .flatMap { it.getSubpluginKotlinTasks(project, kotlinTask) }
.forEach { it.source(kotlinSourceSet.kotlin) } .forEach { kotlinCompilation.kotlinSourceSets.forEach { sourceSet -> it.source(sourceSet.kotlin) } }
} }
} }
override fun doCreateTask(project: Project, taskName: String): KotlinCompileCommon = override fun doCreateTask(project: Project, taskName: String): KotlinCompileCommon =
tasksProvider.createKotlinCommonTask(project, taskName, sourceSet.name) tasksProvider.createKotlinCommonTask(project, taskName, kotlinCompilation.compilationName)
} }
internal abstract class AbstractKotlinPlugin( internal abstract class AbstractKotlinPlugin(
val tasksProvider: KotlinTasksProvider, val tasksProvider: KotlinTasksProvider,
val kotlinSourceSetProvider: KotlinSourceSetProvider, protected val kotlinPluginVersion: String,
protected val kotlinPluginVersion: String,
val registry: ToolingModelBuilderRegistry val registry: ToolingModelBuilderRegistry
) : Plugin<Project> { ) : Plugin<Project> {
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) { 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) project.plugins.apply(JavaPlugin::class.java)
configureSourceSetDefaults(project, javaBasePlugin, javaPluginConvention) configureTarget(
configureDefaultVersionsResolutionStrategy(project) (project.kotlinExtension as KotlinSingleJavaTargetExtension).target,
configureClassInspectionForIC(project) { compilation -> buildSourceSetProcessor(project, compilation, kotlinPluginVersion) }
)
configureProjectGlobalSettings(project, kotlinPluginVersion)
registry.register(KotlinModelBuilder(kotlinPluginVersion)) registry.register(KotlinModelBuilder(kotlinPluginVersion))
} }
open protected fun configureSourceSetDefaults( companion object {
project: Project, fun configureProjectGlobalSettings(project: Project, kotlinPluginVersion: String) {
javaBasePlugin: JavaBasePlugin, configureDefaultVersionsResolutionStrategy(project, kotlinPluginVersion)
javaPluginConvention: JavaPluginConvention configureClassInspectionForIC(project)
) {
javaPluginConvention.sourceSets?.all { sourceSet ->
buildSourceSetProcessor(project, javaBasePlugin, sourceSet, kotlinPluginVersion).run()
}
} }
private fun configureDefaultVersionsResolutionStrategy(project: Project) { fun configureTarget(
project.configurations.all { configuration -> target: KotlinWithJavaTarget,
if (isGradleVersionAtLeast(4, 4)) { buildSourceSetProcessor: (KotlinCompilation) -> KotlinSourceSetProcessor<*>
// Use the API introduced in Gradle 4.4 to modify the dependencies directly before they are resolved: ) {
configuration.withDependencies { dependencySet -> setUpJavaSourceSets(target)
dependencySet.filterIsInstance<ExternalDependency>() configureSourceSetDefaults(target, buildSourceSetProcessor)
.filter { it.group == "org.jetbrains.kotlin" && it.version.isNullOrEmpty() } }
.forEach { it.version { constraint -> constraint.prefer(kotlinPluginVersion) } }
} 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 { val inspectTask = project.tasks.create("inspectClassesForKotlinIC", InspectClassesForMultiModuleIC::class.java)
configuration.resolutionStrategy.eachDependency { details -> inspectTask.sourceSetName = SourceSet.MAIN_SOURCE_SET_NAME
val requested = details.requested inspectTask.jarTask = jarTask
if (requested.group == "org.jetbrains.kotlin" && requested.version.isEmpty()) { inspectTask.dependsOn(classesTask)
details.useVersion(kotlinPluginVersion) 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<String, KotlinWithJavaCompilation>()
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) { internal fun configureDefaultVersionsResolutionStrategy(project: Project, kotlinPluginVersion: String) {
val classesTask = project.tasks.findByName(JavaPlugin.CLASSES_TASK_NAME) project.configurations.all { configuration ->
val jarTask = project.tasks.findByName(JavaPlugin.JAR_TASK_NAME) if (isGradleVersionAtLeast(4, 4)) {
// Use the API introduced in Gradle 4.4 to modify the dependencies directly before they are resolved:
if (classesTask == null || jarTask !is Jar) { configuration.withDependencies { dependencySet ->
project.logger.info( dependencySet.filterIsInstance<ExternalDependency>()
"Could not configure class inspection task " + .filter { it.group == "org.jetbrains.kotlin" && it.version.isNullOrEmpty() }
"(classes task = ${classesTask?.javaClass?.canonicalName}, " + .forEach { it.version { constraint -> constraint.prefer(kotlinPluginVersion) } }
"jar task = ${classesTask?.javaClass?.canonicalName}" }
) } else {
return 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( internal open class KotlinPlugin(
tasksProvider: KotlinTasksProvider, tasksProvider: KotlinTasksProvider,
kotlinSourceSetProvider: KotlinSourceSetProvider, kotlinPluginVersion: String,
kotlinPluginVersion: String,
registry: ToolingModelBuilderRegistry registry: ToolingModelBuilderRegistry
) : AbstractKotlinPlugin(tasksProvider, kotlinSourceSetProvider, kotlinPluginVersion, registry) { ) : AbstractKotlinPlugin(tasksProvider, kotlinPluginVersion, registry) {
override fun buildSourceSetProcessor(project: Project, javaBasePlugin: JavaBasePlugin, sourceSet: SourceSet, kotlinPluginVersion: String) =
Kotlin2JvmSourceSetProcessor(project, javaBasePlugin, sourceSet, tasksProvider, kotlinSourceSetProvider, kotlinPluginVersion) override fun buildSourceSetProcessor(project: Project, compilation: KotlinCompilation, kotlinPluginVersion: String) =
Kotlin2JvmSourceSetProcessor(project, tasksProvider, compilation, kotlinPluginVersion)
override fun apply(project: Project) { 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) project.pluginManager.apply(ScriptingGradleSubplugin::class.java)
super.apply(project) super.apply(project)
} }
} }
internal open class KotlinCommonPlugin( internal open class KotlinCommonPlugin(
tasksProvider: KotlinTasksProvider, tasksProvider: KotlinTasksProvider,
kotlinSourceSetProvider: KotlinSourceSetProvider, kotlinPluginVersion: String,
kotlinPluginVersion: String,
registry: ToolingModelBuilderRegistry registry: ToolingModelBuilderRegistry
) : AbstractKotlinPlugin(tasksProvider, kotlinSourceSetProvider, kotlinPluginVersion, registry) { ) : AbstractKotlinPlugin(tasksProvider, kotlinPluginVersion, registry) {
override fun buildSourceSetProcessor(project: Project, javaBasePlugin: JavaBasePlugin, sourceSet: SourceSet, kotlinPluginVersion: String) =
KotlinCommonSourceSetProcessor(project, javaBasePlugin, sourceSet, tasksProvider, kotlinSourceSetProvider, kotlinPluginVersion)
}
internal open class Kotlin2JsPlugin( override fun buildSourceSetProcessor(
tasksProvider: KotlinTasksProvider, project: Project,
kotlinSourceSetProvider: KotlinSourceSetProvider, compilation: KotlinCompilation,
kotlinPluginVersion: String, kotlinPluginVersion: String
registry: ToolingModelBuilderRegistry ): KotlinSourceSetProcessor<*> =
) : AbstractKotlinPlugin(tasksProvider, kotlinSourceSetProvider, kotlinPluginVersion, registry) { KotlinCommonSourceSetProcessor(project, compilation, tasksProvider, kotlinPluginVersion)
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<Project> {
override fun apply(project: Project) { override fun apply(project: Project) {
val version = loadAndroidPluginVersion() val target = KotlinWithJavaTarget(project, KotlinPlatformType.common, "common")
if (version != null) { (project.kotlinExtension as KotlinSingleJavaTargetExtension).target = target
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( super.apply(project)
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)
} }
} }
class KotlinConfigurationTools internal constructor(val kotlinSourceSetProvider: KotlinSourceSetProvider, internal open class Kotlin2JsPlugin(
val kotlinTasksProvider: KotlinTasksProvider, tasksProvider: KotlinTasksProvider,
val kotlinPluginVersion: String) 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<Project> {
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. /** 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 * @see [LegacyAndroidAndroidProjectHandler] that is implemented with the old internal API and [AndroidGradle25VariantProcessor] that works
@@ -497,18 +592,22 @@ abstract class AbstractAndroidProjectHandler<V>(private val kotlinConfigurationT
protected open fun checkVariantIsValid(variant: V) = Unit protected open fun checkVariantIsValid(variant: V) = Unit
protected abstract fun wireKotlinTasks(project: Project, protected open fun setUpDependencyResolution(variant: V, compilation: KotlinJvmAndroidCompilation) = Unit
androidPlugin: BasePlugin,
androidExt: BaseExtension, protected abstract fun wireKotlinTasks(
variantData: V, project: Project,
javaTask: AbstractCompile, compilation: KotlinJvmAndroidCompilation,
kotlinTask: KotlinCompile) androidPlugin: BasePlugin,
androidExt: BaseExtension,
variantData: V,
javaTask: AbstractCompile,
kotlinTask: KotlinCompile
)
protected abstract fun wrapVariantDataForKapt(variantData: V): KaptVariantData<V> protected abstract fun wrapVariantDataForKapt(variantData: V): KaptVariantData<V>
fun handleProject(project: Project) { fun handleProject(project: Project, kotlinAndroidTarget: KotlinAndroidTarget) {
val ext = project.extensions.getByName("android") as BaseExtension val ext = project.extensions.getByName("android") as BaseExtension
val aptConfigurations = hashMapOf<String, Configuration>()
ext.sourceSets.all { sourceSet -> ext.sourceSets.all { sourceSet ->
logger.kotlinDebug("Creating KotlinBaseSourceSet for source set $sourceSet") logger.kotlinDebug("Creating KotlinBaseSourceSet for source set $sourceSet")
@@ -527,42 +626,49 @@ abstract class AbstractAndroidProjectHandler<V>(private val kotlinConfigurationT
ext.addExtension(KOTLIN_OPTIONS_DSL_NAME, kotlinOptions) ext.addExtension(KOTLIN_OPTIONS_DSL_NAME, kotlinOptions)
project.afterEvaluate { project -> project.afterEvaluate { project ->
if (project != null) { val androidPluginIds = listOf("android", "com.android.application", "android-library", "com.android.library",
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")
"com.android.test", "com.android.feature", "com.android.dynamic-feature", "com.android.instantapp") val plugin = androidPluginIds.asSequence()
val plugin = androidPluginIds.asSequence() .mapNotNull { project.plugins.findPlugin(it) as? BasePlugin }
.mapNotNull { project.plugins.findPlugin(it) as? BasePlugin } .firstOrNull()
.firstOrNull() ?: throw InvalidPluginException("'kotlin-android' expects one of the Android Gradle " +
?: throw InvalidPluginException("'kotlin-android' expects one of the Android Gradle " + "plugins to be applied to the project:\n\t" +
"plugins to be applied to the project:\n\t" + androidPluginIds.joinToString("\n\t") { "* $it" })
androidPluginIds.joinToString("\n\t") { "* $it" })
val subpluginEnvironment = loadSubplugins(project, kotlinConfigurationTools.kotlinPluginVersion) val subpluginEnvironment = loadSubplugins(project, kotlinConfigurationTools.kotlinPluginVersion)
checkAndroidAnnotationProcessorDependencyUsage(project) checkAndroidAnnotationProcessorDependencyUsage(project)
forEachVariant(project) { forEachVariant(project) {
processVariant(it, project, ext, plugin, aptConfigurations, kotlinOptions, processVariant(
kotlinConfigurationTools.kotlinTasksProvider, subpluginEnvironment) it, kotlinAndroidTarget, project, ext, plugin, kotlinOptions, kotlinConfigurationTools.kotlinTasksProvider,
} subpluginEnvironment
)
} }
} }
} }
private fun processVariant(variantData: V, private fun processVariant(
project: Project, variantData: V,
androidExt: BaseExtension, target: KotlinAndroidTarget,
androidPlugin: BasePlugin, project: Project,
aptConfigurations: Map<String, Configuration>, androidExt: BaseExtension,
rootKotlinOptions: KotlinJvmOptionsImpl, androidPlugin: BasePlugin,
tasksProvider: KotlinTasksProvider, rootKotlinOptions: KotlinJvmOptionsImpl,
subpluginEnvironment: SubpluginEnvironment) { tasksProvider: KotlinTasksProvider,
subpluginEnvironment: SubpluginEnvironment
) {
checkVariantIsValid(variantData) checkVariantIsValid(variantData)
val variantDataName = getVariantName(variantData) val variantDataName = getVariantName(variantData)
logger.kotlinDebug("Process variant [$variantDataName]") 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) val javaTask = getJavaTask(variantData)
if (javaTask == null) { if (javaTask == null) {
@@ -570,7 +676,7 @@ abstract class AbstractAndroidProjectHandler<V>(private val kotlinConfigurationT
return return
} }
val kotlinTaskName = "compile${variantDataName.capitalize()}Kotlin" val kotlinTaskName = compilation.compileKotlinTaskName
// todo: Investigate possibility of creating and configuring kotlinTask before evaluation // todo: Investigate possibility of creating and configuring kotlinTask before evaluation
val kotlinTask = tasksProvider.createKotlinJVMTask(project, kotlinTaskName, variantDataName) val kotlinTask = tasksProvider.createKotlinJVMTask(project, kotlinTaskName, variantDataName)
kotlinTask.parentKotlinOptionsImpl = rootKotlinOptions kotlinTask.parentKotlinOptionsImpl = rootKotlinOptions
@@ -579,22 +685,35 @@ abstract class AbstractAndroidProjectHandler<V>(private val kotlinConfigurationT
kotlinTask.destinationDir = File(project.buildDir, "tmp/kotlin-classes/$variantDataName") kotlinTask.destinationDir = File(project.buildDir, "tmp/kotlin-classes/$variantDataName")
kotlinTask.description = "Compiles the $variantDataName kotlin." kotlinTask.description = "Compiles the $variantDataName kotlin."
configureSources(kotlinTask, variantData) configureSources(kotlinTask, variantData, compilation)
wireKotlinTasks(project, androidPlugin, androidExt, variantData, javaTask, kotlinTask)
// 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( val appliedPlugins = subpluginEnvironment.addSubpluginOptions(
project, kotlinTask, javaTask, wrapVariantDataForKapt(variantData), this, null) project, kotlinTask, javaTask, wrapVariantDataForKapt(variantData), this, null)
appliedPlugins.flatMap { it.getSubpluginKotlinTasks(project, kotlinTask) } 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 val logger = compileTask.project.logger
for (provider in getSourceProviders(variantData)) { for (provider in getSourceProviders(variantData)) {
val kotlinSourceSet = provider.getConvention(KOTLIN_DSL_NAME) as? KotlinSourceSet ?: continue 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)) { for (javaSrcDir in getAllJavaSources(variantData)) {
@@ -696,10 +815,10 @@ internal class SubpluginEnvironment(
fun <C: CommonCompilerArguments> addSubpluginOptions( fun <C: CommonCompilerArguments> addSubpluginOptions(
project: Project, project: Project,
kotlinTask: AbstractKotlinCompile<C>, kotlinTask: AbstractKotlinCompile<C>,
javaTask: AbstractCompile, javaTask: AbstractCompile?,
variantData: Any?, variantData: Any?,
androidProjectHandler: AbstractAndroidProjectHandler<out Any?>?, androidProjectHandler: AbstractAndroidProjectHandler<out Any?>?,
javaSourceSet: SourceSet? kotlinCompilation: KotlinCompilation?
): List<KotlinGradleSubplugin<AbstractKotlinCompile<C>>> { ): List<KotlinGradleSubplugin<AbstractKotlinCompile<C>>> {
val pluginOptions = kotlinTask.pluginOptions val pluginOptions = kotlinTask.pluginOptions
@@ -716,7 +835,7 @@ internal class SubpluginEnvironment(
project.logger.kotlinDebug { "Adding '$mavenCoordinate' to '$PLUGIN_CLASSPATH_CONFIGURATION_NAME' configuration" } project.logger.kotlinDebug { "Adding '$mavenCoordinate' to '$PLUGIN_CLASSPATH_CONFIGURATION_NAME' configuration" }
project.dependencies.add(PLUGIN_CLASSPATH_CONFIGURATION_NAME, mavenCoordinate) 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() val subpluginId = subplugin.getCompilerPluginId()
kotlinTask.registerSubpluginOptionsAsInputs(subpluginId, subpluginOptions) kotlinTask.registerSubpluginOptionsAsInputs(subpluginId, subpluginOptions)
@@ -21,11 +21,14 @@ import org.gradle.api.Project
import org.gradle.api.internal.file.FileResolver import org.gradle.api.internal.file.FileResolver
import org.gradle.api.logging.Logger import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging 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.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin
import org.jetbrains.kotlin.gradle.dsl.createKotlinExtension import org.jetbrains.kotlin.gradle.plugin.source.KotlinSourceSet
import org.jetbrains.kotlin.gradle.internal.KotlinSourceSetProviderImpl 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.gradle.tasks.*
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import java.io.FileNotFoundException import java.io.FileNotFoundException
@@ -33,7 +36,9 @@ import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.reflect.KClass import kotlin.reflect.KClass
abstract class KotlinBasePluginWrapper(protected val fileResolver: FileResolver): Plugin<Project> { abstract class KotlinBasePluginWrapper(
protected val fileResolver: FileResolver
): Plugin<Project> {
private val log = Logging.getLogger(this.javaClass) private val log = Logging.getLogger(this.javaClass)
val kotlinPluginVersion = loadKotlinVersionFromResource(log) val kotlinPluginVersion = loadKotlinVersionFromResource(log)
@@ -66,32 +71,54 @@ abstract class KotlinBasePluginWrapper(protected val fileResolver: FileResolver)
plugin.apply(project) plugin.apply(project)
} }
internal abstract fun getPlugin(kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin<Project> internal abstract fun getPlugin(
project: Project,
open val projectExtensionClass: KClass<out KotlinProjectExtension> get() = KotlinProjectExtension::class kotlinGradleBuildServices: KotlinGradleBuildServices
): Plugin<Project>
} }
open class KotlinPluginWrapper @Inject internal constructor(fileResolver: FileResolver, protected val registry: ToolingModelBuilderRegistry): KotlinBasePluginWrapper(fileResolver) { open class KotlinPluginWrapper @Inject constructor(
override fun getPlugin(kotlinGradleBuildServices: KotlinGradleBuildServices) = fileResolver: FileResolver,
KotlinPlugin(KotlinTasksProvider(), KotlinSourceSetProviderImpl(fileResolver), kotlinPluginVersion, registry) protected val registry: ToolingModelBuilderRegistry
): KotlinBasePluginWrapper(fileResolver) {
override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin<Project> =
KotlinPlugin(KotlinTasksProvider(), kotlinPluginVersion, registry)
override val projectExtensionClass: KClass<out KotlinJvmProjectExtension> override val projectExtensionClass: KClass<out KotlinJvmProjectExtension>
get() = KotlinJvmProjectExtension::class get() = KotlinJvmProjectExtension::class
} }
open class KotlinCommonPluginWrapper @Inject internal constructor(fileResolver: FileResolver, protected val registry: ToolingModelBuilderRegistry): KotlinBasePluginWrapper(fileResolver) { open class KotlinCommonPluginWrapper @Inject constructor(
override fun getPlugin(kotlinGradleBuildServices: KotlinGradleBuildServices) = fileResolver: FileResolver,
KotlinCommonPlugin(KotlinCommonTasksProvider(), KotlinSourceSetProviderImpl(fileResolver), kotlinPluginVersion, registry) protected val registry: ToolingModelBuilderRegistry
): KotlinBasePluginWrapper(fileResolver) {
override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin<Project> =
KotlinCommonPlugin(KotlinCommonTasksProvider(), kotlinPluginVersion, registry)
override val projectExtensionClass: KClass<out KotlinSingleJavaTargetExtension>
get() = KotlinSingleJavaTargetExtension::class
} }
open class KotlinAndroidPluginWrapper @Inject internal constructor(fileResolver: FileResolver, protected val registry: ToolingModelBuilderRegistry): KotlinBasePluginWrapper(fileResolver) { open class KotlinAndroidPluginWrapper @Inject constructor(
override fun getPlugin(kotlinGradleBuildServices: KotlinGradleBuildServices) = fileResolver: FileResolver,
KotlinAndroidPlugin(AndroidTasksProvider(), KotlinSourceSetProviderImpl(fileResolver), kotlinPluginVersion) protected val registry: ToolingModelBuilderRegistry
): KotlinBasePluginWrapper(fileResolver) {
override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin<Project> =
KotlinAndroidPlugin(
AndroidTasksProvider(),
kotlinPluginVersion
)
} }
open class Kotlin2JsPluginWrapper @Inject internal constructor(fileResolver: FileResolver, protected val registry: ToolingModelBuilderRegistry): KotlinBasePluginWrapper(fileResolver) { open class Kotlin2JsPluginWrapper @Inject constructor(
override fun getPlugin(kotlinGradleBuildServices: KotlinGradleBuildServices) = fileResolver: FileResolver,
Kotlin2JsPlugin(Kotlin2JsTasksProvider(), KotlinSourceSetProviderImpl(fileResolver), kotlinPluginVersion, registry) protected val registry: ToolingModelBuilderRegistry
): KotlinBasePluginWrapper(fileResolver) {
override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin<Project> =
Kotlin2JsPlugin(Kotlin2JsTasksProvider(), kotlinPluginVersion, registry)
override val projectExtensionClass: KClass<out KotlinSingleJavaTargetExtension>
get() = KotlinSingleJavaTargetExtension::class
} }
fun Project.getKotlinPluginVersion(): String? = fun Project.getKotlinPluginVersion(): String? =
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.gradle.internal.KaptTask
import org.jetbrains.kotlin.gradle.internal.KaptVariantData import org.jetbrains.kotlin.gradle.internal.KaptVariantData
import org.jetbrains.kotlin.gradle.internal.registerGeneratedJavaSource import org.jetbrains.kotlin.gradle.internal.registerGeneratedJavaSource
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.utils.checkedReflection import org.jetbrains.kotlin.gradle.utils.checkedReflection
import java.io.File import java.io.File
@@ -40,12 +41,14 @@ internal class LegacyAndroidAndroidProjectHandler(kotlinConfigurationTools: Kotl
variantManager.variantDataList.forEach(action) variantManager.variantDataList.forEach(action)
} }
override fun wireKotlinTasks(project: Project, override fun wireKotlinTasks(
androidPlugin: BasePlugin, project: Project,
androidExt: BaseExtension, compilation: KotlinJvmAndroidCompilation,
variantData: BaseVariantData<out BaseVariantOutputData>, androidPlugin: BasePlugin,
javaTask: AbstractCompile, androidExt: BaseExtension,
kotlinTask: KotlinCompile variantData: BaseVariantData<out BaseVariantOutputData>,
javaTask: AbstractCompile,
kotlinTask: KotlinCompile
) { ) {
kotlinTask.dependsOn(*javaTask.dependsOn.toTypedArray()) kotlinTask.dependsOn(*javaTask.dependsOn.toTypedArray())
@@ -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<Attribute<*>, Any>())
override fun contains(key: Attribute<*>): Boolean =
attributesMap.contains(key) || parent?.contains(key) ?: false
@Suppress("UNCHECKED_CAST")
override fun <T : Any?> getAttribute(key: Attribute<T>?): T? =
attributesMap.get(key as Attribute<*>) as T? ?: parent?.getAttribute(key)
override fun isEmpty(): Boolean = attributesMap.isEmpty() && parent?.isEmpty ?: false
override fun keySet(): Set<Attribute<*>> = attributesMap.keys + parent?.keySet().orEmpty()
override fun <T : Any?> attribute(key: Attribute<T>?, 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
}
@@ -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<T: KotlinCompilation> : NamedDomainObjectFactory<T> {
val itemClass: Class<T>
}
private fun KotlinTarget.createCompilationOutput(name: String) =
KotlinCompilationOutput(project, project.buildDir.resolve("processedResources/$name"))
class KotlinCommonCompilationFactory(
val target: KotlinOnlyTarget<KotlinCommonCompilation>
) : KotlinCompilationFactory<KotlinCommonCompilation> {
override val itemClass: Class<KotlinCommonCompilation>
get() = KotlinCommonCompilation::class.java
override fun create(name: String): KotlinCommonCompilation =
KotlinCommonCompilation(target, name, target.createCompilationOutput(name))
}
class KotlinJvmCompilationFactory(
val target: KotlinOnlyTarget<KotlinJvmCompilation>
) : KotlinCompilationFactory<KotlinJvmCompilation> {
override val itemClass: Class<KotlinJvmCompilation>
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<KotlinWithJavaCompilation> {
override val itemClass: Class<KotlinWithJavaCompilation>
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<KotlinJvmAndroidCompilation> {
override val itemClass: Class<KotlinJvmAndroidCompilation>
get() = KotlinJvmAndroidCompilation::class.java
override fun create(name: String): KotlinJvmAndroidCompilation =
KotlinJvmAndroidCompilation(target, name, target.createCompilationOutput(name))
}
class KotlinJsCompilationFactory(
val project: Project,
val target: KotlinOnlyTarget<KotlinJsCompilation>
) : KotlinCompilationFactory<KotlinJsCompilation> {
override val itemClass: Class<KotlinJsCompilation>
get() = KotlinJsCompilation::class.java
override fun create(name: String): KotlinJsCompilation =
KotlinJsCompilation(target, name, target.createCompilationOutput(name))
}
@@ -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<String, Any>, 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)
}
@@ -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<KotlinSourceSet> = 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<Any?>) =
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)
@@ -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<UsageContext> = 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<out KotlinJvmAndroidCompilation> =
project.container(compilationFactory.itemClass, compilationFactory)
override fun createUsageContexts(): Set<UsageContext> {
//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<KotlinWithJavaCompilation> =
project.container(KotlinWithJavaCompilation::class.java,
KotlinWithJavaCompilationFactory(project, this)
)
}
open class KotlinOnlyTarget<T : KotlinCompilation>(
project: Project,
override val platformType: KotlinPlatformType
) : AbstractKotlinTarget(project) {
override lateinit var compilations: NamedDomainObjectContainer<T>
internal set
override lateinit var targetName: String
internal set
override var disambiguationClassifier: String? = null
internal set
}
@@ -7,12 +7,8 @@ package org.jetbrains.kotlin.gradle.scripting.internal
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.AbstractCompile
import org.jetbrains.kotlin.gradle.plugin.JetBrainsSubpluginArtifact import org.jetbrains.kotlin.gradle.plugin.*
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.scripting.ScriptingExtension import org.jetbrains.kotlin.gradle.scripting.ScriptingExtension
class ScriptingGradleSubplugin : Plugin<Project> { class ScriptingGradleSubplugin : Plugin<Project> {
@@ -39,10 +35,10 @@ class ScriptingKotlinGradleSubplugin : KotlinGradleSubplugin<AbstractCompile> {
override fun apply( override fun apply(
project: Project, project: Project,
kotlinCompile: AbstractCompile, kotlinCompile: AbstractCompile,
javaCompile: AbstractCompile, javaCompile: AbstractCompile?,
variantData: Any?, variantData: Any?,
androidProjectHandler: Any?, androidProjectHandler: Any?,
javaSourceSet: SourceSet? kotlinCompilation: KotlinCompilation?
): List<SubpluginOption> { ): List<SubpluginOption> {
if (!ScriptingGradleSubplugin.isEnabled(project)) return emptyList() if (!ScriptingGradleSubplugin.isEnabled(project)) return emptyList()
@@ -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))
}
}
@@ -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
)
}
@@ -18,16 +18,9 @@ package org.jetbrains.kotlin.noarg.gradle
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project 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.api.tasks.compile.AbstractCompile
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.gradle.plugin.JetBrainsSubpluginArtifact import org.jetbrains.kotlin.gradle.plugin.*
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.noarg.gradle.model.builder.NoArgModelBuilder import org.jetbrains.kotlin.noarg.gradle.model.builder.NoArgModelBuilder
import javax.inject.Inject import javax.inject.Inject
@@ -58,12 +51,12 @@ class NoArgKotlinGradleSubplugin : KotlinGradleSubplugin<AbstractCompile> {
override fun isApplicable(project: Project, task: AbstractCompile) = NoArgGradleSubplugin.isEnabled(project) override fun isApplicable(project: Project, task: AbstractCompile) = NoArgGradleSubplugin.isEnabled(project)
override fun apply( override fun apply(
project: Project, project: Project,
kotlinCompile: AbstractCompile, kotlinCompile: AbstractCompile,
javaCompile: AbstractCompile, javaCompile: AbstractCompile?,
variantData: Any?, variantData: Any?,
androidProjectHandler: Any?, androidProjectHandler: Any?,
javaSourceSet: SourceSet? kotlinCompilation: KotlinCompilation?
): List<SubpluginOption> { ): List<SubpluginOption> {
if (!NoArgGradleSubplugin.isEnabled(project)) return emptyList() if (!NoArgGradleSubplugin.isEnabled(project)) return emptyList()
@@ -18,16 +18,9 @@ package org.jetbrains.kotlin.samWithReceiver.gradle
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project 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.api.tasks.compile.AbstractCompile
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.gradle.plugin.JetBrainsSubpluginArtifact import org.jetbrains.kotlin.gradle.plugin.*
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.noarg.gradle.model.builder.SamWithReceiverModelBuilder import org.jetbrains.kotlin.noarg.gradle.model.builder.SamWithReceiverModelBuilder
import javax.inject.Inject import javax.inject.Inject
@@ -53,12 +46,12 @@ class SamWithReceiverKotlinGradleSubplugin : KotlinGradleSubplugin<AbstractCompi
override fun isApplicable(project: Project, task: AbstractCompile) = SamWithReceiverGradleSubplugin.isEnabled(project) override fun isApplicable(project: Project, task: AbstractCompile) = SamWithReceiverGradleSubplugin.isEnabled(project)
override fun apply( override fun apply(
project: Project, project: Project,
kotlinCompile: AbstractCompile, kotlinCompile: AbstractCompile,
javaCompile: AbstractCompile, javaCompile: AbstractCompile?,
variantData: Any?, variantData: Any?,
androidProjectHandler: Any?, androidProjectHandler: Any?,
javaSourceSet: SourceSet? kotlinCompilation: KotlinCompilation?
): List<SubpluginOption> { ): List<SubpluginOption> {
if (!SamWithReceiverGradleSubplugin.isEnabled(project)) return emptyList() if (!SamWithReceiverGradleSubplugin.isEnabled(project)) return emptyList()