Gradle plugin prototype that uses the project model 2.0

This commit is contained in:
Sergey Igushkin
2021-02-02 12:31:16 +03:00
parent d66f95b80e
commit 70b88ada93
45 changed files with 1205 additions and 176 deletions
@@ -226,6 +226,11 @@ pluginBundle {
id = "org.jetbrains.kotlin.native.cocoapods",
display = "Kotlin Native plugin for CocoaPods integration"
)
create(
name = "kotlinMultiplatformPluginPm20",
id = "org.jetbrains.kotlin.multiplatform.pm20",
display = "Kotlin Multiplatform plugin with PM2.0"
)
}
publishPluginMarkers()
@@ -19,15 +19,15 @@ import org.jetbrains.kotlin.daemon.common.CompilerId
import org.jetbrains.kotlin.gradle.dsl.kotlinExtensionOrNull
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
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.plugin.internal.state.TaskLoggers
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.isMain
import org.jetbrains.kotlin.gradle.plugin.mpp.ownModuleName
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.tasks.GradleCompileTaskProvider
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileTaskData
import org.jetbrains.kotlin.gradle.tasks.locateTask
import org.jetbrains.kotlin.gradle.utils.archivePathCompatible
import org.jetbrains.kotlin.gradle.utils.newTmpFile
import org.jetbrains.kotlin.gradle.utils.relativeOrCanonical
@@ -216,7 +216,7 @@ internal open class GradleCompilerRunner(protected val taskProvider: GradleCompi
KotlinCompileTaskData.getTaskDataContainer(project).forEach { taskData ->
val compilation = taskData.compilation
val target = taskData.compilation.target
val target = taskData.compilation.owner
val module = IncrementalModuleEntry(
project.path,
compilation.ownModuleName,
@@ -229,12 +229,12 @@ internal open class GradleCompilerRunner(protected val taskProvider: GradleCompi
nameToModules.getOrPut(module.name) { HashSet() }.add(module)
if (compilation.platformType == KotlinPlatformType.js) {
jarForSourceSet(project, compilation.name)?.let {
jarForSourceSet(project, compilation.compilationPurpose)?.let {
jarToModule[it] = module
}
}
if (compilation.isMain()) {
if (compilation is KotlinCompilation<*> && target is KotlinTarget && compilation.isMain()) { // FIXME support PM20
if (isMultiplatformProject) {
try {
//It could cause task reconfiguration. TODO: fix it some day if need
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsSingleTargetPreset
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20ProjectExtension
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.targets.js.calculateJsCompilerType
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl
@@ -25,12 +26,15 @@ import kotlin.reflect.KClass
private const val KOTLIN_PROJECT_EXTENSION_NAME = "kotlin"
internal fun Project.createKotlinExtension(extensionClass: KClass<out KotlinProjectExtension>): KotlinProjectExtension {
internal fun Project.createKotlinExtension(extensionClass: KClass<out KotlinTopLevelExtension>): KotlinTopLevelExtension {
val kotlinExt = extensions.create(KOTLIN_PROJECT_EXTENSION_NAME, extensionClass.java, this)
DslObject(kotlinExt).extensions.create("experimental", ExperimentalExtension::class.java)
return kotlinExtension
return topLevelExtension
}
internal val Project.topLevelExtension: KotlinTopLevelExtension
get() = extensions.getByName(KOTLIN_PROJECT_EXTENSION_NAME) as KotlinTopLevelExtension
internal val Project.kotlinExtensionOrNull: KotlinProjectExtension?
get() = extensions.findByName(KOTLIN_PROJECT_EXTENSION_NAME) as? KotlinProjectExtension
@@ -43,7 +47,11 @@ internal val Project.multiplatformExtensionOrNull: KotlinMultiplatformExtension?
internal val Project.multiplatformExtension: KotlinMultiplatformExtension
get() = extensions.getByName(KOTLIN_PROJECT_EXTENSION_NAME) as KotlinMultiplatformExtension
open class KotlinProjectExtension(internal val project: Project) : KotlinSourceSetContainer {
internal val Project.pm20Extension: KotlinPm20ProjectExtension
get() = extensions.getByName(KOTLIN_PROJECT_EXTENSION_NAME) as KotlinPm20ProjectExtension
open class KotlinTopLevelExtension (internal val project: Project) {
val experimental: ExperimentalExtension
get() = DslObject(this).extensions.getByType(ExperimentalExtension::class.java)
@@ -58,7 +66,9 @@ open class KotlinProjectExtension(internal val project: Project) : KotlinSourceS
fun explicitApiWarning() {
explicitApi = ExplicitApiMode.Warning
}
}
open class KotlinProjectExtension(project: Project) : KotlinTopLevelExtension(project), KotlinSourceSetContainer {
override var sourceSets: NamedDomainObjectContainer<KotlinSourceSet>
@Suppress("UNCHECKED_CAST")
get() = DslObject(this).extensions.getByName("sourceSets") as NamedDomainObjectContainer<KotlinSourceSet>
@@ -20,14 +20,15 @@ import org.gradle.api.tasks.testing.Test
import org.gradle.api.tasks.testing.junit.JUnitOptions
import org.gradle.api.tasks.testing.junitplatform.JUnitPlatformOptions
import org.gradle.api.tasks.testing.testng.TestNGOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.execution.KotlinAggregateExecutionSource
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleFragment
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleModule
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20ProjectExtension
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
import org.jetbrains.kotlin.gradle.plugin.sources.withAllDependsOnSourceSets
import org.jetbrains.kotlin.gradle.plugin.sources.resolveAllDependsOnSourceSets
@@ -41,7 +42,9 @@ import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
internal fun customizeKotlinDependencies(project: Project) {
configureStdlibDefaultDependency(project)
configureKotlinTestDependency(project)
if (project.topLevelExtension is KotlinProjectExtension) { // TODO: extend this logic to PM20
configureKotlinTestDependency(project)
}
configureDefaultVersionsResolutionStrategy(project)
}
@@ -49,7 +52,7 @@ private fun configureDefaultVersionsResolutionStrategy(project: Project) {
project.configurations.all { configuration ->
// Use the API introduced in Gradle 4.4 to modify the dependencies directly before they are resolved:
configuration.withDependencies { dependencySet ->
val coreLibrariesVersion = project.kotlinExtension.coreLibrariesVersion
val coreLibrariesVersion = project.topLevelExtension.coreLibrariesVersion
dependencySet.filterIsInstance<ExternalDependency>()
.filter { it.group == KOTLIN_MODULE_GROUP && it.version.isNullOrEmpty() }
.forEach { it.version { constraint -> constraint.require(coreLibrariesVersion) } }
@@ -64,20 +67,58 @@ internal fun configureStdlibDefaultDependency(project: Project) = with(project)
val scopesToHandleConfigurations = listOf(KotlinDependencyScope.API_SCOPE, KotlinDependencyScope.IMPLEMENTATION_SCOPE)
project.kotlinExtension.sourceSets.all { kotlinSourceSet ->
scopesToHandleConfigurations.forEach { scope ->
val scopeConfiguration = project.sourceSetDependencyConfigurationByScope(kotlinSourceSet, scope)
when (val topLevelExtension = project.topLevelExtension) {
is KotlinPm20ProjectExtension -> {
addStdlibToPm20Project(topLevelExtension)
}
is KotlinProjectExtension -> {
topLevelExtension.sourceSets.all { kotlinSourceSet ->
scopesToHandleConfigurations.forEach { scope ->
val scopeConfiguration = project.sourceSetDependencyConfigurationByScope(kotlinSourceSet, scope)
project.tryWithDependenciesIfUnresolved(scopeConfiguration) { dependencies ->
val scopeToAddStdlibDependency =
if (isRelatedToAndroidTestSourceSet(project, kotlinSourceSet)) // AGP deprecates API configurations in test source sets
KotlinDependencyScope.IMPLEMENTATION_SCOPE
else KotlinDependencyScope.API_SCOPE
project.tryWithDependenciesIfUnresolved(scopeConfiguration) { dependencies ->
val scopeToAddStdlibDependency =
if (isRelatedToAndroidTestSourceSet(
project,
kotlinSourceSet
)
) // AGP deprecates API configurations in test source sets
KotlinDependencyScope.IMPLEMENTATION_SCOPE
else KotlinDependencyScope.API_SCOPE
if (scope != scopeToAddStdlibDependency)
return@tryWithDependenciesIfUnresolved
if (scope != scopeToAddStdlibDependency)
return@tryWithDependenciesIfUnresolved
chooseAndAddStdlibDependency(project, kotlinSourceSet, dependencies)
chooseAndAddStdlibDependency(project, kotlinSourceSet, dependencies)
}
}
}
}
}
}
private fun addStdlibToPm20Project(
topLevelExtension: KotlinPm20ProjectExtension
) {
val project = topLevelExtension.project
topLevelExtension.modules.matching { it.name == KotlinGradleModule.MAIN_MODULE_NAME }.configureEach { main ->
main.fragments.matching { it.name == KotlinGradleFragment.COMMON_FRAGMENT_NAME }.configureEach { common ->
common.dependencies {
api(project.kotlinDependency("kotlin-stdlib-common", project.topLevelExtension.coreLibrariesVersion))
}
}
main.variants.configureEach { variant ->
val dependency = when (variant.platformType) {
KotlinPlatformType.common -> error("variants are not expected to be common")
KotlinPlatformType.jvm -> "kotlin-stdlib" // TODO get JDK from JVM variants
KotlinPlatformType.js -> "kotlin-stdlib-js"
KotlinPlatformType.androidJvm -> null // TODO: expect support on the AGP side?
KotlinPlatformType.native -> null
}
if (dependency != null) {
variant.dependencies {
api(project.kotlinDependency(dependency, project.topLevelExtension.coreLibrariesVersion))
}
}
}
}
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureTransformA
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureTransformLegacyAction
import org.jetbrains.kotlin.gradle.model.builder.KaptModelBuilder
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileTaskData
@@ -237,7 +238,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
val javaCompile: TaskProvider<out AbstractCompile>?,
val variantData: Any?,
val sourceSetName: String,
val kotlinCompilation: KotlinCompilation<*>,
val kotlinCompilation: AbstractKotlinCompilation<*>,
val kaptExtension: KaptExtension,
val kaptClasspathConfigurations: List<Configuration>
) {
@@ -288,7 +289,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
val context = Kapt3SubpluginContext(
project, javaCompileOrNull,
androidVariantData, sourceSetName, kotlinCompilation, kaptExtension, nonEmptyKaptConfigurations
androidVariantData, sourceSetName, kotlinCompilation as AbstractKotlinCompilation<*>/*TODO?*/, kaptExtension, nonEmptyKaptConfigurations
)
val kaptGenerateStubsTaskProvider: TaskProvider<KaptGenerateStubsTask> = context.createKaptGenerateStubsTask()
@@ -18,9 +18,7 @@ import org.jetbrains.kotlin.gradle.model.impl.CompilerArgumentsImpl
import org.jetbrains.kotlin.gradle.model.impl.ExperimentalFeaturesImpl
import org.jetbrains.kotlin.gradle.model.impl.KotlinProjectImpl
import org.jetbrains.kotlin.gradle.model.impl.SourceSetImpl
import org.jetbrains.kotlin.gradle.plugin.KOTLIN_DSL_NAME
import org.jetbrains.kotlin.gradle.plugin.KOTLIN_JS_DSL_NAME
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.getConvention
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.associateWithTransitiveClosure
@@ -129,7 +127,7 @@ class KotlinModelBuilder(private val kotlinPluginVersion: String, private val an
private fun AbstractKotlinCompile<*>.findFriendSourceSets(): Collection<String> {
val friendSourceSets = ArrayList<String>()
taskData.compilation.associateWithTransitiveClosure.forEach { associateCompilation ->
(taskData.compilation as? KotlinCompilation<*>)?.associateWithTransitiveClosure?.forEach { associateCompilation ->
friendSourceSets.add(associateCompilation.name)
}
return friendSourceSets
@@ -15,7 +15,6 @@ import org.gradle.api.artifacts.maven.MavenResolver
import org.gradle.api.attributes.Usage
import org.gradle.api.file.ConfigurableFileTree
import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.logging.Logging
import org.gradle.api.plugins.InvalidPluginException
import org.gradle.api.plugins.JavaPlugin
@@ -36,6 +35,7 @@ import org.jetbrains.kotlin.gradle.internal.customizeKotlinDependencies
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
import org.jetbrains.kotlin.gradle.model.builder.KotlinModelBuilder
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubplugin
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode
import org.jetbrains.kotlin.gradle.targets.js.ir.*
@@ -60,46 +60,48 @@ val KOTLIN_JS_DSL_NAME = "kotlin2js"
val KOTLIN_OPTIONS_DSL_NAME = "kotlinOptions"
abstract class KotlinCompilationProcessor<out T : SourceTask>(
open val kotlinCompilation: KotlinCompilation<*>
open val kotlinCompilation: KotlinCompilationData<*>
) {
abstract val kotlinTask: TaskProvider<out T>
abstract fun run()
protected val project: Project
get() = kotlinCompilation.target.project
get() = kotlinCompilation.project
protected val defaultKotlinDestinationDir: File
get() {
val kotlinExt = project.kotlinExtension
val kotlinExt = project.topLevelExtension
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()
return File(project.buildDir, "classes/kotlin/$targetSubDirectory${kotlinCompilation.compilationName}")
kotlinCompilation.compilationClassifier?.let { "$it/" }.orEmpty()
return File(project.buildDir, "classes/kotlin/$targetSubDirectory${kotlinCompilation.compilationPurpose}")
}
}
internal abstract class KotlinSourceSetProcessor<T : AbstractKotlinCompile<*>>(
val tasksProvider: KotlinTasksProvider,
val taskDescription: String,
kotlinCompilation: AbstractKotlinCompilation<*>
kotlinCompilation: KotlinCompilationData<*>
) : KotlinCompilationProcessor<T>(kotlinCompilation) {
protected abstract fun doTargetSpecificProcessing()
protected val logger = Logging.getLogger(this.javaClass)!!
protected val sourceSetName: String = kotlinCompilation.compilationName
protected val sourceSetName: String = kotlinCompilation.compilationPurpose
override val kotlinTask: TaskProvider<out T> = prepareKotlinCompileTask()
protected val javaSourceSet: SourceSet?
get() =
(kotlinCompilation as? KotlinWithJavaCompilation<*>)?.javaSourceSet
?: kotlinCompilation.target.let {
if (it is KotlinJvmTarget && it.withJavaEnabled)
project.convention.getPlugin(JavaPluginConvention::class.java).sourceSets.maybeCreate(kotlinCompilation.name)
get() {
val compilation = kotlinCompilation
return (compilation as? KotlinWithJavaCompilation<*>)?.javaSourceSet
?: kotlinCompilation.owner.let {
if (it is KotlinJvmTarget && it.withJavaEnabled && compilation is KotlinJvmCompilation)
project.convention.getPlugin(JavaPluginConvention::class.java).sourceSets.maybeCreate(compilation.name)
else null
}
}
private fun prepareKotlinCompileTask(): TaskProvider<out T> =
registerKotlinCompileTask(register = ::doRegisterTask).also { task ->
@@ -136,31 +138,23 @@ internal abstract class KotlinSourceSetProcessor<T : AbstractKotlinCompile<*>>(
// Try to avoid duplicate Java sources in allSource; run lazily to allow changing the directory set:
val kotlinSrcDirsToAdd = Callable {
kotlinCompilation.kotlinSourceSets.map { filterOutJavaSrcDirsIfPossible(it.kotlin) }
kotlinCompilation.kotlinSourceDirectoriesByFragmentName.values.map { filterOutJavaSrcDirsIfPossible(it) }
}
java.allJava.srcDirs(kotlinSrcDirsToAdd)
java.allSource.srcDirs(kotlinSrcDirsToAdd)
}
private fun filterOutJavaSrcDirsIfPossible(sourceDirectorySet: SourceDirectorySet): FileCollection {
val java = javaSourceSet ?: return sourceDirectorySet
// If the API used below is not available, fall back to not filtering the Java sources.
if (SourceDirectorySet::class.java.methods.none { it.name == "getSourceDirectories" }) {
return sourceDirectorySet
}
fun getSourceDirectories(sourceDirectorySet: SourceDirectorySet): FileCollection {
val method = SourceDirectorySet::class.java.getMethod("getSourceDirectories")
return method(sourceDirectorySet) as FileCollection
}
private fun filterOutJavaSrcDirsIfPossible(sourceDirectories: FileCollection): FileCollection {
val java = javaSourceSet ?: return sourceDirectories
// Build a lazily-resolved file collection that filters out Java sources from sources of this sourceDirectorySet
return getSourceDirectories(sourceDirectorySet).minus(getSourceDirectories(java.java))
return sourceDirectories.minus(java.java.sourceDirectories)
}
private fun createAdditionalClassesTaskForIdeRunner() {
val kotlinCompilation = kotlinCompilation as? KotlinCompilation<*> ?: return
open class IDEClassesTask : DefaultTask()
// Workaround: as per KT-26641, when there's a Kotlin compilation with a Java source set, we create another task
// that has a name composed as '<IDE module name>Classes`, where the IDE module name is the default source set name:
@@ -185,7 +179,7 @@ internal abstract class KotlinSourceSetProcessor<T : AbstractKotlinCompile<*>>(
internal class Kotlin2JvmSourceSetProcessor(
tasksProvider: KotlinTasksProvider,
kotlinCompilation: AbstractKotlinCompilation<*>,
kotlinCompilation: KotlinCompilationData<*>,
private val kotlinPluginVersion: String
) : KotlinSourceSetProcessor<KotlinCompile>(
tasksProvider, "Compiles the $kotlinCompilation.", kotlinCompilation
@@ -199,14 +193,16 @@ internal class Kotlin2JvmSourceSetProcessor(
override fun doTargetSpecificProcessing() {
ifKaptEnabled(project) {
Kapt3GradleSubplugin.createAptConfigurationIfNeeded(project, kotlinCompilation.compilationName)
Kapt3GradleSubplugin.createAptConfigurationIfNeeded(project, kotlinCompilation.compilationPurpose)
}
ScriptingGradleSubplugin.configureForSourceSet(project, kotlinCompilation.compilationName)
ScriptingGradleSubplugin.configureForSourceSet(project, kotlinCompilation.compilationPurpose)
project.whenEvaluated {
val subpluginEnvironment = SubpluginEnvironment.loadSubplugins(project, kotlinPluginVersion)
subpluginEnvironment.addSubpluginOptions(project, kotlinCompilation)
if (kotlinCompilation is KotlinCompilation<*>) // FIXME support compiler plugins with PM20
subpluginEnvironment.addSubpluginOptions(project, kotlinCompilation)
javaSourceSet?.let { java ->
val javaTask = project.tasks.withType<AbstractCompile>().named(java.compileJavaTaskName)
@@ -236,7 +232,7 @@ internal fun KotlinCompilationOutput.addClassesDir(classesDirProvider: () -> Fil
internal class Kotlin2JsSourceSetProcessor(
tasksProvider: KotlinTasksProvider,
kotlinCompilation: AbstractKotlinCompilation<*>,
kotlinCompilation: KotlinCompilationData<*>,
private val kotlinPluginVersion: String
) : KotlinSourceSetProcessor<Kotlin2JsCompile>(
tasksProvider,
@@ -294,7 +290,9 @@ internal class Kotlin2JsSourceSetProcessor(
}
val subpluginEnvironment: SubpluginEnvironment = SubpluginEnvironment.loadSubplugins(project, kotlinPluginVersion)
subpluginEnvironment.addSubpluginOptions(project, kotlinCompilation)
if (kotlinCompilation is KotlinCompilation<*>) {
subpluginEnvironment.addSubpluginOptions(project, kotlinCompilation)
}
}
}
}
@@ -358,7 +356,7 @@ internal class KotlinJsIrSourceSetProcessor(
}
internal class KotlinCommonSourceSetProcessor(
compilation: AbstractKotlinCompilation<*>,
compilation: KotlinCompilationData<*>,
tasksProvider: KotlinTasksProvider,
private val kotlinPluginVersion: String
) : KotlinSourceSetProcessor<KotlinCompileCommon>(
@@ -367,13 +365,15 @@ internal class KotlinCommonSourceSetProcessor(
override fun doTargetSpecificProcessing() {
project.tasks.named(kotlinCompilation.compileAllTaskName).dependsOn(kotlinTask)
// can be missing (e.g. in case of tests)
if (kotlinCompilation.isMain()) {
if ((kotlinCompilation as? AbstractKotlinCompilation<*>)?.isMain() == true) {
project.locateTask<Task>(kotlinCompilation.target.artifactsTaskName)?.dependsOn(kotlinTask)
}
project.whenEvaluated {
val subpluginEnvironment: SubpluginEnvironment = SubpluginEnvironment.loadSubplugins(project, kotlinPluginVersion)
subpluginEnvironment.addSubpluginOptions(project, kotlinCompilation)
if (kotlinCompilation is AbstractKotlinCompilation<*>) {
project.whenEvaluated {
val subpluginEnvironment: SubpluginEnvironment = SubpluginEnvironment.loadSubplugins(project, kotlinPluginVersion)
subpluginEnvironment.addSubpluginOptions(project, kotlinCompilation)
}
}
}
@@ -602,7 +602,7 @@ internal abstract class AbstractKotlinPlugin(
internal open class KotlinPlugin(
kotlinPluginVersion: String,
registry: ToolingModelBuilderRegistry
) : AbstractKotlinPlugin(KotlinTasksProvider(targetName), kotlinPluginVersion, registry) {
) : AbstractKotlinPlugin(KotlinTasksProvider(), kotlinPluginVersion, registry) {
companion object {
private const val targetName = "" // use empty suffix for the task names
@@ -633,7 +633,7 @@ internal open class KotlinPlugin(
internal open class KotlinCommonPlugin(
kotlinPluginVersion: String,
registry: ToolingModelBuilderRegistry
) : AbstractKotlinPlugin(KotlinTasksProvider(targetName), kotlinPluginVersion, registry) {
) : AbstractKotlinPlugin(KotlinTasksProvider(), kotlinPluginVersion, registry) {
companion object {
private const val targetName = "common"
@@ -662,7 +662,7 @@ internal open class KotlinCommonPlugin(
internal open class Kotlin2JsPlugin(
kotlinPluginVersion: String,
registry: ToolingModelBuilderRegistry
) : AbstractKotlinPlugin(KotlinTasksProvider(targetName), kotlinPluginVersion, registry) {
) : AbstractKotlinPlugin(KotlinTasksProvider(), kotlinPluginVersion, registry) {
companion object {
private const val targetName = "2Js"
@@ -716,7 +716,7 @@ internal open class KotlinAndroidPlugin(
kotlinPluginVersion: String,
androidTarget: KotlinAndroidTarget
): AbstractAndroidProjectHandler {
val tasksProvider = AndroidTasksProvider(androidTarget.targetName)
val tasksProvider = AndroidTasksProvider()
if (androidPluginVersion != null) {
val minimalVersion = "3.0.0"
@@ -23,12 +23,15 @@ import org.gradle.api.Project
import org.gradle.api.internal.FeaturePreviews
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
import org.gradle.api.model.ObjectFactory
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20GradlePlugin
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20ProjectExtension
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSetFactory
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsCompilerAttribute
@@ -52,7 +55,7 @@ abstract class KotlinBasePluginWrapper : Plugin<Project> {
private val log = Logging.getLogger(this.javaClass)
val kotlinPluginVersion = loadKotlinVersionFromResource(log)
open val projectExtensionClass: KClass<out KotlinProjectExtension> get() = KotlinProjectExtension::class
open val projectExtensionClass: KClass<out KotlinTopLevelExtension> get() = KotlinProjectExtension::class
internal open fun kotlinSourceSetFactory(project: Project): NamedDomainObjectFactory<KotlinSourceSet> =
DefaultKotlinSourceSetFactory(project)
@@ -83,12 +86,18 @@ abstract class KotlinBasePluginWrapper : Plugin<Project> {
kotlinGradleBuildServices.detectKotlinPluginLoadedInMultipleProjects(project, kotlinPluginVersion)
project.createKotlinExtension(projectExtensionClass).apply {
if (this is KotlinPm20ProjectExtension)
this.project = project // refactor this code to remove the specific plugin class?
coreLibrariesVersion = kotlinPluginVersion
fun kotlinSourceSetContainer(factory: NamedDomainObjectFactory<KotlinSourceSet>) =
project.container(KotlinSourceSet::class.java, factory)
project.kotlinExtension.sourceSets = kotlinSourceSetContainer(kotlinSourceSetFactory(project))
val topLevelExtension = project.topLevelExtension
if (topLevelExtension is KotlinProjectExtension) {
project.kotlinExtension.sourceSets = kotlinSourceSetContainer(kotlinSourceSetFactory(project))
}
}
project.extensions.add(KotlinTestsRegistry.PROJECT_EXTENSION_NAME, createTestRegistry(project))
@@ -237,6 +246,14 @@ open class KotlinMultiplatformPluginWrapper @Inject constructor(
}
}
open class KotlinPm20PluginWrapper @Inject constructor(private val objectFactory: ObjectFactory) : KotlinBasePluginWrapper() {
override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin<Project> =
objectFactory.newInstance(KotlinPm20GradlePlugin::class.java)
override val projectExtensionClass: KClass<out KotlinPm20ProjectExtension>
get() = KotlinPm20ProjectExtension::class
}
fun Project.getKotlinPluginVersion(): String? =
plugins.asSequence().mapNotNull { (it as? KotlinBasePluginWrapper)?.kotlinPluginVersion }.firstOrNull()
@@ -8,6 +8,7 @@ import org.gradle.api.tasks.compile.JavaCompile
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
@@ -8,10 +8,13 @@ package org.jetbrains.kotlin.gradle.plugin.mpp
import org.gradle.api.Project
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ExternalModuleDependency
import org.gradle.api.artifacts.ModuleDependency
import org.gradle.api.artifacts.ProjectDependency
import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleModule
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.LazyCapability
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency
import org.jetbrains.kotlin.gradle.targets.js.npm.directoryNpmDependency
import org.jetbrains.kotlin.gradle.targets.js.npm.moduleName
@@ -69,8 +72,17 @@ class DefaultKotlinDependencyHandler(
private fun addDependencyByAnyNotation(
configurationName: String,
dependencyNotation: Any
): Dependency? =
project.dependencies.add(configurationName, dependencyNotation)
): Dependency? {
val dependency = when (dependencyNotation) {
is KotlinGradleModule -> project.dependencies.create(dependencyNotation.project).apply {
(this as ModuleDependency).capabilities {
it.requireCapability(LazyCapability.fromModule(dependencyNotation))
}
}
else -> dependencyNotation
}
return project.dependencies.add(configurationName, dependency)
}
private fun addDependencyByStringNotation(
configurationName: String,
@@ -158,7 +158,6 @@ class GradleProjectModuleBuilder(private val addInferredSourceSetVisibilityAsExp
variant.variantAttributes[KotlinAttributeKey(key.name)] =
attributeString(compileDependenciesConfiguration.attributes, key)
}
variant.isExported = compilation.isMain()
}
}
// Once all fragments are created, add dependencies between them
@@ -11,7 +11,7 @@ import org.gradle.api.Project
import org.gradle.api.attributes.Attribute
import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.file.DuplicatesStrategy
import org.gradle.api.internal.FeaturePreviews
import org.gradle.api.file.FileCollection
import org.gradle.api.internal.plugins.DslObject
import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.api.tasks.SourceTask
@@ -295,11 +295,11 @@ internal fun applyUserDefinedAttributes(target: AbstractKotlinTarget) {
}
internal fun sourcesJarTask(compilation: KotlinCompilation<*>, componentName: String?, artifactNameAppendix: String): TaskProvider<Jar> =
sourcesJarTask(compilation.target.project, lazy { compilation.allKotlinSourceSets }, componentName, artifactNameAppendix)
sourcesJarTask(compilation.target.project, lazy { compilation.allKotlinSourceSets.associate { it.name to it.kotlin } }, componentName, artifactNameAppendix)
internal fun sourcesJarTask(
project: Project,
sourceSets: Lazy<Set<KotlinSourceSet>>,
sourceSets: Lazy<Map<String, FileCollection>>,
componentName: String?,
artifactNameAppendix: String
): TaskProvider<Jar> {
@@ -316,9 +316,9 @@ internal fun sourcesJarTask(
project.whenEvaluated {
result.configure {
sourceSets.value.forEach { sourceSet ->
it.from(sourceSet.kotlin) { copySpec ->
copySpec.into(sourceSet.name)
sourceSets.value.forEach { (sourceSetName, sourceSetFiles) ->
it.from(sourceSetFiles) { copySpec ->
copySpec.into(sourceSetName)
// Duplicates are coming from `SourceSets` that `sourceSet` depends on.
// Such dependency was added by Kotlin compilation.
// TODO: rethink approach for adding dependent `SourceSets` to Kotlin compilation `SourceSet`
@@ -24,34 +24,43 @@ object KotlinUsages {
private val jvmPlatformTypes: Set<KotlinPlatformType> = setOf(jvm, androidJvm)
internal fun consumerApiUsage(target: KotlinTarget) = target.project.usageByName(
when (target.platformType) {
internal fun consumerApiUsage(project: Project, platformType: KotlinPlatformType) = project.usageByName(
when (platformType) {
in jvmPlatformTypes -> JAVA_API
else -> KOTLIN_API
}
)
internal fun consumerRuntimeUsage(target: KotlinTarget) = target.project.usageByName(
when (target.platformType) {
internal fun consumerApiUsage(target: KotlinTarget): Usage =
consumerApiUsage(target.project, target.platformType)
internal fun consumerRuntimeUsage(project: Project, platformType: KotlinPlatformType) = project.usageByName(
when (platformType) {
in jvmPlatformTypes -> JAVA_RUNTIME
else -> KOTLIN_RUNTIME
}
)
internal fun producerApiUsage(target: KotlinTarget) = target.project.usageByName(
when (target.platformType) {
internal fun consumerRuntimeUsage(target: KotlinTarget) = consumerRuntimeUsage(target.project, target.platformType)
internal fun producerApiUsage(project: Project, platformType: KotlinPlatformType) = project.usageByName(
when (platformType) {
in jvmPlatformTypes -> "java-api-jars"
else -> KOTLIN_API
}
)
internal fun producerRuntimeUsage(target: KotlinTarget) = target.project.usageByName(
when (target.platformType) {
internal fun producerApiUsage(target: KotlinTarget) = producerApiUsage(target.project, target.platformType)
internal fun producerRuntimeUsage(project: Project, platformType: KotlinPlatformType) = project.usageByName(
when (platformType) {
in jvmPlatformTypes -> "java-runtime-jars"
else -> KOTLIN_RUNTIME
}
)
internal fun producerRuntimeUsage(target: KotlinTarget) = producerRuntimeUsage(target.project, target.platformType)
private class KotlinJavaRuntimeJarsCompatibility : AttributeCompatibilityRule<Usage> {
// When Gradle resolves a plain old JAR dependency with no metadata attached, the Usage attribute of that dependency
// is 'java-runtime-jars'. This rule tells Gradle that Kotlin consumers can consume plain old JARs:
@@ -13,6 +13,7 @@ import org.gradle.api.UnknownTaskException
import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.execution.TaskExecutionListener
import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.plugins.BasePluginConvention
import org.gradle.api.plugins.ExtraPropertiesExtension
import org.gradle.api.provider.Property
@@ -23,12 +24,14 @@ import org.gradle.util.ConfigureUtil
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.internal.KotlinCompilationsModuleGroups
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.plugin.sources.defaultSourceSetLanguageSettingsChecker
import org.jetbrains.kotlin.gradle.plugin.sources.withAllDependsOnSourceSets
import org.jetbrains.kotlin.gradle.plugin.sources.resolveAllDependsOnSourceSets
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
import org.jetbrains.kotlin.gradle.tasks.locateTask
import org.jetbrains.kotlin.gradle.utils.*
import java.io.File
import java.util.*
import java.util.concurrent.Callable
@@ -52,8 +55,11 @@ internal val KotlinCompilation<*>.kotlinSourceSetsIncludingDefault: Set<KotlinSo
abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
target: KotlinTarget,
override val compilationPurpose: String
) : KotlinCompilation<T>, HasKotlinDependencies, KotlinCompilationData<T> {
override val compilationName: String
) : KotlinCompilation<T>, HasKotlinDependencies {
get() = compilationPurpose
override fun kotlinOptions(configure: T.() -> Unit) =
configure(kotlinOptions)
@@ -86,7 +92,7 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
when {
isMain() && target is KotlinMetadataTarget ->
KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME // corner case: main compilation of the metadata target compiles commonMain
else -> compilationName
else -> compilationPurpose
}
)
@@ -101,23 +107,14 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
Callable { target.project.buildDir.resolve("processedResources/${target.targetName}/$name") })
}
open fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) {
fun AbstractKotlinCompile<*>.configureAction() {
source(sourceSet.kotlin)
sourceFilesExtensions(sourceSet.customSourceFilesExtensions)
commonSourceSet += project.files(Callable {
if (addAsCommonSources.value) sourceSet.kotlin else emptyList<Any>()
})
}
target.project.tasks
// To configure a task that may have not yet been created at this point, use 'withType-matching-configureEach`:
.withType(AbstractKotlinCompile::class.java)
.matching { it.name == compileKotlinTaskName }
.configureEach { compileKotlinTask ->
compileKotlinTask.configureAction()
}
}
open fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) =
addSourcesToKotlinCompileTask(
project,
compileKotlinTaskName,
sourceSet.customSourceFilesExtensions,
{ sourceSet.kotlin },
addAsCommonSources
)
internal fun addExactSourceSetsEagerly(sourceSets: Set<KotlinSourceSet>) {
with(target.project) {
@@ -166,20 +163,20 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
override val compileDependencyConfigurationName: String
get() = lowerCamelCaseName(
target.disambiguationClassifier,
compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(),
compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(),
"compileClasspath"
)
override val compileKotlinTaskName: String
get() = lowerCamelCaseName(
"compile",
compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
"Kotlin",
target.targetName
)
override val compileAllTaskName: String
get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName, "classes")
get() = lowerCamelCaseName(target.disambiguationClassifier, compilationPurpose, "classes")
override lateinit var compileDependencyFiles: FileCollection
@@ -201,7 +198,7 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
override fun dependencies(configureClosure: Closure<Any?>) =
dependencies f@{ ConfigureUtil.configure(configureClosure, this@f) }
override fun toString(): String = "compilation '$compilationName' ($target)"
override fun toString(): String = "compilation '$compilationPurpose' ($target)"
internal val friendArtifactsTask: TaskProvider<AbstractArchiveTask>? by lazy {
if (associateWithTransitiveClosure.any { it.isMain() }) {
@@ -240,7 +237,7 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
}
override val moduleName: String
get() = KotlinCompilationsModuleGroups.getModuleLeaderCompilation(this).takeIf { it != this }?.ownModuleName ?: ownModuleName
get() = KotlinCompilationsModuleGroups.getModuleLeaderCompilation(this).takeIf { it != this }?.ownModuleName() ?: ownModuleName
override fun associateWith(other: KotlinCompilation<*>) {
require(other.target == target) { "Only associations between compilations of a single target are supported" }
@@ -278,17 +275,64 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
override val associateWith: List<KotlinCompilation<*>>
get() = Collections.unmodifiableList(_associateWith.toList())
override val kotlinOptions: T
get() = TODO("Not yet implemented")
override val project: Project
get() = target.project
override val owner: Any?
get() = target
override val compilationClassifier: String?
get() = target.disambiguationClassifier
override val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet>
get() = defaultSourceSet.withAllDependsOnSourceSets().associate { it.name to it.kotlin }
override val languageSettings: LanguageSettingsBuilder
get() = defaultSourceSet.languageSettings
override val platformType: KotlinPlatformType
get() = target.platformType
override val ownModuleName: String
get() = ownModuleName()
}
internal val KotlinCompilation<*>.ownModuleName: String
get() {
val project = target.project
val baseName = project.convention.findPlugin(BasePluginConvention::class.java)?.archivesBaseName
?: project.name
val suffix = if (isMain()) "" else "_$compilationName"
return filterModuleName("$baseName$suffix")
internal fun addSourcesToKotlinCompileTask(
project: Project,
taskName: String,
sourceFileExtensions: Iterable<String>,
sources: () -> Iterable<File>,
addAsCommonSources: Lazy<Boolean>
) {
fun AbstractKotlinCompile<*>.configureAction() {
source(project.files(Callable { sources() }))
sourceFilesExtensions(sourceFileExtensions)
commonSourceSet += project.files(Callable {
if (addAsCommonSources.value) sources() else emptyList<Any>()
})
}
project.tasks
// To configure a task that may have not yet been created at this point, use 'withType-matching-configureEach`:
.withType(AbstractKotlinCompile::class.java)
.matching { it.name == taskName }
.configureEach { compileKotlinTask ->
compileKotlinTask.configureAction()
}
}
private fun KotlinCompilation<*>.ownModuleName(): String {
val project = target.project
val baseName = project.convention.findPlugin(BasePluginConvention::class.java)?.archivesBaseName
?: project.name
val suffix = if (isMain()) "" else "_$compilationName"
return filterModuleName("$baseName$suffix")
}
internal val KotlinCompilation<*>.associateWithTransitiveClosure: Iterable<KotlinCompilation<*>>
get() = mutableSetOf<KotlinCompilation<*>>().apply {
fun visit(other: KotlinCompilation<*>) {
@@ -306,7 +350,7 @@ abstract class AbstractKotlinCompilationToRunnableFiles<T : KotlinCommonOptions>
override val runtimeDependencyConfigurationName: String
get() = lowerCamelCaseName(
target.disambiguationClassifier,
compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
"runtimeClasspath"
)
@@ -397,5 +441,5 @@ internal object CompilationSourceSetUtil {
private val invalidModuleNameCharactersRegex = """[\\/\r\n\t]""".toRegex()
private fun filterModuleName(moduleName: String): String =
internal fun filterModuleName(moduleName: String): String =
moduleName.replace(invalidModuleNameCharactersRegex, "_")
@@ -0,0 +1,133 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.NamedDomainObjectProvider
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension
import org.jetbrains.kotlin.gradle.dsl.pm20Extension
import org.jetbrains.kotlin.gradle.internal.customizeKotlinDependencies
import org.jetbrains.kotlin.gradle.utils.checkGradleCompatibility
abstract class KotlinPm20GradlePlugin : Plugin<Project> {
override fun apply(project: Project) {
checkGradleCompatibility("the Kotlin Multiplatform plugin", GradleVersion.version("6.1"))
// Gradle sets up the attribute schema for consuming JVM dependencies in the JavaBasePlugin
project.plugins.apply(JavaBasePlugin::class.java)
createDefaultModules(project)
customizeKotlinDependencies(project)
registerDefaultVariantFactories(project)
}
private fun registerDefaultVariantFactories(project: Project) {
project.pm20Extension.modules.configureEach {
it.fragments.registerFactory(
KotlinJvmVariant::class.java,
KotlinJvmVariantFactory(it)
)
}
}
private fun createDefaultModules(project: Project) {
project.pm20Extension.apply {
modules.create(KotlinGradleModule.MAIN_MODULE_NAME)
modules.create(KotlinGradleModule.TEST_MODULE_NAME)
main { makePublic() }
}
}
private fun setupMetadataCompilation() {
// TODO dependency transformations in tasks
// TODO classpath configurations
// TODO compilation data -> tasks
// TODO project structure metadata -> metadata artifact
// TODO task outputs -> metadata artifact
// TODO export the metadata artifact in consumable configurations
}
}
open class KotlinPm20ProjectExtension : KotlinTopLevelExtension() {
internal lateinit var project: Project
val modules: NamedDomainObjectContainer<KotlinGradleModule> by lazy {
project.objects.domainObjectContainer(
KotlinGradleModule::class.java,
KotlinGradleModuleFactory(project)
)
}
@Suppress("unused") // DSL function
fun mainAndTest(configure: KotlinGradleModule.() -> Unit) {
main(configure)
test(configure)
}
val main: KotlinGradleModule
get() = modules.getByName(KotlinGradleModule.MAIN_MODULE_NAME)
val test: KotlinGradleModule
get() = modules.getByName(KotlinGradleModule.TEST_MODULE_NAME)
fun main(configure: KotlinGradleModule.() -> Unit = { }) = main.apply(configure)
fun test(configure: KotlinGradleModule.() -> Unit = { }) = test.apply(configure)
}
val KotlinGradleModule.jvm: KotlinJvmVariant
get() = fragments.maybeCreate("jvm", KotlinJvmVariant::class.java)
fun KotlinGradleModule.jvm(configure: KotlinJvmVariant.() -> Unit): KotlinJvmVariant = jvm.apply(configure)
fun KotlinPm20ProjectExtension.jvm(configure: KotlinFragmentSlice<KotlinJvmVariant>.() -> Unit) {
val getOrCreateVariant: KotlinGradleModule.() -> KotlinJvmVariant = { jvm }
mainAndTest { getOrCreateVariant(this) }
val slice = KotlinFragmentSlice(this, getOrCreateVariant)
configure(slice)
}
open class KotlinFragmentSlice<T : KotlinGradleFragment>(
val pm20ProjectExtension: KotlinPm20ProjectExtension,
val getOrCreateFragment: (KotlinGradleModule) -> T
) {
fun inMain(configure: T.() -> Unit) {
pm20ProjectExtension.modules.getByName(KotlinGradleModule.MAIN_MODULE_NAME).apply {
getOrCreateFragment(this).configure()
}
}
fun inTest(configure: T.() -> Unit) {
pm20ProjectExtension.modules.getByName(KotlinGradleModule.TEST_MODULE_NAME).apply {
getOrCreateFragment(this).configure()
}
}
fun inMainAndTest(configure: T.() -> Unit) {
pm20ProjectExtension.mainAndTest { getOrCreateFragment(this).configure() }
}
fun inAllModules(configure: T.() -> Unit) {
pm20ProjectExtension.modules.all {
getOrCreateFragment(it).configure()
}
}
fun inModule(moduleName: String, configure: T.() -> Unit) {
pm20ProjectExtension.modules.getByName(moduleName).apply { getOrCreateFragment(this).configure() }
}
fun inModule(module: NamedDomainObjectProvider<KotlinGradleModule>, configure: T.() -> Unit) {
module.get().apply { inModule(this, configure) }
}
fun inModule(module: KotlinGradleModule, configure: T.() -> Unit) {
getOrCreateFragment(module).configure()
}
}
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationOutput
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
interface KotlinCompilationData<T : KotlinCommonOptions> {
val project: Project
val owner: Any?
val compilationPurpose: String
val compilationClassifier: String?
val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet>
val compileKotlinTaskName: String
val compileAllTaskName: String
val compileDependencyFiles: FileCollection
val output: KotlinCompilationOutput
val languageSettings: LanguageSettingsBuilder
val platformType: KotlinPlatformType
val moduleName: String
val ownModuleName: String
val kotlinOptions: T
}
@@ -0,0 +1,110 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import groovy.lang.Closure
import org.gradle.api.Named
import org.gradle.api.NamedDomainObjectProvider
import org.gradle.api.Project
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.provider.Provider
import org.gradle.util.ConfigureUtil
import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultKotlinDependencyHandler
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.project.model.KotlinModuleDependency
import org.jetbrains.kotlin.project.model.KotlinModuleFragment
import javax.inject.Inject
open class KotlinGradleFragment @Inject constructor(
override val containingModule: KotlinGradleModule,
override val fragmentName: String
) : KotlinModuleFragment, HasKotlinDependencies, Named {
override fun getName(): String = fragmentName
// TODO pull up to KotlinModuleFragment
val languageSettings: LanguageSettingsBuilder = DefaultLanguageSettingsBuilder()
protected val project: Project
get() = containingModule.project
open fun refines(other: KotlinGradleFragment) {
checkCanRefine(other)
refines(containingModule.fragments.named(other.name))
}
open fun refines(other: NamedDomainObjectProvider<KotlinGradleFragment>) {
_directRefinesDependencies.add(other)
other.configure { checkCanRefine(it) }
listOf(
KotlinGradleFragment::transitiveApiConfigurationName,
KotlinGradleFragment::transitiveImplementationConfigurationName
).forEach { getConfiguration ->
project.addExtendsFromRelation(getConfiguration(this), getConfiguration(other.get())) // todo eager instantiation; fix?
}
}
private fun checkCanRefine(other: KotlinGradleFragment) {
check(containingModule == other.containingModule) { "Fragments can only refine each other within one module." }
}
override fun dependencies(configure: KotlinDependencyHandler.() -> Unit): Unit =
DefaultKotlinDependencyHandler(this, project).run(configure)
override fun dependencies(configureClosure: Closure<Any?>) =
dependencies f@{ ConfigureUtil.configure(configureClosure, this@f) }
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")
private val _directRefinesDependencies = mutableSetOf<Provider<KotlinGradleFragment>>()
override val directRefinesDependencies: Iterable<KotlinGradleFragment>
get() = _directRefinesDependencies.map { it.get() }
override val declaredModuleDependencies: Iterable<KotlinModuleDependency>
get() = TODO("Not yet implemented")
override val kotlinSourceRoots: SourceDirectorySet by lazy {
project.objects.sourceDirectorySet(
"$fragmentName.kotlin", "Kotlin sources for fragment $fragmentName"
)
}
/** This configuration includes the dependencies from the refines-parents */
internal val transitiveApiConfigurationName: String
get() = disambiguateName("transitiveApi")
/** This configuration includes the dependencies from the refines-parents */
internal val transitiveImplementationConfigurationName: String
get() = disambiguateName("transitiveImplementation")
override val relatedConfigurationNames: List<String>
get() = super.relatedConfigurationNames +
// TODO: resolvable metadata configurations?
listOf(transitiveApiConfigurationName, transitiveImplementationConfigurationName)
companion object {
const val COMMON_FRAGMENT_NAME = "common"
}
}
internal fun KotlinModuleFragment.disambiguateName(simpleName: String) =
lowerCamelCaseName(fragmentName, containingModule.moduleIdentifier.moduleClassifier ?: KotlinGradleModule.MAIN_MODULE_NAME, simpleName)
@@ -0,0 +1,93 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import groovy.lang.Closure
import org.gradle.api.ExtensiblePolymorphicDomainObjectContainer
import org.gradle.api.Named
import org.gradle.api.NamedDomainObjectSet
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
import org.jetbrains.kotlin.project.model.KotlinModule
import org.jetbrains.kotlin.project.model.KotlinModuleIdentifier
import org.jetbrains.kotlin.project.model.LocalModuleIdentifier
import javax.inject.Inject
open class KotlinGradleModule(
internal val project: Project,
val moduleClassifier: String?
) : KotlinModule, Named, HasKotlinDependencies {
@Inject
constructor(project: Project, moduleClassifier: CharSequence)
: this(project, moduleClassifier.toString().takeIf { it != MAIN_MODULE_NAME })
override val moduleIdentifier: KotlinModuleIdentifier =
LocalModuleIdentifier(project.currentBuildId().name, project.path, moduleClassifier)
override val fragments: ExtensiblePolymorphicDomainObjectContainer<KotlinGradleFragment> =
project.objects.polymorphicDomainObjectContainer(KotlinGradleFragment::class.java)
// TODO DSL & build script model: find a way to create a flexible typed view on fragments?
override val variants: NamedDomainObjectSet<KotlinGradleVariant> by lazy {
fragments.withType(KotlinGradleVariant::class.java)
}
var isPublic: Boolean = false
private set
private var setPublicHandlers: MutableList<() -> Unit> = mutableListOf()
fun ifMadePublic(action: () -> Unit) {
if (isPublic) action() else setPublicHandlers.add(action)
}
fun makePublic() {
if (isPublic) return
setPublicHandlers.forEach { it() }
isPublic = true
}
companion object {
const val MAIN_MODULE_NAME = "main"
const val TEST_MODULE_NAME = "test"
}
override fun getName(): String = when (moduleClassifier) {
null -> MAIN_MODULE_NAME
else -> moduleClassifier
}
// DSL
val common: KotlinGradleFragment
get() = fragments.getByName(KotlinGradleFragment.COMMON_FRAGMENT_NAME)
fun common(configure: KotlinGradleFragment.() -> Unit) =
common.configure()
override fun dependencies(configure: KotlinDependencyHandler.() -> Unit) =
common.dependencies(configure)
override fun dependencies(configureClosure: Closure<Any?>) =
common.dependencies(configureClosure)
override val apiConfigurationName: String
get() = common.apiConfigurationName
override val implementationConfigurationName: String
get() = common.implementationConfigurationName
override val compileOnlyConfigurationName: String
get() = common.compileOnlyConfigurationName
override val runtimeOnlyConfigurationName: String
get() = common.runtimeOnlyConfigurationName
}
internal val KotlinGradleModule.isMain
get() = moduleIdentifier.moduleClassifier == null
@@ -0,0 +1,47 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.NamedDomainObjectFactory
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.pm20Extension
open class KotlinGradleModuleFactory(private val project: Project) : NamedDomainObjectFactory<KotlinGradleModule> {
override fun create(name: String): KotlinGradleModule {
val result = project.objects.newInstance(KotlinGradleModule::class.java, project, name)
registerFragmentFactory(result)
registerDefaultCommonFragment(result)
addDefaultDependencyOnMainModule(result)
addDefaultRefinementDependencyOnCommon(result)
return result
}
protected open fun registerDefaultCommonFragment(module: KotlinGradleModule) {
module.fragments.create(KotlinGradleFragment.COMMON_FRAGMENT_NAME, KotlinGradleFragment::class.java)
}
protected open fun addDefaultRefinementDependencyOnCommon(module: KotlinGradleModule) {
module.fragments.matching { it.name != KotlinGradleFragment.COMMON_FRAGMENT_NAME }.all {
it.refines(module.fragments.named(KotlinGradleFragment.COMMON_FRAGMENT_NAME))
}
}
protected open fun addDefaultDependencyOnMainModule(module: KotlinGradleModule) {
if (module.name != KotlinGradleModule.MAIN_MODULE_NAME) {
module.fragments
.matching { it.fragmentName == KotlinGradleFragment.COMMON_FRAGMENT_NAME }
.configureEach { commonFragment ->
commonFragment.dependencies {
api(module.project.pm20Extension.modules.getByName(KotlinGradleModule.MAIN_MODULE_NAME))
}
}
}
}
protected open fun registerFragmentFactory(module: KotlinGradleModule) {
module.fragments.registerFactory(KotlinGradleFragment::class.java, CommonGradleFragmentFactory(module))
}
}
@@ -0,0 +1,80 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.plugins.BasePluginConvention
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
import org.jetbrains.kotlin.gradle.dsl.pm20Extension
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationOutput
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.mpp.filterModuleName
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.project.model.refinesClosure
open class KotlinJvmVariant(containingModule: KotlinGradleModule, fragmentName: String) :
KotlinGradleVariantWithRuntimeDependencies(containingModule, fragmentName) {
override val platformType: KotlinPlatformType
get() = KotlinPlatformType.jvm
}
class KotlinJvmVariantCompilationData(val variant: KotlinJvmVariant) : KotlinCompilationData<KotlinJvmOptions> {
override val project: Project get() = variant.containingModule.project
override val owner: KotlinJvmVariant get() = variant
override val compilationPurpose: String
get() = variant.containingModule.name
override val compilationClassifier: String
get() = variant.name
override val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet>
get() = variant.refinesClosure.filterIsInstance<KotlinGradleVariant>().associate { it.disambiguateName("") to it.kotlinSourceRoots }
override val output: KotlinCompilationOutput
get() = variant.compilationOutputs
override val compileKotlinTaskName: String
get() = lowerCamelCaseName("compile", compilationPurpose.takeIf { it != "main" }, "Kotlin", compilationClassifier)
override val compileAllTaskName: String
get() = variant.disambiguateName("classes")
override val compileDependencyFiles: FileCollection
get() = variant.compileDependencyFiles
override val languageSettings: LanguageSettingsBuilder
get() = variant.languageSettings
override val platformType: KotlinPlatformType
get() = variant.platformType
override val moduleName: String
get() = // TODO accurate module names that don't rely on all variants having a main counterpart
variant.containingModule.project.pm20Extension.modules
.getByName(KotlinGradleModule.MAIN_MODULE_NAME).variants.findByName(variant.name)?.ownModuleName() ?: ownModuleName
override val ownModuleName: String
get() = variant.ownModuleName()
// TODO pull out to the variant
override val kotlinOptions: KotlinJvmOptions
get() = KotlinJvmOptionsImpl()
}
internal fun KotlinGradleVariant.ownModuleName(): String {
val project = containingModule.project
val baseName = project.convention.findPlugin(BasePluginConvention::class.java)?.archivesBaseName
?: project.name
val suffix = if (containingModule.moduleClassifier == null) "" else "_${containingModule.moduleClassifier}"
return filterModuleName("$baseName$suffix")
}
@@ -0,0 +1,122 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.artifacts.Configuration
import org.gradle.api.attributes.Usage
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
import org.jetbrains.kotlin.gradle.plugin.mpp.sourcesJarTask
import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
import org.jetbrains.kotlin.project.model.refinesClosure
abstract class AbstractKotlinGradleVariantFactory<T : KotlinGradleVariant>(
module: KotlinGradleModule
) : AbstractKotlinGradleFragmentFactory<T>(module) {
override fun create(name: String): T = super.create(name).also { fragment ->
createSourcesArchiveTask(fragment)
configureKotlinCompilation(fragment)
createElementsConfigurations(fragment)
// TODO configure resources processing
}
protected open fun setPlatformAttributesInConfiguration(fragment: T, configuration: Configuration) {
configuration.attributes.attribute(KotlinPlatformType.attribute, fragment.platformType)
}
open fun configureCompileResolvableConfiguration(fragment: T, configuration: Configuration) {
setPlatformAttributesInConfiguration(fragment, configuration)
configuration.attributes.attribute(Usage.USAGE_ATTRIBUTE, KotlinUsages.consumerApiUsage(project, fragment.platformType))
}
open fun configureApiElementsConfiguration(fragment: T, configuration: Configuration) {
setPlatformAttributesInConfiguration(fragment, configuration)
configuration.attributes.attribute(Usage.USAGE_ATTRIBUTE, KotlinUsages.producerApiUsage(project, fragment.platformType))
}
abstract fun configureKotlinCompilation(fragment: T)
open fun createSourcesArchiveTask(fragment: T) {
sourcesJarTask(
project,
lazy { fragment.refinesClosure.associate { it.disambiguateName("") to project.files(it.kotlinSourceRoots) } },
fragment.name,
fragment.name.toLowerCase()
)
}
override fun createDependencyConfigurations(fragment: T) {
super.createDependencyConfigurations(fragment)
fragment.compileDependencyFiles = project.configurations.create(fragment.compileDependencyConfigurationName).apply {
isCanBeConsumed = false
isCanBeResolved = true
configureCompileResolvableConfiguration(fragment, this@apply)
project.addExtendsFromRelation(name, fragment.transitiveApiConfigurationName)
project.addExtendsFromRelation(name, fragment.transitiveImplementationConfigurationName)
}
// FIXME runtime classpath if supported
}
open fun createElementsConfigurations(fragment: T) {
project.configurations.maybeCreate(fragment.apiElementsConfigurationName).apply {
isCanBeResolved = false
isCanBeConsumed = false
module.ifMadePublic {
isCanBeConsumed = true
// FIXME set capability
}
attributes.attribute<Usage>(Usage.USAGE_ATTRIBUTE, KotlinUsages.producerApiUsage(project, fragment.platformType))
extendsFrom(project.configurations.getByName(fragment.transitiveApiConfigurationName))
// FIXME + compileOnly
configureApiElementsConfiguration(fragment, this@apply)
}
}
}
abstract class AbstractKotlinGradleVariantWithRuntimeDependenciesFactory<T : KotlinGradleVariantWithRuntimeDependencies>(module: KotlinGradleModule) :
AbstractKotlinGradleVariantFactory<T>(module) {
open fun configureRuntimeResolvableConfiguration(fragment: T, configuration: Configuration) {
setPlatformAttributesInConfiguration(fragment, configuration)
configuration.attributes.attribute(Usage.USAGE_ATTRIBUTE, KotlinUsages.consumerRuntimeUsage(project, fragment.platformType))
}
open fun configureRuntimeElementsConfiguration(fragment: T, configuration: Configuration) {
setPlatformAttributesInConfiguration(fragment, configuration)
configuration.attributes.attribute(Usage.USAGE_ATTRIBUTE, KotlinUsages.producerRuntimeUsage(project, fragment.platformType))
}
override fun createDependencyConfigurations(fragment: T) {
super.createDependencyConfigurations(fragment)
fragment.runtimeDependencyFiles = project.configurations.create(fragment.runtimeDependencyConfigurationName).apply {
isCanBeConsumed = false
isCanBeResolved = true
configureCompileResolvableConfiguration(fragment, this@apply)
project.addExtendsFromRelation(name, fragment.transitiveApiConfigurationName)
project.addExtendsFromRelation(name, fragment.transitiveImplementationConfigurationName)
}
}
override fun createElementsConfigurations(fragment: T) {
super.createElementsConfigurations(fragment)
project.configurations.maybeCreate(fragment.runtimeElementsConfigurationName).apply {
isCanBeResolved = false
isCanBeConsumed = false
module.ifMadePublic {
isCanBeConsumed = true
// FIXME set capability
}
configureRuntimeElementsConfiguration(fragment, this@apply)
extendsFrom(project.configurations.getByName(fragment.transitiveApiConfigurationName))
extendsFrom(project.configurations.getByName(fragment.transitiveImplementationConfigurationName))
// FIXME + runtimeOnly
}
}
}
@@ -0,0 +1,74 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationOutput
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultKotlinCompilationOutput
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.fromPlatform
import org.jetbrains.kotlin.gradle.tasks.withType
import org.jetbrains.kotlin.project.model.KotlinAttributeKey
import org.jetbrains.kotlin.project.model.KotlinModuleVariant
import org.jetbrains.kotlin.project.model.KotlinPlatformTypeAttribute
abstract class KotlinGradleVariant(
containingModule: KotlinGradleModule,
override val fragmentName: String
) : KotlinGradleFragment(containingModule, fragmentName), KotlinModuleVariant {
abstract val platformType: KotlinPlatformType
override val variantAttributes: Map<KotlinAttributeKey, String>
get() = mapOf(KotlinPlatformTypeAttribute to KotlinPlatformTypeAttribute.fromPlatform(platformType)) // TODO user attributes
// TODO generalize with KotlinCompilation?
val compileDependencyConfigurationName: String
get() = disambiguateName("CompileDependencies")
open lateinit var compileDependencyFiles: FileCollection
// TODO rewrite using our own artifacts API?
val compilationOutputs: KotlinCompilationOutput =
DefaultKotlinCompilationOutput(
project,
project.provider { project.buildDir.resolve("processedResources/${containingModule.name}/${fragmentName}") }
)
// TODO rewrite using our own artifacts API
open val sourceArchiveTask: TaskProvider<AbstractArchiveTask>
get() = project.tasks.withType<AbstractArchiveTask>().named(defaultSourceArtifactTaskName)
// TODO generalize exposing outputs: what if a variant has more than one such configurations or none?
val apiElementsConfigurationName: String
get() = disambiguateName("apiElements")
}
// TODO: rewrite with the artifacts API
internal val KotlinGradleVariant.defaultSourceArtifactTaskName: String
get() = disambiguateName("sourcesJar")
abstract class KotlinGradleVariantWithRuntimeDependencies(
containingModule: KotlinGradleModule,
fragmentName: String
) : KotlinGradleVariant(containingModule, fragmentName) {
// TODO deduplicate with KotlinCompilation?
val runtimeDependencyConfigurationName: String
get() = disambiguateName("RuntimeDependencies")
open lateinit var runtimeDependencyFiles: FileCollection
open val runtimeFiles: ConfigurableFileCollection by lazy {
project.files(compilationOutputs.allOutputs, runtimeDependencyFiles)
}
// TODO generalize exposing outputs: what if a variant has more than one such configurations or none?
val runtimeElementsConfigurationName: String
get() = disambiguateName("runtimeElements")
}
@@ -0,0 +1,66 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.NamedDomainObjectFactory
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.plugin.sources.METADATA_CONFIGURATION_NAME_SUFFIX
import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.project.model.KotlinModuleFragment
import java.io.File
abstract class AbstractKotlinGradleFragmentFactory<T : KotlinGradleFragment>(
protected val module: KotlinGradleModule
) : NamedDomainObjectFactory<T> {
protected val project: Project
get() = module.project
abstract fun instantiateFragment(name: String): T
override fun create(name: String): T =
instantiateFragment(name).apply {
createDependencyConfigurations(this)
addDefaultSourceDirectories(this)
}
protected open fun createDependencyConfigurations(fragment: T) {
with(project.configurations) {
fragment.relatedConfigurationNames.forEach { configurationName ->
maybeCreate(configurationName).apply {
// FIXME add metadata configurations?
if (!configurationName.endsWith(METADATA_CONFIGURATION_NAME_SUFFIX)) {
isCanBeResolved = false
}
isCanBeConsumed = false
}
}
listOf(
fragment.apiConfigurationName to fragment.transitiveApiConfigurationName,
fragment.implementationConfigurationName to fragment.transitiveImplementationConfigurationName
).forEach { (configuration, transitiveConfiguration) ->
project.addExtendsFromRelation(transitiveConfiguration, configuration)
}
}
}
protected open fun addDefaultSourceDirectories(fragment: KotlinGradleFragment) {
fragment.kotlinSourceRoots.srcDir(defaultSourceFolder(project, module.name, fragment.fragmentName, "kotlin"))
// TODO handle resources
}
companion object {
fun defaultSourceFolder(project: Project, moduleName: String, fragmentName: String, type: String): File {
return project.file("src/${lowerCamelCaseName(fragmentName, moduleName)}/$type")
}
}
}
class CommonGradleFragmentFactory(module: KotlinGradleModule) : AbstractKotlinGradleFragmentFactory<KotlinGradleFragment>(module) {
override fun instantiateFragment(name: String): KotlinGradleFragment =
project.objects.newInstance(KotlinGradleFragment::class.java, module, name)
}
@@ -0,0 +1,86 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.*
import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.plugins.BasePluginConvention
import org.gradle.api.tasks.TaskProvider
import org.gradle.jvm.tasks.Jar
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
import org.jetbrains.kotlin.gradle.dsl.pm20Extension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
import org.jetbrains.kotlin.gradle.utils.dashSeparatedName
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.project.model.*
import org.jetbrains.kotlin.project.model.utils.variantsContainingFragment
import java.util.concurrent.Callable
//region Fragment
//endregion Fragment
//region Variant
open class KotlinJvmVariantFactory(module: KotlinGradleModule) :
AbstractKotlinGradleVariantWithRuntimeDependenciesFactory<KotlinJvmVariant>(module) {
override fun instantiateFragment(name: String) = KotlinJvmVariant(module, name)
// FIXME expose the JAR with the artifacts API
private fun getOrCreateJarTask(fragment: KotlinJvmVariant): TaskProvider<Jar> {
val jarTaskName = fragment.disambiguateName("jar")
return project.locateOrRegisterTask(jarTaskName) {
it.from(fragment.compilationOutputs.allOutputs)
it.archiveClassifier.set(dashSeparatedName(fragment.name, module.moduleClassifier))
}
}
override fun createElementsConfigurations(fragment: KotlinJvmVariant) {
super.createElementsConfigurations(fragment)
listOf(fragment.apiElementsConfigurationName, fragment.runtimeElementsConfigurationName).forEach {
project.artifacts.add(it, getOrCreateJarTask(fragment))
}
}
override fun configureKotlinCompilation(fragment: KotlinJvmVariant) {
val compilationData = KotlinJvmVariantCompilationData(fragment)
val classesTaskName = compilationData.compileAllTaskName
project.tasks.register(classesTaskName) { classesTask ->
classesTask.dependsOn(fragment.compilationOutputs.allOutputs)
}
Kotlin2JvmSourceSetProcessor(KotlinTasksProvider(), compilationData, project.getKotlinPluginVersion() ?: "unknown"/*TODO*/).run()
val allSources = { project.files(Callable { fragment.refinesClosure.map { it.kotlinSourceRoots } }) }
val commonSources = {
project.files(Callable {
fragment.refinesClosure.filter { module.variantsContainingFragment(it).count() > 1 }.map { it.kotlinSourceRoots }
})
}
addSourcesToKotlinCompileTask(
project, compilationData.compileKotlinTaskName, /*FIXME*/ emptyList(), allSources,
addAsCommonSources = lazyOf(false)
)
addSourcesToKotlinCompileTask(
project, compilationData.compileKotlinTaskName, /*FIXME*/ emptyList(), commonSources,
addAsCommonSources = lazyOf(true)
)
}
}
//endregion Variant
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util
import org.gradle.api.capabilities.Capability
import org.gradle.api.provider.Provider
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleModule
internal class LazyCapability(
val groupProvider: Provider<String>,
val nameValue: String,
val versionProvider: Provider<String>,
val suffix: String?
) : Capability {
override fun getGroup(): String = groupProvider.get()
override fun getName(): String = nameValue + suffix?.let { "..$it" }.orEmpty()
override fun getVersion(): String? = versionProvider.get()
companion object {
fun fromModule(module: KotlinGradleModule): LazyCapability {
val project = module.project
return LazyCapability(
project.provider { project.group.toString() },
project.name,
project.provider { project.version.toString() },
module.moduleClassifier
)
}
}
}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.plugin.sources
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope.*
@@ -26,7 +27,7 @@ internal enum class KotlinDependencyScope(val scopeName: String) {
}
}
internal fun Project.sourceSetDependencyConfigurationByScope(sourceSet: KotlinSourceSet, scope: KotlinDependencyScope): Configuration =
internal fun Project.sourceSetDependencyConfigurationByScope(sourceSet: HasKotlinDependencies, scope: KotlinDependencyScope): Configuration =
project.configurations.getByName(
when (scope) {
API_SCOPE -> sourceSet.apiConfigurationName
@@ -99,7 +99,7 @@ open class KotlinJsCompilation(
private fun disambiguateNameInPlatform(simpleName: String): String {
return lowerCamelCaseName(
disambiguationClassifierInPlatform,
compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
simpleName
)
}
@@ -111,7 +111,7 @@ open class KotlinJsCompilation(
target.irTarget?.let {
target.disambiguationClassifierInPlatform
} ?: target.disambiguationClassifier,
compilationName
compilationPurpose
)
}
}
@@ -50,7 +50,7 @@ open class KotlinJsTargetConfigurator(kotlinPluginVersion: String) :
}
override fun buildCompilationProcessor(compilation: KotlinJsCompilation): KotlinSourceSetProcessor<*> {
val tasksProvider = KotlinTasksProvider(compilation.target.targetName)
val tasksProvider = KotlinTasksProvider()
return Kotlin2JsSourceSetProcessor(tasksProvider, compilation, kotlinPluginVersion)
}
@@ -36,7 +36,7 @@ class KotlinJsIrCompilation(
target.disambiguationClassifierInPlatform
else
target.disambiguationClassifier,
compilationName
compilationPurpose
)
}
}
@@ -54,7 +54,7 @@ open class KotlinJsIrTargetConfigurator(kotlinPluginVersion: String) :
}
override fun buildCompilationProcessor(compilation: KotlinJsIrCompilation): KotlinSourceSetProcessor<*> {
val tasksProvider = KotlinTasksProvider(compilation.target.targetName)
val tasksProvider = KotlinTasksProvider()
return KotlinJsIrSourceSetProcessor(tasksProvider, compilation, kotlinPluginVersion)
}
@@ -93,7 +93,7 @@ constructor(
val compilationId: String by lazy {
compilation.let {
val target = it.target
target.project.path + "@" + target.name + ":" + it.compilationName
target.project.path + "@" + target.name + ":" + it.compilationPurpose
}
}
@@ -62,7 +62,7 @@ constructor(
val compilationId: String by lazy {
compilation.let {
val target = it.target
target.project.path + "@" + target.name + ":" + it.compilationName
target.project.path + "@" + target.name + ":" + it.compilationPurpose
}
}
@@ -35,7 +35,7 @@ open class KotlinJvmCompilation(
get() = if (target.withJavaEnabled) {
val project = target.project
val javaSourceSets = project.convention.getPlugin(JavaPluginConvention::class.java).sourceSets
val javaSourceSet = javaSourceSets.getByName(compilationName)
val javaSourceSet = javaSourceSets.getByName(compilationPurpose)
project.tasks.withType(JavaCompile::class.java).named(javaSourceSet.compileJavaTaskName)
} else null
}
@@ -73,7 +73,7 @@ class KotlinJvmTargetConfigurator(kotlinPluginVersion: String) :
}
override fun buildCompilationProcessor(compilation: KotlinJvmCompilation): KotlinSourceSetProcessor<*> {
val tasksProvider = KotlinTasksProvider(compilation.target.targetName)
val tasksProvider = KotlinTasksProvider()
return Kotlin2JvmSourceSetProcessor(tasksProvider, compilation, kotlinPluginVersion)
}
}
@@ -36,7 +36,7 @@ class KotlinJvmWithJavaTargetPreset(
}
AbstractKotlinPlugin.configureTarget(target) { compilation ->
Kotlin2JvmSourceSetProcessor(KotlinTasksProvider(name), compilation, kotlinPluginVersion)
Kotlin2JvmSourceSetProcessor(KotlinTasksProvider(), compilation, kotlinPluginVersion)
}
target.compilations.getByName("test").run {
@@ -110,7 +110,7 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
override fun buildCompilationProcessor(compilation: AbstractKotlinCompilation<*>): KotlinCompilationProcessor<*> = when (compilation) {
is KotlinCommonCompilation -> {
val tasksProvider = KotlinTasksProvider(compilation.target.targetName)
val tasksProvider = KotlinTasksProvider()
KotlinCommonSourceSetProcessor(compilation, tasksProvider, kotlinPluginVersion)
}
is KotlinSharedNativeCompilation -> NativeSharedCompilationProcessor(compilation)
@@ -57,7 +57,7 @@ open class DefaultCInteropSettings @Inject constructor(
val interopProcessingTaskName: String
get() = lowerCamelCaseName(
"cinterop",
compilation.compilationName.takeIf { it != "main" }.orEmpty(),
compilation.compilationPurpose.takeIf { it != "main" }.orEmpty(),
name,
target.disambiguationClassifier
)
@@ -9,7 +9,6 @@ package org.jetbrains.kotlin.gradle.plugin.mpp
import groovy.lang.Closure
import org.gradle.api.Action
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.TaskProvider
import org.gradle.util.ConfigureUtil
@@ -77,9 +76,6 @@ class KotlinNativeCompilation(
) : AbstractKotlinNativeCompilation(target, konanTarget, name),
KotlinCompilationWithResources<KotlinCommonOptions> {
private val project: Project
get() = target.project
// Interop DSL.
val cinterops = project.container(DefaultCInteropSettings::class.java) { cinteropName ->
DefaultCInteropSettings(project, cinteropName, this)
@@ -95,15 +91,15 @@ class KotlinNativeCompilation(
override val compileDependencyConfigurationName: String
get() = lowerCamelCaseName(
target.disambiguationClassifier,
compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(),
compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(),
"compileKlibraries"
)
override val compileAllTaskName: String
get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName, "klibrary")
get() = lowerCamelCaseName(target.disambiguationClassifier, compilationPurpose, "klibrary")
val binariesTaskName: String
get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName, "binaries")
get() = lowerCamelCaseName(target.disambiguationClassifier, compilationPurpose, "binaries")
override fun addAssociateCompilationDependencies(other: KotlinCompilation<*>) {
with(target.project) {
@@ -30,7 +30,9 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptionsImpl
import org.jetbrains.kotlin.gradle.dsl.fillDefaultValues
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation
import org.jetbrains.kotlin.gradle.utils.getValue
import org.jetbrains.kotlin.gradle.plugin.sources.resolveAllDependsOnSourceSets
@@ -78,19 +80,25 @@ open class KotlinCompileCommon : AbstractKotlinCompile<K2MetadataCompilerArgumen
}
private fun outputPathsFromMetadataCompilationsOf(sourceSets: Iterable<KotlinSourceSet>): List<File> {
val target = taskData.compilation.target
return sourceSets
.mapNotNull { sourceSet -> target.compilations.findByName(sourceSet.name)?.output?.classesDirs }
.flatten()
val target = taskData.compilation.owner
return when (target) {
is KotlinTarget -> sourceSets
.mapNotNull { sourceSet -> target.compilations.findByName(sourceSet.name)?.output?.classesDirs }
.flatten()
else -> error("unexpected compilation owner") // FIXME support PM20 variant
}
}
private val defaultKotlinSourceSet: KotlinSourceSet
get() = taskData.compilation.defaultSourceSet
@get:PathSensitive(PathSensitivity.RELATIVE)
@get:InputFiles
internal val refinesMetadataPaths by project.provider {
outputPathsFromMetadataCompilationsOf(defaultKotlinSourceSet.resolveAllDependsOnSourceSets())
when (val compilation = taskData.compilation) {
is KotlinCompilation<*> -> {
val defaultKotlinSourceSet: KotlinSourceSet = compilation.defaultSourceSet
outputPathsFromMetadataCompilationsOf(defaultKotlinSourceSet.resolveAllDependsOnSourceSets())
}
else -> error("unexpected compilation type") // FIXME support PM20 variant
}
}
override fun callCompilerAsync(args: K2MetadataCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) {
@@ -42,7 +42,6 @@ import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.COMPILER_CLASSPATH_CONFIGURATION_NAME
import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.associateWithTransitiveClosure
import org.jetbrains.kotlin.gradle.plugin.mpp.ownModuleName
import org.jetbrains.kotlin.gradle.report.ReportingSettings
import org.jetbrains.kotlin.gradle.targets.js.ir.isProduceUnzippedKlib
import org.jetbrains.kotlin.gradle.utils.*
@@ -216,7 +215,9 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
@get:InputFiles
@get:Classpath
open val pluginClasspath: FileCollection by project.provider {
project.configurations.getByName(taskData.compilation.pluginConfigurationName)
// FIXME support compiler plugins with PM20
(taskData.compilation as? KotlinCompilation<*>?)?.pluginConfigurationName?.let(project.configurations::getByName)
?: project.files()
}
@get:Internal
@@ -253,7 +254,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
@get:Internal
@field:Transient
internal val kotlinExtProvider: KotlinProjectExtension = project.extensions.findByType(KotlinProjectExtension::class.java)!!
internal val kotlinExtProvider: KotlinTopLevelExtension = project.extensions.findByType(KotlinTopLevelExtension::class.java)!!
override fun getDestinationDir(): File =
taskData.destinationDir.get()
@@ -293,7 +294,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
@get:Internal
internal val sourceSetName: String
get() = taskData.compilation.name
get() = taskData.compilation.compilationPurpose
@get:InputFiles
@get:PathSensitive(PathSensitivity.RELATIVE)
@@ -308,7 +309,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
val friendPaths: FileCollection = project.files(
project.provider {
taskData.compilation.run {
if (this !is AbstractKotlinCompilation<*>) return@run project.files()
if (this !is AbstractKotlinCompilation<*>) return@run project.files() // FIXME support PM20
mutableListOf<FileCollection>().also { allCollections ->
associateWithTransitiveClosure.forEach { allCollections.add(it.output.classesDirs) }
allCollections.add(friendArtifacts)
@@ -398,7 +399,9 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
internal abstract fun callCompilerAsync(args: T, sourceRoots: SourceRoots, changedFiles: ChangedFiles)
@get:Input
internal val isMultiplatform: Boolean by lazy { project.plugins.any { it is KotlinPlatformPluginBase || it is KotlinMultiplatformPluginWrapper } }
internal val isMultiplatform: Boolean by lazy {
project.plugins.any { it is KotlinPlatformPluginBase || it is KotlinMultiplatformPluginWrapper || it is KotlinPm20PluginWrapper }
}
@get:Internal
internal val abstractKotlinCompileArgumentsContributor by lazy {
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.mapKotlinTaskProperties
import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.plugin.runOnceAfterEvaluated
import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinOptions
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrLink
@@ -80,11 +81,11 @@ internal inline fun <reified T : Task> Project.locateOrRegisterTask(name: String
return project.locateTask(name) ?: project.registerTask(name, T::class.java, body = body)
}
internal open class KotlinTasksProvider(val targetName: String) {
internal open class KotlinTasksProvider {
open fun registerKotlinJVMTask(
project: Project,
name: String,
compilation: KotlinCompilation<*>,
compilation: KotlinCompilationData<*>,
configureAction: (KotlinCompile) -> (Unit)
): TaskProvider<out KotlinCompile> {
val properties = PropertiesProvider(project)
@@ -99,7 +100,7 @@ internal open class KotlinTasksProvider(val targetName: String) {
fun registerKotlinJSTask(
project: Project,
name: String,
compilation: KotlinCompilation<*>,
compilation: KotlinCompilationData<*>,
configureAction: (Kotlin2JsCompile) -> Unit
): TaskProvider<out Kotlin2JsCompile> {
val properties = PropertiesProvider(project)
@@ -114,7 +115,7 @@ internal open class KotlinTasksProvider(val targetName: String) {
fun registerKotlinJsIrTask(
project: Project,
name: String,
compilation: KotlinCompilation<*>,
compilation: KotlinCompilationData<*>,
configureAction: (KotlinJsIrLink) -> Unit
): TaskProvider<out KotlinJsIrLink> {
val properties = PropertiesProvider(project)
@@ -129,7 +130,7 @@ internal open class KotlinTasksProvider(val targetName: String) {
fun registerKotlinCommonTask(
project: Project,
name: String,
compilation: KotlinCompilation<*>,
compilation: KotlinCompilationData<*>,
configureAction: (KotlinCompileCommon) -> (Unit)
): TaskProvider<out KotlinCompileCommon> {
val properties = PropertiesProvider(project)
@@ -145,13 +146,13 @@ internal open class KotlinTasksProvider(val targetName: String) {
kotlinTaskHolder: TaskProvider<out AbstractKotlinCompile<*>>,
project: Project,
propertiesProvider: PropertiesProvider,
compilation: KotlinCompilation<*>
compilation: KotlinCompilationData<*>
) {
project.runOnceAfterEvaluated("apply properties and language settings to ${kotlinTaskHolder.name}", kotlinTaskHolder) {
propertiesProvider.mapKotlinTaskProperties(kotlinTaskHolder.get())
applyLanguageSettingsToKotlinOptions(
compilation.defaultSourceSet.languageSettings,
compilation.languageSettings,
(kotlinTaskHolder.get() as org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>).kotlinOptions
)
}
@@ -161,12 +162,12 @@ internal open class KotlinTasksProvider(val targetName: String) {
if (properties.parallelTasksInProject != true) Task::class.java else WorkersTask::class.java
}
internal class AndroidTasksProvider(targetName: String) : KotlinTasksProvider(targetName) {
internal class AndroidTasksProvider : KotlinTasksProvider() {
override fun configure(
kotlinTaskHolder: TaskProvider<out AbstractKotlinCompile<*>>,
project: Project,
propertiesProvider: PropertiesProvider,
compilation: KotlinCompilation<*>
compilation: KotlinCompilationData<*>
) {
super.configure(kotlinTaskHolder, project, propertiesProvider, compilation)
kotlinTaskHolder.configure {
@@ -10,21 +10,22 @@ import org.gradle.api.plugins.ExtraPropertiesExtension
import org.gradle.api.provider.Property
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.utils.getValue
import java.io.File
internal open class KotlinCompileTaskData(
val taskName: String,
@field:Transient // cannot be serialized for Gradle Instant Execution, but actually is not needed when a task is deserialized
val compilation: KotlinCompilation<*>,
val compilation: KotlinCompilationData<*>,
val destinationDir: Property<File>,
val useModuleDetection: Property<Boolean>
) {
private val project: Project
get() = compilation.target.project
get() = compilation.project
private val taskBuildDirectory: File by project.provider {
File(File(compilation.target.project.buildDir, KOTLIN_BUILD_DIR_NAME), taskName)
File(File(compilation.project.buildDir, KOTLIN_BUILD_DIR_NAME), taskName)
}
//TODO
@@ -42,9 +43,9 @@ internal open class KotlinCompileTaskData(
fun register(
taskName: String,
compilation: KotlinCompilation<*>
compilation: KotlinCompilationData<*>
): KotlinCompileTaskData {
val project = compilation.target.project
val project = compilation.project
val container = project.getTaskDataMap()
@Suppress("UnstableApiUsage")
@@ -0,0 +1 @@
implementation-class=org.jetbrains.kotlin.gradle.plugin.KotlinPm20PluginWrapper
@@ -17,13 +17,12 @@ interface KotlinModuleFragment {
// TODO: scopes
val declaredModuleDependencies: Iterable<KotlinModuleDependency>
// TODO: should this be source roots or source files?
val kotlinSourceRoots: Iterable<File>
}
interface KotlinModuleVariant : KotlinModuleFragment {
val variantAttributes: Map<KotlinAttributeKey, String>
var isExported: Boolean
}
val KotlinModuleFragment.fragmentAttributeSets: Map<KotlinAttributeKey, Set<String>>
@@ -65,7 +64,6 @@ class BasicKotlinModuleVariant(
containingModule,
fragmentName
), KotlinModuleVariant {
override var isExported: Boolean = true
override val variantAttributes: MutableMap<KotlinAttributeKey, String> = mutableMapOf()
override fun toString(): String = "variant $fragmentName"
}
@@ -9,7 +9,7 @@ class MatchVariantsByExactAttributes : ModuleVariantResolver {
override fun getChosenVariant(requestingVariant: KotlinModuleVariant, dependencyModule: KotlinModule): VariantResolution {
val candidates = dependencyModule.variants
return candidates.filter { candidate ->
candidate.isExported && candidate.variantAttributes.all { (attributeKey, candidateValue) ->
candidate.variantAttributes.all { (attributeKey, candidateValue) ->
attributeKey !in requestingVariant.variantAttributes.keys ||
candidateValue == requestingVariant.variantAttributes.getValue(attributeKey)
}