[Gradle] Remove Gradle KPM implementation

KT-61463
This commit is contained in:
Sebastian Sellmair
2023-08-25 15:32:55 +02:00
committed by Space Team
parent 34abc008ec
commit 282d2f4454
115 changed files with 52 additions and 7209 deletions
@@ -20,8 +20,6 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPro
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
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrSingleTargetPreset
@@ -31,7 +29,6 @@ import org.jetbrains.kotlin.gradle.utils.castIsolatedKotlinPluginClassLoaderAwar
import org.jetbrains.kotlin.gradle.utils.configureExperimentalTryK2
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.statistics.metrics.StringMetrics
import javax.inject.Inject
import kotlin.reflect.KClass
@@ -65,12 +62,6 @@ internal val Project.multiplatformExtensionOrNull: KotlinMultiplatformExtension?
internal val Project.multiplatformExtension: KotlinMultiplatformExtension
get() = extensions.getByName(KOTLIN_PROJECT_EXTENSION_NAME).castIsolatedKotlinPluginClassLoaderAware()
internal val Project.pm20Extension: KotlinPm20ProjectExtension
get() = extensions.getByName(KOTLIN_PROJECT_EXTENSION_NAME).castIsolatedKotlinPluginClassLoaderAware()
internal val Project.pm20ExtensionOrNull: KotlinPm20ProjectExtension?
get() = extensions.findByName(KOTLIN_PROJECT_EXTENSION_NAME)?.castIsolatedKotlinPluginClassLoaderAware()
abstract class KotlinTopLevelExtension(internal val project: Project) : KotlinTopLevelExtensionConfig {
override lateinit var coreLibrariesVersion: String
@@ -14,8 +14,6 @@ import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmModule
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20ProjectExtension
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
@@ -36,8 +34,6 @@ internal fun Project.configureKotlinDomApiDefaultDependency(
coreLibrariesVersion: Provider<String>
) {
when (topLevelExtension) {
is KotlinPm20ProjectExtension -> addKotlinDomApiToKpmProject(project, coreLibrariesVersion)
is KotlinJsProjectExtension -> topLevelExtension.registerTargetObserver { target ->
target?.addKotlinDomApiDependency(configurations, dependencies, coreLibrariesVersion)
}
@@ -54,26 +50,6 @@ internal fun Project.configureKotlinDomApiDefaultDependency(
}
}
private fun addKotlinDomApiToKpmProject(
project: Project,
coreLibrariesVersion: Provider<String>
) {
project.pm20Extension.modules.named(GradleKpmModule.MAIN_MODULE_NAME) { main ->
main.variants.configureEach { variant ->
when (variant.platformType) {
KotlinPlatformType.common -> error("variants are not expected to be common")
KotlinPlatformType.js -> {
val dependencyHandler = project.dependencies
variant.dependencies {
api(dependencyHandler.kotlinDomApiDependency(coreLibrariesVersion.get()))
}
}
else -> {}
}
}
}
}
private fun KotlinTarget.addKotlinDomApiDependency(
configurations: ConfigurationContainer,
dependencies: DependencyHandler,
@@ -39,13 +39,13 @@ internal class Kotlin2JsSourceSetProcessor(
it.dependsOn(kotlinTask)
}
compilationInfo.tcsOrNull?.compilation?.run { this as? KotlinWithJavaCompilation<*, *> }?.javaSourceSet?.clearJavaSrcDirs()
compilationInfo.tcs.compilation.run { this as? KotlinWithJavaCompilation<*, *> }?.javaSourceSet?.clearJavaSrcDirs()
project.whenEvaluated {
val subpluginEnvironment: SubpluginEnvironment = SubpluginEnvironment.loadSubplugins(project)
/* Not supported in KPM */
compilationInfo.tcsOrNull?.compilation?.let { compilation ->
compilationInfo.tcs.compilation.let { compilation ->
subpluginEnvironment.addSubpluginOptions(project, compilation)
}
}
@@ -57,7 +57,7 @@ internal class Kotlin2JvmSourceSetProcessor(
project.launchInStage(AfterEvaluateBuildscript) {
val subpluginEnvironment = SubpluginEnvironment.loadSubplugins(project)
/* Not supported in KPM yet */
compilationInfo.tcsOrNull?.compilation?.let { compilation ->
compilationInfo.tcs.compilation.let { compilation ->
subpluginEnvironment.addSubpluginOptions(project, compilation)
}
@@ -25,7 +25,7 @@ internal class KotlinCommonSourceSetProcessor(
project.tasks.named(compilationInfo.compileAllTaskName).dependsOn(kotlinTask)
// can be missing (e.g. in case of tests)
if (compilationInfo.isMain) {
compilationInfo.tcsOrNull?.compilation?.target?.let { target ->
compilationInfo.tcs.compilation.target.let { target ->
project.locateTask<Task>(target.artifactsTaskName)?.dependsOn(kotlinTask)
}
}
@@ -33,7 +33,7 @@ internal class KotlinCommonSourceSetProcessor(
project.whenEvaluated {
val subpluginEnvironment: SubpluginEnvironment = SubpluginEnvironment.loadSubplugins(project)
/* Not supported in KPM yet */
compilationInfo.tcsOrNull?.compilation?.let { compilation ->
compilationInfo.tcs.compilation.let { compilation ->
subpluginEnvironment.addSubpluginOptions(project, compilation)
}
}
@@ -14,12 +14,8 @@ import org.gradle.api.file.SourceDirectorySet
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.internal
import org.jetbrains.kotlin.gradle.plugin.mpp.isMain
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmAbstractFragmentMetadataCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmModule
import org.jetbrains.kotlin.gradle.plugin.sources.dependsOnClosure
import org.jetbrains.kotlin.gradle.utils.filesProvider
import org.jetbrains.kotlin.gradle.utils.toSetOrEmpty
import org.jetbrains.kotlin.project.model.LanguageSettings
internal sealed class KotlinCompilationInfo {
@@ -101,88 +97,11 @@ internal sealed class KotlinCompilationInfo {
return displayName
}
}
class KPM(val compilationData: GradleKpmCompilationData<*>) : KotlinCompilationInfo() {
override val origin: GradleKpmCompilationData<*> = compilationData
override val project: Project
get() = origin.project
override val platformType: KotlinPlatformType
get() = origin.platformType
override val targetDisambiguationClassifier: String?
get() = origin.compilationClassifier
override val compilationName: String
get() = origin.compilationPurpose
override val moduleName: String
get() = origin.moduleName
override val compilerOptions: HasCompilerOptions<*>
get() = origin.compilerOptions
override val compileKotlinTaskName: String
get() = origin.compileKotlinTaskName
override val compileAllTaskName: String
get() = origin.compileAllTaskName
override val languageSettings: LanguageSettings
get() = origin.languageSettings
override val friendPaths: FileCollection
get() = project.filesProvider { origin.friendPaths }
override val refinesPaths: FileCollection
get() = project.filesProvider files@{
val compilationData = origin as? GradleKpmAbstractFragmentMetadataCompilationData<*> ?: return@files emptyList<Any>()
val fragment = compilationData.fragment
fragment.refinesClosure.minus(fragment).map {
val compilation = compilationData.metadataCompilationRegistry.getForFragmentOrNull(it) ?: return@map project.files()
compilation.output.classesDirs
}
}
override val isMain: Boolean
get() = origin.compilationPurpose == GradleKpmModule.MAIN_MODULE_NAME
override val classesDirs: ConfigurableFileCollection
get() = origin.output.classesDirs
override val compileDependencyFiles: FileCollection
get() = project.filesProvider { origin.compileDependencyFiles }
override val sources: List<SourceDirectorySet>
get() = origin.kotlinSourceDirectoriesByFragmentName.values.toList()
override val displayName: String
get() = origin.toString()
override fun toString(): String {
return displayName
}
}
}
internal fun KotlinCompilationInfo(compilation: KotlinCompilation<*>): KotlinCompilationInfo.TCS {
return KotlinCompilationInfo.TCS(compilation)
}
internal val KotlinCompilationInfo.tcsOrNull: KotlinCompilationInfo.TCS?
get() = when (this) {
is KotlinCompilationInfo.KPM -> null
is KotlinCompilationInfo.TCS -> this
}
internal val KotlinCompilationInfo.tcs: KotlinCompilationInfo.TCS
get() = this as KotlinCompilationInfo.TCS
internal val KotlinCompilationInfo.kpmOrNull: KotlinCompilationInfo.KPM?
get() = when (this) {
is KotlinCompilationInfo.KPM -> this
is KotlinCompilationInfo.TCS -> null
}
@@ -39,7 +39,7 @@ internal class KotlinJsIrSourceSetProcessor(
it.dependsOn(kotlinTask)
}
val compilation = compilationInfo.tcsOrNull?.compilation as KotlinJsIrCompilation
val compilation = compilationInfo.tcs.compilation as KotlinJsIrCompilation
compilation.binaries
.withType(JsIrBinary::class.java)
@@ -60,7 +60,7 @@ internal class KotlinJsIrSourceSetProcessor(
project.whenEvaluated {
val subpluginEnvironment: SubpluginEnvironment = SubpluginEnvironment.loadSubplugins(project)
/* Not supported in KPM, yet */
compilationInfo.tcsOrNull?.compilation?.let { compilation ->
compilationInfo.tcs.compilation.let { compilation ->
subpluginEnvironment.addSubpluginOptions(project, compilation)
}
@@ -39,8 +39,6 @@ import org.jetbrains.kotlin.gradle.plugin.diagnostics.launchKotlinGradleProjectC
import org.jetbrains.kotlin.gradle.plugin.internal.*
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.BuildFlowService
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
@@ -404,21 +402,6 @@ abstract class AbstractKotlinMultiplatformPluginWrapper : KotlinBasePluginWrappe
get() = KotlinMultiplatformExtension::class
}
abstract class AbstractKotlinPm20PluginWrapper(
private val objectFactory: ObjectFactory,
) : KotlinBasePluginWrapper() {
override fun apply(project: Project) {
super.apply(project)
project.runMultiplatformAndroidGradlePluginCompatibilityHealthCheckWhenAndroidIsApplied()
}
override fun getPlugin(project: Project): Plugin<Project> =
objectFactory.newInstance(KotlinPm20GradlePlugin::class.java)
override val projectExtensionClass: KClass<out KotlinPm20ProjectExtension>
get() = KotlinPm20ProjectExtension::class
}
fun Project.getKotlinPluginVersion() = getKotlinPluginVersion(project.logger)
fun getKotlinPluginVersion(logger: Logger): String {
@@ -54,7 +54,7 @@ internal abstract class KotlinSourceSetProcessor<T : AbstractKotlinCompile<*>>(
// Related commit into Gradle: https://github.com/gradle/gradle/commit/758adc5b0c5a5d27e2797a9fa8fd2690530c5de9
// Proper workaround is peeked from here:
// https://github.com/gradle/gradle/blob/16cbc3a678771b08418d086eb67e9934c9282dfb/subprojects/plugins/src/main/java/org/gradle/api/plugins/internal/JvmPluginsHelper.java#L142-L148
if (compilationInfo.tcsOrNull?.compilation is KotlinWithJavaCompilation<*, *>) {
if (compilationInfo.tcs.compilation is KotlinWithJavaCompilation<*, *>) {
val kotlinSourceDirectorySet = compilationInfo.tcs.compilation.defaultSourceSet.kotlin
kotlinSourceDirectorySet.destinationDirectory.value(defaultKotlinDestinationDir)
task.configure {
@@ -93,7 +93,7 @@ internal abstract class KotlinSourceSetProcessor<T : AbstractKotlinCompile<*>>(
override fun run() {
doTargetSpecificProcessing()
if (compilationInfo.tcsOrNull?.compilation is KotlinWithJavaCompilation<*, *>) {
if (compilationInfo.tcs.compilation is KotlinWithJavaCompilation<*, *>) {
project.launch { addKotlinDirectoriesToJavaSourceSet() }
createAdditionalClassesTaskForIdeRunner()
}
@@ -113,7 +113,7 @@ internal abstract class KotlinSourceSetProcessor<T : AbstractKotlinCompile<*>>(
private fun createAdditionalClassesTaskForIdeRunner() {
val kotlinCompilation = compilationInfo.tcsOrNull?.compilation ?: return
val kotlinCompilation = compilationInfo.tcs.compilation
@DisableCachingByDefault(because = "Marker task for IDE sync")
open class IDEClassesTask : DefaultTask()
@@ -25,8 +25,6 @@ import org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers.IdeBinaryDepen
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationConfigurationsContainer
import org.jetbrains.kotlin.gradle.plugin.mpp.internal
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmFragment
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmVariant
import org.jetbrains.kotlin.gradle.plugin.mpp.resolvableMetadataConfiguration
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.sources.InternalKotlinSourceSet
@@ -12,8 +12,6 @@ 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.mpp.pm20.GradleKpmModule
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.ComputedCapability
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
@@ -71,17 +69,7 @@ class DefaultKotlinDependencyHandler(
configurationName: String,
dependencyNotation: Any
): Dependency? {
val dependency = when (dependencyNotation) {
is GradleKpmModule -> project.dependencies.create(dependencyNotation.project).apply {
(this as ModuleDependency).capabilities {
if (dependencyNotation.moduleClassifier != null) {
it.requireCapability(ComputedCapability.fromModule(dependencyNotation))
}
}
}
else -> dependencyNotation
}
return project.dependencies.add(configurationName, dependency)
return project.dependencies.add(configurationName, dependencyNotation)
}
private fun addDependencyByStringNotation(
@@ -1,352 +0,0 @@
/*
* Copyright 2010-2020 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
import org.gradle.api.Named
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ModuleDependency
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.artifacts.result.ResolvedComponentResult
import org.gradle.api.attributes.Attribute
import org.gradle.api.attributes.AttributeContainer
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.currentBuildId
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.representsProject
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.sources.getVisibleSourceSetsFromAssociateCompilations
import org.jetbrains.kotlin.gradle.plugin.sources.internal
import org.jetbrains.kotlin.gradle.utils.buildPathCompat
import org.jetbrains.kotlin.gradle.utils.getOrPutRootProjectProperty
import org.jetbrains.kotlin.project.model.*
class ProjectStructureMetadataModuleBuilder {
private val modulesCache = mutableMapOf<KpmModuleIdentifier, KpmModule>()
private fun buildModuleFromProjectStructureMetadata(
component: ResolvedComponentResult,
metadata: KotlinProjectStructureMetadata
): KpmModule {
val moduleData = KpmBasicModule(component.toSingleKpmModuleIdentifier()).apply {
metadata.sourceSetNamesByVariantName.keys.forEach { variantName ->
fragments.add(KpmBasicVariant(this@apply, variantName))
}
fun fragment(sourceSetName: String): KpmBasicFragment {
if (fragments.none { it.fragmentName == sourceSetName })
fragments.add(KpmBasicFragment(this@apply, sourceSetName))
return fragmentByName(sourceSetName)
}
metadata.sourceSetNamesByVariantName.forEach { (variantName, sourceSets) ->
val variant = fragmentByName(variantName)
sourceSets.forEach { sourceSetName ->
variant.declaredRefinesDependencies.add(fragment(sourceSetName))
}
}
metadata.sourceSetModuleDependencies.forEach { (sourceSetName, dependencies) ->
val fragment = fragment(sourceSetName)
dependencies.forEach { dependency ->
fragment.declaredModuleDependencies.add(
KpmModuleDependency(
KpmMavenModuleIdentifier(
dependency.groupId.orEmpty(),
dependency.moduleId,
null /* TODO */
)
)
)
}
}
metadata.sourceSetsDependsOnRelation.forEach { (depending, dependencies) ->
val dependingFragment = fragment(depending)
dependencies.forEach { dependency ->
dependingFragment.declaredRefinesDependencies.add(fragment(dependency))
}
}
}
return GradleKpmExternalImportedModule(
moduleData,
metadata,
moduleData.fragments.filterTo(mutableSetOf()) { it.fragmentName in metadata.hostSpecificSourceSets }
)
}
fun getModule(component: ResolvedComponentResult, projectStructureMetadata: KotlinProjectStructureMetadata): KpmModule {
val moduleId = component.toSingleKpmModuleIdentifier()
return modulesCache.getOrPut(moduleId) {
buildModuleFromProjectStructureMetadata(
component,
projectStructureMetadata
)
}
}
}
private fun detectModules(targets: Iterable<KotlinTarget>, sourceSets: Iterable<KotlinSourceSet>): Map<String, List<KotlinCompilation<*>>> {
// DSU-like approach: all compilations and source sets that are reachable via dependsOn edges are considered a single module
val compilations = targets.flatMap { it.compilations }
val dsu = mutableMapOf<Any, Any>().apply {
compilations.forEach { put(it, it) }
sourceSets.forEach { put(it, it) }
}
fun get(item: Any): Any =
dsu.getValue(item).let { leader -> if (leader === item) leader else get(leader).also { dsu[item] = it } }
fun union(item: Any, other: Any) = dsu.put(get(item), get(other))
sourceSets.forEach { sourceSet ->
sourceSet.dependsOn.forEach { other -> union(sourceSet, other) }
}
compilations.forEach { compilation ->
compilation.kotlinSourceSets.forEach { union(compilation, it) }
}
val uniqueCompilationNamesCounter = mutableMapOf<Set<String>, Int>()
fun moduleName(compilations: Iterable<KotlinCompilation<*>>): String {
val names = compilations.map { it.name }.toSortedSet()
val uniqueNumber = uniqueCompilationNamesCounter.put(names, uniqueCompilationNamesCounter[names]?.plus(1) ?: 0)
return names.joinToString("-") + (uniqueNumber?.let { "-$it" } ?: "")
}
return compilations.groupBy { get(it) }.values.associateBy { moduleName(it) }
}
@Suppress("unused")
class GradleProjectModuleBuilder(private val addInferredSourceSetVisibilityAsExplicit: Boolean) {
private fun getModulesFromPm20Project(project: Project) = project.pm20Extension.modules.toList()
fun buildModulesFromProject(project: Project): List<KpmModule> {
if (project.pm20ExtensionOrNull != null)
return getModulesFromPm20Project(project)
val extension = project.multiplatformExtensionOrNull
?: project.kotlinExtension
val targets = when (extension) {
is KotlinMultiplatformExtension -> extension.targets.filter { it.name != KotlinMultiplatformPlugin.METADATA_TARGET_NAME }
is KotlinSingleTargetExtension<*> -> listOf(extension.target)
else -> return emptyList()
}
val moduleCompilationCluster = detectModules(targets, extension.sourceSets)
val publishedVariantsByCompilation = targets.flatMap { target ->
(target as? AbstractKotlinTarget)?.kotlinComponents.orEmpty()
.flatMap { component -> (component as? KotlinVariant)?.usages.orEmpty() }
}.groupBy { it.compilation }
val moduleByFragment = mutableMapOf<KpmFragment, KpmModule>()
val result = moduleCompilationCluster.entries.map { (classifier, compilationsToInclude) ->
val sourceSetsToInclude = compilationsToInclude.flatMapTo(mutableSetOf()) { it.allKotlinSourceSets }
val moduleIdentifier = KpmLocalModuleIdentifier(
project.currentBuildId().buildPathCompat,
project.path,
classifier.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }
)
KpmBasicModule(moduleIdentifier).apply {
val variantToCompilation = mutableMapOf<KpmBasicFragment, KotlinCompilation<*>>()
compilationsToInclude.forEach { compilation ->
// A compilation may be exposed as more than one variant, so we collect all of its names
val variantNames =
publishedVariantsByCompilation[compilation]?.filter { it.includeIntoProjectStructureMetadata }?.map { it.name }
?: listOf(compilation.defaultSourceSetName)
variantNames.forEach { variantName ->
val variant = KpmBasicVariant(this@apply, variantName, DefaultLanguageSettingsBuilder(project))
moduleByFragment[variant] = this@apply
variantToCompilation[variant] = compilation
fragments.add(variant)
// TODO The attributes from the compile dependencies configuration might differ from exposed attributes
val compileDependenciesConfiguration =
project.configurations.getByName(compilation.compileDependencyConfigurationName)
compileDependenciesConfiguration.attributes.keySet().forEach { key ->
variant.variantAttributes[KotlinAttributeKey(key.name)] =
attributeString(compileDependenciesConfiguration.attributes, key)
}
}
}
// Once all fragments are created, add dependencies between them
sourceSetsToInclude.forEach { sourceSet ->
val existingVariant = fragments.filterIsInstance<KpmBasicVariant>().find { it.fragmentName == sourceSet.name }
val fragment = existingVariant ?: KpmBasicFragment(this@apply, sourceSet.name, sourceSet.languageSettings).also { fragments.add(it) }
moduleByFragment[fragment] = this@apply
fragment.kotlinSourceRoots = sourceSet.kotlin.sourceDirectories.toList()
// FIXME: Kotlin/Native implementation-effective-api dependencies are missing here. Introduce dependency scopes
sourceSet.internal.resolvableMetadataConfiguration.incoming.dependencies.forEach {
val moduleDependency = it.toKpmModuleDependency(project)
fragment.declaredModuleDependencies.add(moduleDependency)
}
}
fragments.forEach { fragment ->
val sourceSet = extension.sourceSets.findByName(fragment.fragmentName)
?: variantToCompilation.getValue(fragment).defaultSourceSet
sourceSet.dependsOn.forEach { dependency ->
val dependencyFragment = fragmentByName(dependency.name)
fragment.declaredRefinesDependencies.add(dependencyFragment)
}
}
}
}
fun fragmentByName(name: String) =
result.asSequence().flatMap { it.fragments.asSequence() }.first { it.fragmentName == name }
targets.flatMap { it.compilations }.forEach { compilation ->
val variant = fragmentByName(compilation.defaultSourceSetName)
compilation.associatedCompilations.forEach { associate ->
val associateVariant = fragmentByName(associate.defaultSourceSetName)
variant.declaredModuleDependencies.add(KpmModuleDependency(associateVariant.containingModule.moduleIdentifier))
}
}
if (addInferredSourceSetVisibilityAsExplicit) {
project.kotlinExtension.sourceSets.forEach { sourceSet ->
val fragment = fragmentByName(sourceSet.name)
getVisibleSourceSetsFromAssociateCompilations(sourceSet).forEach { dependency ->
val dependencyFragment = fragmentByName(dependency.name)
fragment.declaredModuleDependencies.add(KpmModuleDependency(dependencyFragment.containingModule.moduleIdentifier))
}
}
}
return result
}
private fun <T : Any> attributeString(container: AttributeContainer, attributeKey: Attribute<T>): String {
val value = container.getAttribute(attributeKey)
return when (value) {
is Named -> value.name
else -> value.toString()
}
}
}
internal fun Dependency.toKpmModuleDependency(
project: Project
): KpmModuleDependency {
return KpmModuleDependency(
when (this) {
is ProjectDependency ->
KpmLocalModuleIdentifier(
project.currentBuildId().buildPathCompat,
dependencyProject.path,
moduleClassifiersFromCapabilities(requestedCapabilities).single() // FIXME multiple capabilities
)
is ModuleDependency ->
KpmMavenModuleIdentifier(
group.orEmpty(),
name,
moduleClassifiersFromCapabilities(requestedCapabilities).single() // FIXME multiple capabilities
)
else -> KpmMavenModuleIdentifier(group.orEmpty(), name, null)
}
)
}
private fun KpmBasicModule.fragmentByName(name: String) =
fragments.single { it.fragmentName == name }
class KpmCachingModuleVariantResolver(private val actualResolver: KpmModuleVariantResolver) : KpmModuleVariantResolver {
private val resultCacheByRequestingVariant: MutableMap<KpmVariant, MutableMap<KpmModule, KpmVariantResolution>> = mutableMapOf()
override fun getChosenVariant(requestingVariant: KpmVariant, dependencyModule: KpmModule): KpmVariantResolution {
val resultCache = resultCacheByRequestingVariant.getOrPut(requestingVariant) { mutableMapOf() }
return resultCache.getOrPut(dependencyModule) { actualResolver.getChosenVariant(requestingVariant, dependencyModule) }
}
}
@Suppress("UNREACHABLE_CODE", "UNUSED_VARIABLE")
class KpmGradleModuleVariantResolver : KpmModuleVariantResolver {
override fun getChosenVariant(requestingVariant: KpmVariant, dependencyModule: KpmModule): KpmVariantResolution {
// TODO maybe improve this behavior? Currently it contradicts dependency resolution in that it may return a chosen variant for an
// unrequested dependency. This workaround is needed for synthetic modules which were not produced from module metadata, so maybe
// those modules should be marked somehow
if (dependencyModule is GradleKpmExternalPlainModule) {
return KpmVariantResolution.fromMatchingVariants(
requestingVariant,
dependencyModule,
listOf(dependencyModule.singleVariant)
)
}
if (requestingVariant !is GradleKpmVariant) {
return KpmVariantResolution.Unknown(requestingVariant, dependencyModule)
}
val module = requestingVariant.containingModule
val project = module.project
// This implementation can only resolve variants for the current project's KotlinModule
require(module.representsProject(project))
val compileClasspath = getCompileDependenciesConfigurationForVariant(project, requestingVariant)
val dependencyModuleId = dependencyModule.moduleIdentifier
/** @see SourceSetVisibilityProvider.PlatformCompilationData */
val resolvedGradleVariantName: String = TODO("Implement Resolved Gradle Variant finder as it done in TCS")
val kotlinVariantName = when (dependencyModule) {
is GradleKpmModule -> {
dependencyModule.variants.singleOrNull { resolvedGradleVariantName in it.gradleVariantNames }?.name
?: return KpmVariantResolution.Unknown(requestingVariant, dependencyModule)
}
else -> resolvedGradleVariantName?.let(::kotlinVariantNameFromPublishedVariantName)
}
val resultVariant = dependencyModule.variants.singleOrNull { it.fragmentName == kotlinVariantName }
return if (resultVariant == null)
KpmVariantResolution.KpmNoVariantMatch(requestingVariant, dependencyModule)
else
KpmVariantResolution.KpmVariantMatch(requestingVariant, dependencyModule, resultVariant)
}
private fun getCompileDependenciesConfigurationForVariant(project: Project, requestingVariant: KpmVariant): Configuration =
when {
project.pm20ExtensionOrNull != null -> {
(requestingVariant as GradleKpmVariant).compileDependenciesConfiguration
}
else -> {
val targets =
project.multiplatformExtensionOrNull?.targets ?: listOf((project.kotlinExtension as KotlinSingleTargetExtension<*>).target)
val compilation =
targets.filterIsInstance<AbstractKotlinTarget>()
.flatMap { it.kotlinComponents.filterIsInstance<KotlinVariant>() }
.flatMap { it.usages }
.firstOrNull { it.name == requestingVariant.fragmentName }
?.compilation
?: targets.asSequence().flatMap { it.compilations.asSequence() }.single {
it.defaultSourceSetName == requestingVariant.fragmentName
} // TODO: generalize the mapping PM2.0 <-> MPP
?: error("could not find a compilation that produces the variant $requestingVariant in $project")
project.configurations.getByName(compilation.compileDependencyConfigurationName)
}
}
companion object {
fun getForCurrentBuild(project: Project): KpmModuleVariantResolver {
val extraPropertyName = "org.jetbrains.kotlin.dependencyResolution.variantResolver.${project.getKotlinPluginVersion()}"
return project.getOrPutRootProjectProperty(extraPropertyName) {
KpmCachingModuleVariantResolver(KpmGradleModuleVariantResolver())
}
}
}
}
@@ -15,7 +15,6 @@ import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.Nested
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmModule
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.currentBuildId
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope
@@ -225,40 +224,6 @@ private fun buildKotlinProjectStructureMetadata(extension: KotlinMultiplatformEx
)
}
internal fun buildProjectStructureMetadata(module: GradleKpmModule): KotlinProjectStructureMetadata {
val kotlinVariantToGradleVariantNames = module.variants.associate { it.name to it.gradleVariantNames }
fun <T> expandVariantKeys(map: Map<String, T>) =
map.entries.flatMap { (key, value) ->
kotlinVariantToGradleVariantNames[key].orEmpty().plus(key).map { it to value }
}.toMap()
val kotlinFragmentsPerKotlinVariant =
module.variants.associate { variant -> variant.name to variant.withRefinesClosure.map { it.name }.toSet() }
val fragmentRefinesRelation =
module.fragments.associate { it.name to it.declaredRefinesDependencies.map { it.fragmentName }.toSet() }
// FIXME: support native implementation-as-api-dependencies
// FIXME: support dependencies on auxiliary modules
val fragmentDependencies =
module.fragments.associate { fragment ->
fragment.name to fragment.declaredModuleDependencies.map {
ModuleIds.lossyFromModuleIdentifier(module.project, it.moduleIdentifier)
}.toSet()
}
return KotlinProjectStructureMetadata(
sourceSetNamesByVariantName = expandVariantKeys(kotlinFragmentsPerKotlinVariant),
sourceSetsDependsOnRelation = fragmentRefinesRelation,
sourceSetBinaryLayout = module.fragments.associate { it.name to SourceSetMetadataLayout.KLIB },
sourceSetModuleDependencies = fragmentDependencies,
sourceSetCInteropMetadataDirectory = emptyMap(), // Not supported yet
hostSpecificSourceSets = module.project.future { getHostSpecificFragments(module).mapTo(mutableSetOf()) { it.name } }.getOrThrow(),
isPublishedAsRoot = true,
sourceSetNames = module.fragments.map { it.name }.toSet()
)
}
internal fun <Serializer> KotlinProjectStructureMetadata.serialize(
serializer: Serializer,
node: Serializer.(name: String, Serializer.() -> Unit) -> Unit,
@@ -13,7 +13,6 @@ import org.gradle.api.artifacts.result.ResolvedComponentResult
import org.gradle.api.publish.maven.MavenPublication
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.PublishedModuleCoordinatesProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.ComputedCapability
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.currentBuildId
import org.jetbrains.kotlin.gradle.utils.buildPathCompat
import org.jetbrains.kotlin.gradle.utils.currentBuild
@@ -78,26 +77,16 @@ internal object ModuleIds {
val dependencyProject = thisProject.project(moduleIdentifier.projectId)
val topLevelExtension = dependencyProject.topLevelExtension
val getRootPublication: () -> MavenPublication? = when {
dependencyProject.pm20ExtensionOrNull != null -> {
{ dependencyProject.pm20Extension.kpmModelContainer.rootPublication }
}
topLevelExtension is KotlinMultiplatformExtension -> {
{ topLevelExtension.rootSoftwareComponent.publicationDelegate }
}
else -> error("unexpected top-level extension $topLevelExtension")
}
val capabilities = when {
dependencyProject.pm20ExtensionOrNull != null -> listOfNotNull(ComputedCapability.capabilityStringFromModule(
dependencyProject.pm20Extension.modules.single { it.moduleIdentifier == moduleIdentifier }
))
topLevelExtension is KotlinMultiplatformExtension -> emptyList()
else -> error("unexpected top-level extension $topLevelExtension")
}
val coordinatesProvider = MavenPublicationCoordinatesProvider(
dependencyProject,
getRootPublication,
defaultModuleSuffix = null,
capabilities = capabilities
capabilities = emptyList()
)
return ChangingModuleDependencyIdentifier({ coordinatesProvider.group }, { coordinatesProvider.name })
}
@@ -1,9 +0,0 @@
/*
* Copyright 2010-2022 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
@RequiresOptIn("API is marked as advanced. Consultation with the Kotlin Team advised.")
annotation class AdvancedKotlinGradlePluginApi
@@ -1,23 +0,0 @@
/*
* Copyright 2010-2022 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.jetbrains.kotlin.project.model.KpmModule
import org.jetbrains.kotlin.project.model.KpmModuleDependency
import org.jetbrains.kotlin.project.model.KpmModuleDependencyResolver
import java.util.*
class GradleKpmCachingModuleDependencyResolver(private val actualResolver: KpmModuleDependencyResolver) : KpmModuleDependencyResolver {
private val cacheByRequestingModule = WeakHashMap<KpmModule, MutableMap<KpmModuleDependency, KpmModule?>>()
private fun cacheForRequestingModule(requestingModule: KpmModule) =
cacheByRequestingModule.getOrPut(requestingModule) { mutableMapOf() }
override fun resolveDependency(requestingModule: KpmModule, moduleDependency: KpmModuleDependency): KpmModule? =
cacheForRequestingModule(requestingModule).getOrPut(moduleDependency) {
actualResolver.resolveDependency(requestingModule, moduleDependency)
}
}
@@ -1,48 +0,0 @@
/*
* 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.
*/
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.FragmentNameDisambiguation
typealias GradleKpmCommonFragmentFactory = GradleKpmFragmentFactory<GradleKpmFragmentInternal>
fun GradleKpmCommonFragmentFactory(module: GradleKpmModule): GradleKpmCommonFragmentFactory =
GradleKpmCommonFragmentFactory(GradleKpmCommonFragmentInstantiator(module))
fun GradleKpmCommonFragmentFactory(
commonFragmentInstantiator: GradleKpmCommonFragmentInstantiator,
commonFragmentConfigurator: GradleKpmCommonFragmentConfigurator = GradleKpmCommonFragmentConfigurator()
): GradleKpmFragmentFactory<GradleKpmFragmentInternal> = GradleKpmFragmentFactory(
fragmentInstantiator = commonFragmentInstantiator,
fragmentConfigurator = commonFragmentConfigurator
)
class GradleKpmCommonFragmentInstantiator(
private val module: GradleKpmModule,
private val dependencyConfigurationsFactory: GradleKpmFragmentDependencyConfigurationsFactory =
GradleKpmDefaultFragmentDependencyConfigurationsFactory
) : GradleKpmFragmentFactory.FragmentInstantiator<GradleKpmFragmentInternal> {
override fun create(name: String): GradleKpmFragmentInternal {
val names = FragmentNameDisambiguation(module, name)
return module.project.objects.newInstance(
GradleKpmFragmentInternal::class.java,
module,
name,
dependencyConfigurationsFactory.create(module, names)
)
}
}
class GradleKpmCommonFragmentConfigurator(
private val sourceDirectoriesSetup: GradleKpmSourceDirectoriesConfigurator<GradleKpmFragmentInternal> =
GradleKpmDefaultSourceDirectoriesConfigurator
) : GradleKpmFragmentFactory.FragmentConfigurator<GradleKpmFragmentInternal> {
override fun configure(fragment: GradleKpmFragmentInternal) {
sourceDirectoriesSetup.configure(fragment)
}
}
@@ -1,50 +0,0 @@
/*
* 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.HasCompilerOptions
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationOutput
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.project.model.LanguageSettings
/*
Previously used to find a common representation for KPM and TCS.
Not in use anymore. Can be removed/inlined into KPM later.
*/
interface GradleKpmCompilationData<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: LanguageSettings
val platformType: KotlinPlatformType
val moduleName: String
@Deprecated(
message = "Replaced with compilerOptions.options",
replaceWith = ReplaceWith("compilerOptions.options")
)
val kotlinOptions: T
val compilerOptions: HasCompilerOptions<*>
val friendPaths: Iterable<FileCollection>
}
@@ -1,27 +0,0 @@
/*
* 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.Dependency
import org.gradle.jvm.tasks.Jar
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.FragmentNameDisambiguationOmittingMain
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
import org.jetbrains.kotlin.gradle.utils.dashSeparatedLowercaseName
/**
* Registers a [Jar] task with the variant's compilation outputs and attaches this artifact to the given configuration.
*/
val GradleKpmCompilationOutputsJarArtifact = GradleKpmConfigurationArtifactsSetup<GradleKpmVariant> {
val jar = project.locateOrRegisterTask<Jar>(fragment.outputsJarTaskName) {
it.from(fragment.compilationOutputs.allOutputs)
it.archiveAppendix.set(dashSeparatedLowercaseName(fragment.name, fragment.containingModule.moduleClassifier))
}
artifact(jar)
fragment.project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, jar)
}
internal val GradleKpmVariant.outputsJarTaskName: String
get() = FragmentNameDisambiguationOmittingMain(containingModule, name).disambiguateName("jar")
@@ -1,76 +0,0 @@
/*
* 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.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.plugin.Kotlin2JvmSourceSetProcessor
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationInfo
import org.jetbrains.kotlin.gradle.plugin.KotlinNativeTargetConfigurator
import org.jetbrains.kotlin.gradle.plugin.mpp.addCommonSourcesToKotlinCompileTask
import org.jetbrains.kotlin.gradle.plugin.mpp.addSourcesToKotlinCompileTask
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
open class GradleKpmCompilationTaskConfigurator(
protected val project: Project
) {
open val fragmentSourcesProvider: GradleKpmFragmentSourcesProvider = GradleKpmFragmentSourcesProvider()
open fun getSourcesForFragmentCompilation(fragment: GradleKpmFragment): MultipleSourceRootsProvider =
fragmentSourcesProvider.getSourcesFromRefinesClosure(fragment)
open fun getCommonSourcesForFragmentCompilation(fragment: GradleKpmFragment): MultipleSourceRootsProvider =
fragmentSourcesProvider.getCommonSourcesFromRefinesClosure(fragment)
fun createKotlinJvmCompilationTask(
variant: GradleKpmVariant,
compilationData: GradleKpmCompilationData<*>
): TaskProvider<out KotlinCompile> {
Kotlin2JvmSourceSetProcessor(KotlinTasksProvider(), KotlinCompilationInfo.KPM(compilationData)).run()
val allSources = getSourcesForFragmentCompilation(variant)
val commonSources = getCommonSourcesForFragmentCompilation(variant)
// FIXME support custom source file extensions in the two calls below
addSourcesToKotlinCompileTask(project, compilationData.compileKotlinTaskName, emptyList()) { allSources }
addCommonSourcesToKotlinCompileTask(project, compilationData.compileKotlinTaskName, emptyList()) { commonSources }
val result = project.tasks.named(compilationData.compileKotlinTaskName, KotlinCompile::class.java) {
it.kotlinPluginData = project.compilerPluginProviderForPlatformCompilation(variant, compilationData)
}
compilationData.output.classesDirs.from(result.flatMap { it.destinationDirectory })
return result
}
protected fun createKotlinNativeCompilationTask(
fragment: GradleKpmFragment,
compilationData: GradleKpmNativeCompilationData<*>,
configure: KotlinNativeCompile.() -> Unit
): TaskProvider<KotlinNativeCompile> {
val compileTask = KotlinNativeTargetConfigurator.createKlibCompilationTask(
KotlinCompilationInfo.KPM(compilationData), compilationData.konanTarget
)
val allSources = getSourcesForFragmentCompilation(fragment)
val commonSources = getCommonSourcesForFragmentCompilation(fragment)
compileTask.configure {
it.setSource(allSources)
it.commonSources.from(commonSources)
it.configure()
}
return compileTask
}
fun createKotlinNativeCompilationTask(
variant: GradleKpmNativeVariantInternal,
compilationData: GradleKpmNativeCompilationData<*>
): TaskProvider<KotlinNativeCompile> = createKotlinNativeCompilationTask(variant, compilationData) {
kotlinPluginData = project.compilerPluginProviderForPlatformCompilation(variant, compilationData)
}
}
@@ -1,28 +0,0 @@
/*
* 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.tasks.TaskProvider
interface GradleKpmCompileTaskConfigurator<in T : GradleKpmVariant> {
fun registerCompileTasks(variant: T): TaskProvider<*>
}
object GradleKpmJvmCompileTaskConfigurator : GradleKpmCompileTaskConfigurator<GradleKpmJvmVariant> {
override fun registerCompileTasks(variant: GradleKpmJvmVariant): TaskProvider<*> {
val compilationData = variant.compilationData
LifecycleTasksManager(variant.project).registerClassesTask(compilationData)
return GradleKpmCompilationTaskConfigurator(variant.project).createKotlinJvmCompilationTask(variant, compilationData)
}
}
object GradleKpmNativeCompileTaskConfigurator : GradleKpmCompileTaskConfigurator<GradleKpmNativeVariantInternal> {
override fun registerCompileTasks(variant: GradleKpmNativeVariantInternal): TaskProvider<*> {
val compilationData = variant.compilationData
LifecycleTasksManager(variant.project).registerClassesTask(compilationData)
return GradleKpmCompilationTaskConfigurator(variant.project).createKotlinNativeCompilationTask(variant, compilationData)
}
}
@@ -1,17 +0,0 @@
/*
* 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.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.project.model.*
/**
* Gradle plugin that provides [KpmCompilerPlugin] from applied [Project]
*/
interface GradleKpmCompilerPlugin : Plugin<Project> {
val kpmCompilerPlugin: KpmCompilerPlugin
}
@@ -1,45 +0,0 @@
/*
* Copyright 2010-2022 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.artifacts.Configuration
import org.gradle.api.artifacts.result.ResolvedComponentResult
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
import org.jetbrains.kotlin.gradle.utils.getOrPutRootProjectProperty
import org.jetbrains.kotlin.project.model.KpmModuleDependency
import org.jetbrains.kotlin.project.model.KpmModuleIdentifier
open class GradleKpmComponentResultCachingResolver {
private val cachedResultsByRequestingModule = mutableMapOf<GradleKpmModule, Map<KpmModuleIdentifier, ResolvedComponentResult>>()
protected open fun configurationToResolve(requestingModule: GradleKpmModule): Configuration =
configurationToResolveMetadataDependencies(requestingModule)
protected open fun resolveDependencies(module: GradleKpmModule): Map<KpmModuleIdentifier, ResolvedComponentResult> {
val allComponents = configurationToResolve(module).incoming.resolutionResult.allComponents
// FIXME handle multi-component results
return allComponents.flatMap { component -> component.toKpmModuleIdentifiers().map { it to component } }.toMap()
}
private fun getResultsForModule(module: GradleKpmModule): Map<KpmModuleIdentifier, ResolvedComponentResult> =
cachedResultsByRequestingModule.getOrPut(module) { resolveDependencies(module) }
fun resolveModuleDependencyAsComponentResult(
requestingModule: GradleKpmModule,
moduleDependency: KpmModuleDependency
): ResolvedComponentResult? =
getResultsForModule(requestingModule)[moduleDependency.moduleIdentifier]
companion object {
fun getForCurrentBuild(project: Project): GradleKpmComponentResultCachingResolver {
val extraPropertyName = "org.jetbrains.kotlin.dependencyResolution.gradleComponentResolver.${project.getKotlinPluginVersion()}"
return project.getOrPutRootProjectProperty(extraPropertyName) {
GradleKpmComponentResultCachingResolver()
}
}
}
}
@@ -1,80 +0,0 @@
/*
* Copyright 2010-2022 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.Project
import org.gradle.api.artifacts.ConfigurablePublishArtifact
import org.gradle.api.artifacts.ConfigurationPublications
import org.gradle.api.artifacts.ConfigurationVariant
interface GradleKpmConfigurationArtifactsSetup<in T : GradleKpmFragment> {
fun setupArtifacts(outgoing: ConfigurationPublications, fragment: T)
object None : GradleKpmConfigurationArtifactsSetup<GradleKpmFragment> {
override fun setupArtifacts(outgoing: ConfigurationPublications, fragment: GradleKpmFragment) = Unit
}
}
class GradleKpmConfigurationArtifactsSetupContext<T : GradleKpmFragment> internal constructor(
internal val outgoing: ConfigurationPublications,
val fragment: T
) {
val project: Project get() = fragment.project
val variants: NamedDomainObjectContainer<ConfigurationVariant> get() = outgoing.variants
fun artifact(notation: Any) {
outgoing.artifact(notation)
}
fun artifact(notation: Any, configure: ConfigurablePublishArtifact.() -> Unit) {
outgoing.artifact(notation, configure)
}
}
@Suppress("FunctionName")
fun <T : GradleKpmFragment> GradleKpmConfigurationArtifactsSetup(
addArtifacts: GradleKpmConfigurationArtifactsSetupContext<T>.() -> Unit
): GradleKpmConfigurationArtifactsSetup<T> {
return object : GradleKpmConfigurationArtifactsSetup<T> {
override fun setupArtifacts(outgoing: ConfigurationPublications, fragment: T) {
val context = GradleKpmConfigurationArtifactsSetupContext(outgoing, fragment)
context.addArtifacts()
}
}
}
operator fun <T : GradleKpmFragment> GradleKpmConfigurationArtifactsSetup<T>.plus(
other: GradleKpmConfigurationArtifactsSetup<T>
): GradleKpmConfigurationArtifactsSetup<T> {
if (this === GradleKpmConfigurationArtifactsSetup.None) return other
if (other === GradleKpmConfigurationArtifactsSetup.None) return this
if (this is CompositeFragmentConfigurationArtifactsSetup && other is CompositeFragmentConfigurationArtifactsSetup) {
return CompositeFragmentConfigurationArtifactsSetup(this.children + other.children)
}
if (this is CompositeFragmentConfigurationArtifactsSetup) {
return CompositeFragmentConfigurationArtifactsSetup(this.children + other)
}
if (other is CompositeFragmentConfigurationArtifactsSetup) {
return CompositeFragmentConfigurationArtifactsSetup(listOf(this) + other.children)
}
return CompositeFragmentConfigurationArtifactsSetup(listOf(this, other))
}
internal class CompositeFragmentConfigurationArtifactsSetup<in T : GradleKpmFragment>(
val children: List<GradleKpmConfigurationArtifactsSetup<T>>
) : GradleKpmConfigurationArtifactsSetup<T> {
override fun setupArtifacts(outgoing: ConfigurationPublications, fragment: T) {
children.forEach { child -> child.setupArtifacts(outgoing, fragment) }
}
}
@@ -1,81 +0,0 @@
/*
* Copyright 2010-2022 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.Named
import org.gradle.api.Project
import org.gradle.api.attributes.Attribute
import org.gradle.api.attributes.AttributeContainer
/* Internal abbreviation */
interface GradleKpmConfigurationAttributesSetup<in T : GradleKpmFragment> {
fun setupAttributes(attributes: AttributeContainer, fragment: T)
object None : GradleKpmConfigurationAttributesSetup<GradleKpmFragment> {
override fun setupAttributes(attributes: AttributeContainer, fragment: GradleKpmFragment) = Unit
}
}
class GradleKpmConfigurationAttributesSetupContext<T : GradleKpmFragment> internal constructor(
internal val attributes: AttributeContainer,
val fragment: T,
) : AttributeContainer by attributes {
val project: Project get() = fragment.project
inline fun <reified T : Named> named(name: String): T = project.objects.named(T::class.java, name)
inline fun <reified T : Named> namedAttribute(key: Attribute<T>, name: String) = apply { attribute(key, named(name)) }
override fun <K : Any> attribute(key: Attribute<K>, value: K): GradleKpmConfigurationAttributesSetupContext<T> = apply {
attributes.attribute(key, value)
}
}
@Suppress("FunctionName")
fun <T : GradleKpmFragment> GradleKpmConfigurationAttributesSetup(
setAttributes: GradleKpmConfigurationAttributesSetupContext<T>.() -> Unit
): GradleKpmConfigurationAttributesSetup<T> {
return object : GradleKpmConfigurationAttributesSetup<T> {
override fun setupAttributes(attributes: AttributeContainer, fragment: T) {
val context = GradleKpmConfigurationAttributesSetupContext(attributes, fragment)
context.setAttributes()
}
}
}
fun <T : GradleKpmFragment> AttributeContainer.apply(
attributes: GradleKpmConfigurationAttributesSetup<T>, fragment: T
) {
attributes.setupAttributes(this, fragment)
}
operator fun <T : GradleKpmFragment> GradleKpmConfigurationAttributesSetup<T>.plus(other: GradleKpmConfigurationAttributesSetup<T>): GradleKpmConfigurationAttributesSetup<T> {
if (this === GradleKpmConfigurationAttributesSetup.None) return other
if (other === GradleKpmConfigurationAttributesSetup.None) return this
if (this is GradleKpmCompositeConfigurationAttributesSetup && other is GradleKpmCompositeConfigurationAttributesSetup) {
return GradleKpmCompositeConfigurationAttributesSetup(this.children + other.children)
}
if (this is GradleKpmCompositeConfigurationAttributesSetup) {
return GradleKpmCompositeConfigurationAttributesSetup(this.children + other)
}
if (other is GradleKpmCompositeConfigurationAttributesSetup) {
return GradleKpmCompositeConfigurationAttributesSetup(listOf(this) + other.children)
}
return GradleKpmCompositeConfigurationAttributesSetup(listOf(this, other))
}
internal class GradleKpmCompositeConfigurationAttributesSetup<in T : GradleKpmFragment>(val children: List<GradleKpmConfigurationAttributesSetup<T>>) :
GradleKpmConfigurationAttributesSetup<T> {
override fun setupAttributes(attributes: AttributeContainer, fragment: T) {
children.forEach { child -> child.setupAttributes(attributes, fragment) }
}
}
@@ -1,81 +0,0 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ConfigurationPublications
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmConfigurationCapabilitiesSetup.CapabilitiesContainer
interface GradleKpmConfigurationCapabilitiesSetup<in T : GradleKpmFragment> {
interface CapabilitiesContainer {
fun capability(notation: Any)
}
fun setCapabilities(container: CapabilitiesContainer, fragment: T)
object None : GradleKpmConfigurationCapabilitiesSetup<GradleKpmFragment> {
override fun setCapabilities(container: CapabilitiesContainer, fragment: GradleKpmFragment) = Unit
}
}
fun <T : GradleKpmFragment> GradleKpmConfigurationCapabilitiesSetup<T>.setCapabilities(
publications: ConfigurationPublications, fragment: T
) = setCapabilities(CapabilitiesContainer(publications), fragment)
fun CapabilitiesContainer(configuration: ConfigurationPublications): CapabilitiesContainer =
CapabilitiesContainerImpl(configuration)
private class CapabilitiesContainerImpl(
private val publications: ConfigurationPublications
) : CapabilitiesContainer {
override fun capability(notation: Any) = publications.capability(notation)
}
class GradleKpmConfigurationCapabilitiesSetupContext<T : GradleKpmFragment> internal constructor(
internal val container: CapabilitiesContainer, val fragment: T
) : CapabilitiesContainer by container {
val project: Project get() = fragment.project
}
fun <T : GradleKpmFragment> GradleKpmConfigurationCapabilitiesSetup(
setCapabilities: GradleKpmConfigurationCapabilitiesSetupContext<T>.() -> Unit
): GradleKpmConfigurationCapabilitiesSetup<T> = object : GradleKpmConfigurationCapabilitiesSetup<T> {
override fun setCapabilities(container: CapabilitiesContainer, fragment: T) {
val context = GradleKpmConfigurationCapabilitiesSetupContext(container, fragment)
context.setCapabilities()
}
}
operator fun <T : GradleKpmFragment> GradleKpmConfigurationCapabilitiesSetup<T>.plus(
other: GradleKpmConfigurationCapabilitiesSetup<T>
): GradleKpmConfigurationCapabilitiesSetup<T> {
if (this === GradleKpmConfigurationCapabilitiesSetup.None) return other
if (other === GradleKpmConfigurationCapabilitiesSetup.None) return this
if (this is CompositeKpmCapabilitiesSetup && other is CompositeKpmCapabilitiesSetup) {
return CompositeKpmCapabilitiesSetup(this.children + other.children)
}
if (this is CompositeKpmCapabilitiesSetup) {
return CompositeKpmCapabilitiesSetup(this.children + other)
}
if (other is CompositeKpmCapabilitiesSetup) {
return CompositeKpmCapabilitiesSetup(listOf(this) + other.children)
}
return CompositeKpmCapabilitiesSetup(listOf(this, other))
}
internal class CompositeKpmCapabilitiesSetup<in T : GradleKpmFragment>(val children: List<GradleKpmConfigurationCapabilitiesSetup<T>>) :
GradleKpmConfigurationCapabilitiesSetup<T> {
override fun setCapabilities(container: CapabilitiesContainer, fragment: T) {
children.forEach { child -> child.setCapabilities(container, fragment) }
}
}
@@ -1,19 +0,0 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.artifacts.Configuration
interface GradleKpmConfigurationProvider {
fun getConfiguration(context: GradleKpmFragmentConfigureContext): Configuration
}
fun GradleKpmConfigurationProvider(provider: GradleKpmFragmentConfigureContext.() -> Configuration):
GradleKpmConfigurationProvider = object : GradleKpmConfigurationProvider {
override fun getConfiguration(context: GradleKpmFragmentConfigureContext): Configuration = context.provider()
}
@@ -1,64 +0,0 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.artifacts.Configuration
import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
interface GradleKpmConfigurationRelationSetup {
fun setupExtendsFromRelations(configuration: Configuration, context: GradleKpmFragmentConfigureContext)
object None : GradleKpmConfigurationRelationSetup {
override fun setupExtendsFromRelations(configuration: Configuration, context: GradleKpmFragmentConfigureContext) = Unit
}
}
operator fun GradleKpmConfigurationRelationSetup.plus(other: GradleKpmConfigurationRelationSetup): GradleKpmConfigurationRelationSetup {
if (this === GradleKpmConfigurationRelationSetup.None) return other
if (other === GradleKpmConfigurationRelationSetup.None) return this
if (this is CompositeKpmConfigurationRelationSetup && other is CompositeKpmConfigurationRelationSetup) {
return CompositeKpmConfigurationRelationSetup(this.children + other.children)
}
if (this is CompositeKpmConfigurationRelationSetup) {
return CompositeKpmConfigurationRelationSetup(this.children + other)
}
if (other is CompositeKpmConfigurationRelationSetup) {
return CompositeKpmConfigurationRelationSetup(listOf(this) + other.children)
}
return CompositeKpmConfigurationRelationSetup(listOf(this, other))
}
internal class CompositeKpmConfigurationRelationSetup(val children: List<GradleKpmConfigurationRelationSetup>) :
GradleKpmConfigurationRelationSetup {
override fun setupExtendsFromRelations(configuration: Configuration, context: GradleKpmFragmentConfigureContext) {
children.forEach { child -> child.setupExtendsFromRelations(configuration, context) }
}
}
class GradleKpmFragmentConfigureRelationContext internal constructor(
val configuration: Configuration,
context: GradleKpmFragmentConfigureContext
) : GradleKpmFragmentConfigureContext by context {
fun extendsFrom(configuration: Configuration) = this.configuration.extendsFrom(configuration)
fun extendsFrom(configuration: String) = project.addExtendsFromRelation(this.configuration.name, configuration)
}
fun GradleKpmConfigurationRelationSetup(
setExtendsFrom: GradleKpmFragmentConfigureRelationContext.() -> Unit
): GradleKpmConfigurationRelationSetup = object : GradleKpmConfigurationRelationSetup {
override fun setupExtendsFromRelations(configuration: Configuration, context: GradleKpmFragmentConfigureContext) {
val relationContext = GradleKpmFragmentConfigureRelationContext(configuration, context)
relationContext.setExtendsFrom()
}
}
@@ -1,51 +0,0 @@
/*
* Copyright 2010-2022 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.artifacts.Configuration
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.GradleKpmNameDisambiguation
/* Internal abbreviation */
data class GradleKpmConfigurationSetup<in T : GradleKpmFragment>(
val provider: GradleKpmConfigurationProvider,
val attributes: GradleKpmConfigurationAttributesSetup<T> = GradleKpmConfigurationAttributesSetup.None,
val artifacts: GradleKpmConfigurationArtifactsSetup<T> = GradleKpmConfigurationArtifactsSetup.None,
val relations: GradleKpmConfigurationRelationSetup = GradleKpmConfigurationRelationSetup.None,
@property:AdvancedKotlinGradlePluginApi
val capabilities: GradleKpmConfigurationCapabilitiesSetup<T> = GradleKpmConfigurationCapabilitiesSetup.None,
)
interface GradleKpmFragmentConfigureContext : GradleKpmNameDisambiguation {
val project: Project get() = module.project
val module: GradleKpmModule
val dependencies: GradleKpmFragmentDependencyConfigurations
}
internal class GradleKpmFragmentConfigureContextImpl(
override val module: GradleKpmModule,
override val dependencies: GradleKpmFragmentDependencyConfigurations,
names: GradleKpmNameDisambiguation
) : GradleKpmFragmentConfigureContext, GradleKpmNameDisambiguation by names
fun <T : GradleKpmFragment> GradleKpmConfigurationSetup<T>.withConfigurationProvider(
provider: GradleKpmFragmentConfigureContext.() -> Configuration
) = copy(provider = GradleKpmConfigurationProvider(provider))
operator fun <T : GradleKpmFragment> GradleKpmConfigurationSetup<T>.plus(other: GradleKpmConfigurationAttributesSetup<T>):
GradleKpmConfigurationSetup<T> = copy(attributes = attributes + other)
operator fun <T : GradleKpmFragment> GradleKpmConfigurationSetup<T>.plus(other: GradleKpmConfigurationArtifactsSetup<T>):
GradleKpmConfigurationSetup<T> = copy(artifacts = artifacts + other)
operator fun <T : GradleKpmFragment> GradleKpmConfigurationSetup<T>.plus(other: GradleKpmConfigurationRelationSetup):
GradleKpmConfigurationSetup<T> = copy(relations = relations + other)
@AdvancedKotlinGradlePluginApi
operator fun <T : GradleKpmFragment> GradleKpmConfigurationSetup<T>.plus(other: GradleKpmConfigurationCapabilitiesSetup<T>):
GradleKpmConfigurationSetup<T> = copy(capabilities = capabilities + other)
@@ -1,37 +0,0 @@
/*
* Copyright 2010-2022 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.publish.maven.MavenPublication
import org.jetbrains.kotlin.gradle.plugin.mpp.MavenPublicationCoordinatesProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.ComputedCapability
class GradleKpmDefaultSingleMavenPublishedModuleHolder(
private var module: GradleKpmModule, override val defaultPublishedModuleSuffix: String?
) : GradleKpmSingleMavenPublishedModuleHolder {
private val project get() = module.project
private var assignedMavenPublication: MavenPublication? = null
private val publicationAssignedHandlers = mutableListOf<(MavenPublication) -> Unit>()
override fun assignMavenPublication(publication: MavenPublication) {
if (assignedMavenPublication != null) error("already assigned publication $publication")
assignedMavenPublication = publication
publicationAssignedHandlers.forEach { it(publication) }
}
override fun whenPublicationAssigned(handlePublication: (MavenPublication) -> Unit) {
assignedMavenPublication?.let(handlePublication) ?: publicationAssignedHandlers.add(handlePublication)
}
override val publishedMavenModuleCoordinates: PublishedModuleCoordinatesProvider = MavenPublicationCoordinatesProvider(
project,
{ assignedMavenPublication },
defaultPublishedModuleSuffix,
capabilities = listOfNotNull(ComputedCapability.capabilityStringFromModule(module))
)
}
@@ -1,15 +0,0 @@
/*
* 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
interface GradleKpmDependencyConfigurations {
val apiConfiguration: Configuration
val implementationConfiguration: Configuration
val compileOnlyConfiguration: Configuration
val runtimeOnlyConfiguration: Configuration
}
@@ -1,100 +0,0 @@
/*
* 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.artifacts.result.ResolvedComponentResult
import org.gradle.api.artifacts.result.ResolvedDependencyResult
import org.jetbrains.kotlin.project.model.*
internal fun resolvableMetadataConfiguration(
module: GradleKpmModule
) = module.project.configurations.getByName(module.resolvableMetadataConfigurationName)
internal fun configurationToResolveMetadataDependencies(requestingModule: KpmModule): Configuration =
resolvableMetadataConfiguration(requestingModule as GradleKpmModule)
class GradleKpmDependencyGraphResolver(
private val moduleResolver: KpmModuleDependencyResolver
) : KpmDependencyGraphResolver {
private fun configurationToResolve(requestingModule: GradleKpmModule): Configuration =
configurationToResolveMetadataDependencies(requestingModule)
override fun resolveDependencyGraph(requestingModule: KpmModule): KpmDependencyGraphResolution {
if (requestingModule !is GradleKpmModule)
return KpmDependencyGraphResolution.Unknown(requestingModule)
return resolveAsGraph(requestingModule)
}
private fun resolveAsGraph(requestingModule: GradleKpmModule): GradleKpmDependencyGraph {
val nodeByModuleId = mutableMapOf<KpmModuleIdentifier, GradleKpmDependencyGraphNode>()
fun getKotlinModuleFromComponentResult(component: ResolvedComponentResult): KpmModule =
moduleResolver.resolveDependency(requestingModule, component.toKpmModuleDependency())
?: buildSyntheticPlainModule(
component,
component.variants.singleOrNull()?.displayName ?: "default",
)
fun nodeFromModule(componentResult: ResolvedComponentResult, kpmModule: KpmModule): GradleKpmDependencyGraphNode {
val id = kpmModule.moduleIdentifier
return nodeByModuleId.getOrPut(id) {
val metadataSourceComponent =
(kpmModule as? GradleKpmExternalImportedModule)
?.takeIf { it.hasLegacyMetadataModule }
?.let { (componentResult.dependencies.singleOrNull() as? ResolvedDependencyResult)?.selected }
?: componentResult
val dependenciesRequestedByModule =
kpmModule.fragments.flatMap { fragment -> fragment.declaredModuleDependencies.map { it.moduleIdentifier } }.toSet()
val resolvedComponentDependencies = metadataSourceComponent.dependencies
.filterIsInstance<ResolvedDependencyResult>()
// This filter statement is used to only visit the dependencies of the variant(s) of the requested Kotlin module and not
// other variants. This prevents infinite recursion when visiting multiple Kotlin modules within one Gradle components
.filter { dependency -> dependency.requested.toKpmModuleIdentifiers().any { it in dependenciesRequestedByModule } }
.flatMap { dependency -> dependency.requested.toKpmModuleIdentifiers().map { id -> id to dependency.selected } }
.toMap()
val fragmentDependencies = kpmModule.fragments.associateWith { it.declaredModuleDependencies }
val nodeDependenciesMap = fragmentDependencies.mapValues { (_, deps) ->
deps.mapNotNull { resolvedComponentDependencies[it.moduleIdentifier] }.map {
val dependencyModule = getKotlinModuleFromComponentResult(it)
nodeFromModule(it, dependencyModule)
}
}
GradleKpmDependencyGraphNode(
kpmModule,
componentResult,
metadataSourceComponent,
nodeDependenciesMap
)
}
}
return GradleKpmDependencyGraph(
requestingModule,
nodeFromModule(configurationToResolve(requestingModule).incoming.resolutionResult.root, requestingModule)
)
}
}
class GradleKpmDependencyGraphNode(
override val module: KpmModule,
val selectedComponent: ResolvedComponentResult,
/** If the Kotlin module description was provided by a different component, such as with legacy publishing layout using *-metadata
* modules, then this property points to the other component. */
val metadataSourceComponent: ResolvedComponentResult?,
override val dependenciesByFragment: Map<KpmFragment, Iterable<GradleKpmDependencyGraphNode>>
) : KpmDependencyGraphNode(module, dependenciesByFragment)
class GradleKpmDependencyGraph(
override val requestingModule: GradleKpmModule,
override val root: GradleKpmDependencyGraphNode
) : KpmDependencyGraphResolution.KpmDependencyGraph(requestingModule, root)
@@ -1,72 +0,0 @@
/*
* 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.Action
import org.gradle.api.Named
import org.gradle.api.NamedDomainObjectProvider
import org.gradle.api.Project
import org.gradle.api.file.SourceDirectorySet
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.project.model.KpmFragment
import org.jetbrains.kotlin.project.model.utils.variantsContainingFragment
import org.jetbrains.kotlin.tooling.core.MutableExtras
import org.jetbrains.kotlin.tooling.core.closure
import org.jetbrains.kotlin.tooling.core.withClosure
interface GradleKpmFragment : KpmFragment, HasKotlinDependencies, GradleKpmFragmentDependencyConfigurations, Named {
override val kotlinSourceRoots: SourceDirectorySet
override val containingModule: GradleKpmModule
override fun getName(): String = fragmentName
override val languageSettings: LanguageSettingsBuilder
val project: Project
get() = containingModule.project
val extras: MutableExtras
fun refines(other: GradleKpmFragment)
fun refines(other: NamedDomainObjectProvider<GradleKpmFragment>)
override val declaredRefinesDependencies: Iterable<GradleKpmFragment>
override val refinesClosure: Set<GradleKpmFragment>
get() = this.closure { it.declaredRefinesDependencies }
override val withRefinesClosure: Set<GradleKpmFragment>
get() = this.withClosure { it.declaredRefinesDependencies }
override fun dependencies(configure: Action<KotlinDependencyHandler>) =
dependencies { configure.execute(this) }
companion object {
const val COMMON_FRAGMENT_NAME = "common"
}
override val apiConfigurationName: String
get() = apiConfiguration.name
override val implementationConfigurationName: String
get() = implementationConfiguration.name
override val compileOnlyConfigurationName: String
get() = compileOnlyConfiguration.name
override val runtimeOnlyConfigurationName: String
get() = runtimeOnlyConfiguration.name
}
val GradleKpmFragment.path: String
get() = "${project.path}/${containingModule.name}/$fragmentName"
val GradleKpmFragment.containingVariants: Set<GradleKpmVariant>
get() = containingModule.variantsContainingFragment(this).map { it as GradleKpmVariant }.toSet()
@@ -1,49 +0,0 @@
/*
* 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
interface GradleKpmFragmentDependencyConfigurations : GradleKpmDependencyConfigurations {
/** This configuration includes the dependencies from the refines-parents */
val transitiveApiConfiguration: Configuration
/** This configuration includes the dependencies from the refines-parents */
val transitiveImplementationConfiguration: Configuration
/** This configuration includes the dependencies from the refines-parents */
val transitiveRuntimeOnlyConfiguration: Configuration
private class Impl(
override val apiConfiguration: Configuration,
override val implementationConfiguration: Configuration,
override val compileOnlyConfiguration: Configuration,
override val runtimeOnlyConfiguration: Configuration,
override val transitiveApiConfiguration: Configuration,
override val transitiveImplementationConfiguration: Configuration,
override val transitiveRuntimeOnlyConfiguration: Configuration
) : GradleKpmFragmentDependencyConfigurations
companion object {
fun create(
apiConfiguration: Configuration,
implementationConfiguration: Configuration,
compileOnlyConfiguration: Configuration,
runtimeOnlyConfiguration: Configuration,
transitiveApiConfiguration: Configuration,
transitiveImplementationConfiguration: Configuration,
transitiveRuntimeOnlyConfiguration: Configuration
): GradleKpmFragmentDependencyConfigurations = Impl(
apiConfiguration = apiConfiguration,
implementationConfiguration = implementationConfiguration,
compileOnlyConfiguration = compileOnlyConfiguration,
runtimeOnlyConfiguration = runtimeOnlyConfiguration,
transitiveApiConfiguration = transitiveApiConfiguration,
transitiveImplementationConfiguration = transitiveImplementationConfiguration,
transitiveRuntimeOnlyConfiguration = transitiveRuntimeOnlyConfiguration
)
}
}
@@ -1,53 +0,0 @@
/*
* 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.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.GradleKpmNameDisambiguation
interface GradleKpmFragmentDependencyConfigurationsFactory {
fun create(module: GradleKpmModule, names: GradleKpmNameDisambiguation): GradleKpmFragmentDependencyConfigurations
}
object GradleKpmDefaultFragmentDependencyConfigurationsFactory : GradleKpmFragmentDependencyConfigurationsFactory {
override fun create(module: GradleKpmModule, names: GradleKpmNameDisambiguation): GradleKpmFragmentDependencyConfigurations {
val configurations = module.project.configurations
val apiConfiguration = configurations.maybeCreate(names.disambiguateName("api"))
val implementationConfiguration = configurations.maybeCreate(names.disambiguateName("implementation"))
val compileOnlyConfiguration = configurations.maybeCreate(names.disambiguateName("compileOnly"))
val runtimeOnlyConfiguration = configurations.maybeCreate(names.disambiguateName("runtimeOnly"))
val transitiveApiConfiguration = configurations.maybeCreate(names.disambiguateName("transitiveApi"))
val transitiveImplementationConfiguration = configurations.maybeCreate(names.disambiguateName("transitiveImplementation"))
val transitiveRuntimeOnlyConfiguration = configurations.maybeCreate(names.disambiguateName("transitiveRuntimeOnly"))
listOf(
apiConfiguration,
implementationConfiguration,
compileOnlyConfiguration,
runtimeOnlyConfiguration,
transitiveApiConfiguration,
transitiveImplementationConfiguration,
transitiveRuntimeOnlyConfiguration
).forEach { configuration ->
configuration.isCanBeConsumed = false
configuration.isCanBeResolved = false
}
transitiveApiConfiguration.extendsFrom(apiConfiguration)
transitiveImplementationConfiguration.extendsFrom(implementationConfiguration)
transitiveRuntimeOnlyConfiguration.extendsFrom(runtimeOnlyConfiguration)
return GradleKpmFragmentDependencyConfigurations.create(
apiConfiguration = apiConfiguration,
implementationConfiguration = implementationConfiguration,
compileOnlyConfiguration = compileOnlyConfiguration,
runtimeOnlyConfiguration = runtimeOnlyConfiguration,
transitiveApiConfiguration = transitiveApiConfiguration,
transitiveImplementationConfiguration = transitiveImplementationConfiguration,
transitiveRuntimeOnlyConfiguration = transitiveRuntimeOnlyConfiguration
)
}
}
@@ -1,59 +0,0 @@
/*
* 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.artifacts.Configuration
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmFragmentFactory.FragmentConfigurator
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmFragmentFactory.FragmentInstantiator
/**
* Factory used by [GradleKpmModule] to polymorphic-ally create fragments/variants.
* Fragments are created in two stages with this factory:
*
* [FragmentInstantiator]:
* An Instantiator (unlike something called a 'Factory') will just provide a new instance.
* All objects referenced from the Fragment shall be already created and accessing them should be safe,
* whilst some additional configuration still hase to be done in the configuration step.
*
* [FragmentConfigurator]:
* After the fragment is instantiated, additional configuration (depending on the fragment instance) can be done.
* Typical configurations are:
* - Further setting up attributes of configurations (based upon the fragment itself)
* - Setting up additional Gradle tasks
* - Setting up publication
*/
class GradleKpmFragmentFactory<T : GradleKpmFragment>(
private val fragmentInstantiator: FragmentInstantiator<T>,
private val fragmentConfigurator: FragmentConfigurator<T>
) : NamedDomainObjectFactory<T> {
/**
* @see GradleKpmFragmentFactory
*/
interface FragmentInstantiator<out T : GradleKpmFragment> {
fun create(name: String): T
}
/**
* @see GradleKpmFragmentFactory
*/
interface FragmentConfigurator<in T : GradleKpmFragment> {
fun configure(fragment: T)
}
override fun create(name: String): T {
return fragmentInstantiator.create(name).apply(fragmentConfigurator::configure)
}
}
internal fun <T : GradleKpmFragment> Configuration.configure(
definition: GradleKpmConfigurationSetup<T>, fragment: T
) {
definition.attributes.setupAttributes(attributes, fragment)
definition.artifacts.setupArtifacts(outgoing, fragment)
definition.capabilities.setCapabilities(outgoing, fragment)
}
@@ -1,169 +0,0 @@
/*
* 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.artifacts.result.ResolvedDependencyResult
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution.ChooseVisibleSourceSets.MetadataProvider.ArtifactMetadataProvider
import org.jetbrains.kotlin.project.model.*
import org.jetbrains.kotlin.utils.addToStdlib.flattenTo
import java.io.File
import java.util.*
internal class GradleKpmFragmentGranularMetadataResolver(
private val requestingFragment: GradleKpmFragment,
private val refinesParentResolvers: Lazy<Iterable<GradleKpmFragmentGranularMetadataResolver>>
) {
val resolutions: Iterable<MetadataDependencyResolution> by lazy {
doResolveMetadataDependencies()
}
private val project: Project
get() = requestingFragment.containingModule.project
private val parentResultsByModuleIdentifier: Map<KpmModuleIdentifier, List<MetadataDependencyResolution>> by lazy {
refinesParentResolvers.value.flatMap { it.resolutions }.groupBy { it.dependency.toSingleKpmModuleIdentifier() }
}
private val moduleResolver = GradleKpmModuleDependencyResolver.getForCurrentBuild(project)
private val variantResolver = KpmGradleModuleVariantResolver.getForCurrentBuild(project)
private val fragmentResolver = KpmDefaultFragmentsResolver(variantResolver)
private val dependencyGraphResolver = GradleKpmDependencyGraphResolver(moduleResolver)
@Suppress("UNREACHABLE_CODE", "UNUSED_VARIABLE")
private fun doResolveMetadataDependencies(): Iterable<MetadataDependencyResolution> {
val configurationToResolve = configurationToResolveMetadataDependencies(requestingFragment.containingModule)
val resolvedComponentsByModuleId =
configurationToResolve.incoming.resolutionResult.allComponents.associateBy { it.toSingleKpmModuleIdentifier() }
val resolvedDependenciesByModuleId =
configurationToResolve.incoming.resolutionResult.allDependencies.filterIsInstance<ResolvedDependencyResult>()
.flatMap { dependency -> dependency.requested.toKpmModuleIdentifiers().map { id -> id to dependency } }.toMap()
val dependencyGraph = dependencyGraphResolver.resolveDependencyGraph(requestingFragment.containingModule)
if (dependencyGraph is KpmDependencyGraphResolution.Unknown)
error("unexpected failure in dependency graph resolution for $requestingFragment in $project")
dependencyGraph as GradleKpmDependencyGraph // refactor the type hierarchy to avoid this downcast? FIXME?
val fragmentsToInclude = requestingFragment.withRefinesClosure
val requestedDependencies = dependencyGraph.root.dependenciesByFragment.filterKeys { it in fragmentsToInclude }.values.flatten()
val visited = mutableSetOf<GradleKpmDependencyGraphNode>()
val fragmentResolutionQueue = ArrayDeque<GradleKpmDependencyGraphNode>(requestedDependencies)
val results = mutableSetOf<MetadataDependencyResolution>()
while (fragmentResolutionQueue.isNotEmpty()) {
val dependencyNode = fragmentResolutionQueue.removeFirst()
if (!visited.add(dependencyNode)) {
continue
}
val dependencyModule = dependencyNode.module
val fragmentVisibility = fragmentResolver.getChosenFragments(requestingFragment, dependencyModule)
val chosenFragments = fragmentVisibility as? KpmFragmentResolution.ChosenFragments
val visibleFragments = chosenFragments?.visibleFragments?.toList().orEmpty()
val visibleTransitiveDependencies =
dependencyNode.dependenciesByFragment.filterKeys { it in visibleFragments }.values.flattenTo(mutableSetOf())
fragmentResolutionQueue.addAll(visibleTransitiveDependencies.filter { it !in visited })
val resolvedComponentResult = dependencyNode.selectedComponent
val result = when (dependencyModule) {
is GradleKpmExternalPlainModule -> {
MetadataDependencyResolution.KeepOriginalDependency(resolvedComponentResult)
}
else -> run {
val metadataSourceComponent = dependencyNode.run { metadataSourceComponent ?: selectedComponent }
val visibleFragmentNames = visibleFragments.map { it.fragmentName }.toSet()
val visibleFragmentNamesExcludingVisibleByParents =
visibleFragmentNames.minus(fragmentsNamesVisibleByParents(metadataSourceComponent.toSingleKpmModuleIdentifier()))
/*
We can safely assume that a metadata extractor can be created, because the project structure metadata already
had to be read in order to create the Kotlin module and infer fragment visibility.
*/
val projectStructureMetadataExtractor: MppDependencyProjectStructureMetadataExtractor =
TODO("Implement for KPM. As it done for TCS")
val projectStructureMetadata = (dependencyModule as? GradleKpmExternalImportedModule)?.projectStructureMetadata
?: checkNotNull(projectStructureMetadataExtractor.getProjectStructureMetadata())
val metadataProvider = when (projectStructureMetadataExtractor) {
is ProjectMppDependencyProjectStructureMetadataExtractor -> TODO("Implement ProjectStructureMetadata for KPM")
is JarMppDependencyProjectStructureMetadataExtractor -> ArtifactMetadataProvider(
CompositeMetadataArtifactImpl(
moduleDependencyIdentifier = ModuleIds.fromComponent(project, metadataSourceComponent),
moduleDependencyVersion = metadataSourceComponent.moduleVersion?.version ?: "unspecified",
kotlinProjectStructureMetadata = projectStructureMetadata,
primaryArtifactFile = projectStructureMetadataExtractor.primaryArtifactFile,
hostSpecificArtifactFilesBySourceSetName = if (
dependencyModule is GradleKpmExternalImportedModule && chosenFragments != null
) resolveHostSpecificMetadataArtifacts(dependencyModule, chosenFragments) else emptyMap(),
)
)
}
MetadataDependencyResolution.ChooseVisibleSourceSets(
dependency = metadataSourceComponent,
projectStructureMetadata = projectStructureMetadata,
allVisibleSourceSetNames = visibleFragmentNames,
visibleSourceSetNamesExcludingDependsOn = visibleFragmentNamesExcludingVisibleByParents,
visibleTransitiveDependencies =
visibleTransitiveDependencies.map { resolvedDependenciesByModuleId.getValue(it.module.moduleIdentifier) }.toSet(),
metadataProvider = metadataProvider
)
}
}
results.add(result)
}
// FIXME this code is based on whole components; use module IDs with classifiers instead
val resultSourceComponents = results.mapTo(mutableSetOf()) { it.dependency }
resolvedComponentsByModuleId.values.minus(resultSourceComponents).forEach {
results.add(MetadataDependencyResolution.Exclude.Unrequested(it))
}
return results
}
private fun fragmentsNamesVisibleByParents(kotlinModuleIdentifier: KpmModuleIdentifier): MutableSet<String> {
val parentResolutionsForDependency = parentResultsByModuleIdentifier[kotlinModuleIdentifier].orEmpty()
return parentResolutionsForDependency.filterIsInstance<MetadataDependencyResolution.ChooseVisibleSourceSets>()
.flatMapTo(mutableSetOf()) { it.allVisibleSourceSetNames }
}
private fun resolveHostSpecificMetadataArtifacts(
dependencyModule: GradleKpmExternalImportedModule,
chosenFragments: KpmFragmentResolution.ChosenFragments,
): Map<String, File> {
val visibleFragments = chosenFragments.visibleFragments
val variantResolutions = chosenFragments.variantResolutions
val hostSpecificFragments = dependencyModule.hostSpecificFragments
return visibleFragments.intersect(hostSpecificFragments).mapNotNull { hostSpecificFragment ->
val relevantVariantResolution = variantResolutions
.filterIsInstance<KpmVariantResolution.KpmVariantMatch>()
// find some of our variants that resolved a dependency's variant containing the fragment
.find { hostSpecificFragment in it.chosenVariant.withRefinesClosure }
// resolve the dependencies of that variant getting the host-specific metadata artifact
@Suppress("UNREACHABLE_CODE", "UNUSED_VARIABLE")
relevantVariantResolution?.let { resolution ->
val configurationResolvingPlatformVariant =
(resolution.requestingVariant as GradleKpmVariant).compileDependenciesConfiguration
val hostSpecificArtifact: File? = TODO("Implement host-specific lookup for KPM as it done for TCS")
hostSpecificArtifact?.let { hostSpecificFragment.fragmentName to it }
}
}.toMap()
}
}
@@ -1,18 +0,0 @@
/*
* 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
internal class GradleKpmFragmentGranularMetadataResolverFactory {
private val resolvers = mutableMapOf<GradleKpmFragment, GradleKpmFragmentGranularMetadataResolver>()
fun getOrCreate(fragment: GradleKpmFragment): GradleKpmFragmentGranularMetadataResolver = resolvers.getOrPut(fragment) {
GradleKpmFragmentGranularMetadataResolver(fragment, lazy {
fragment.refinesClosure.map { refinesFragment ->
getOrCreate(refinesFragment)
}
})
}
}
@@ -1,113 +0,0 @@
/*
* 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.Action
import org.gradle.api.NamedDomainObjectProvider
import org.gradle.api.Project
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.provider.Provider
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.mpp.toKpmModuleDependency
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.sources.FragmentConsistencyChecker
import org.jetbrains.kotlin.gradle.plugin.sources.FragmentConsistencyChecks
import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
import org.jetbrains.kotlin.gradle.utils.runProjectConfigurationHealthCheckWhenEvaluated
import org.jetbrains.kotlin.project.model.KpmModuleDependency
import org.jetbrains.kotlin.tooling.core.MutableExtras
import org.jetbrains.kotlin.tooling.core.mutableExtrasOf
import javax.inject.Inject
abstract class GradleKpmFragmentInternal @Inject constructor(
final override val containingModule: GradleKpmModule,
final override val fragmentName: String,
dependencyConfigurations: GradleKpmFragmentDependencyConfigurations
) : GradleKpmFragment,
GradleKpmFragmentDependencyConfigurations by dependencyConfigurations {
final override fun getName(): String = fragmentName
final override val project: Project // overriding with final to avoid warnings
get() = super.project
override val extras: MutableExtras = mutableExtrasOf()
// TODO pull up to KotlinModuleFragment
// FIXME apply to compilation
// FIXME check for consistency
override val languageSettings: LanguageSettingsBuilder = DefaultLanguageSettingsBuilder(project)
override fun refines(other: GradleKpmFragment) {
checkCanRefine(other)
refines(containingModule.fragments.named(other.name))
}
override fun refines(other: NamedDomainObjectProvider<GradleKpmFragment>) {
_declaredRefinesDependencies.add(other)
other.configure { checkCanRefine(it) }
project.addExtendsFromRelation(
this.transitiveApiConfiguration.name, other.get().transitiveApiConfiguration.name
)
project.addExtendsFromRelation(
this.transitiveImplementationConfiguration.name, other.get().transitiveImplementationConfiguration.name
)
project.addExtendsFromRelation(
this.transitiveRuntimeOnlyConfiguration.name, other.get().transitiveRuntimeOnlyConfiguration.name
)
project.runProjectConfigurationHealthCheckWhenEvaluated {
kotlinGradleFragmentConsistencyChecker.runAllChecks(this@GradleKpmFragmentInternal, other.get())
}
}
private fun checkCanRefine(other: GradleKpmFragment) {
check(containingModule == other.containingModule) {
"Fragments can only refine each other within one module. Can't make $this refine $other"
}
}
override fun dependencies(configure: KotlinDependencyHandler.() -> Unit): Unit =
DefaultKotlinDependencyHandler(this, project).run(configure)
override fun dependencies(configure: Action<KotlinDependencyHandler>) =
dependencies { configure.execute(this) }
private val _declaredRefinesDependencies = mutableSetOf<Provider<GradleKpmFragment>>()
override val declaredRefinesDependencies: Iterable<GradleKpmFragment>
get() = _declaredRefinesDependencies.map { it.get() }.toSet()
// TODO: separate the declared module dependencies and exported module dependencies? we need this to keep implementation dependencies
// out of the consumer's metadata compilations compile classpath; however, Native variants must expose implementation as API
// anyway, so for now all fragments follow that behavior
override val declaredModuleDependencies: Iterable<KpmModuleDependency>
get() = listOf(apiConfiguration, implementationConfiguration).flatMapTo(mutableSetOf()) { exportConfiguration ->
exportConfiguration.allDependencies.map { dependency -> dependency.toKpmModuleDependency(project) }
}
override val kotlinSourceRoots: SourceDirectorySet =
project.objects.sourceDirectorySet(
"$fragmentName.kotlin", "Kotlin sources for fragment $fragmentName"
)
override fun toString(): String = "fragment $fragmentName in $containingModule"
private val kotlinGradleFragmentConsistencyChecker =
FragmentConsistencyChecker(
unitsName = "fragments",
name = { name },
checks = FragmentConsistencyChecks<GradleKpmFragment>(
unitName = "fragment",
languageSettings = { languageSettings }
).allChecks
)
}
@@ -1,60 +0,0 @@
/*
* 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.provider.Provider
import org.gradle.language.base.plugins.LifecycleBasePlugin
import java.io.File
typealias SourceRoots = Iterable<File>
typealias SourceRootsProvider = Provider<out SourceRoots>
typealias MultipleSourceRootsProvider = Provider<out Iterable<SourceRootsProvider>>
typealias SourceRootsProvidersByFragment = Map<GradleKpmFragment, SourceRootsProvider>
/** Note: the API is [Provider]-based rather than FileCollection-based because FileCollection API erases the internal structure of the
* file sets, and this internal structure is currently needed for correctly inferring Java source roots from the sources added to the
* JVM compilations (it is important to pass sources in SourceDirectorySets) */
open class GradleKpmFragmentSourcesProvider {
protected open fun getSourcesFromFragmentsAsMap(
fragments: Iterable<GradleKpmFragment>
): SourceRootsProvidersByFragment =
fragments.associateWith { it.project.provider { it.kotlinSourceRoots } }
open fun getFragmentOwnSources(fragment: GradleKpmFragment): SourceRootsProvider =
getSourcesFromFragmentsAsMap(listOf(fragment)).values.single()
open fun getAllFragmentSourcesAsMap(module: GradleKpmModule): SourceRootsProvidersByFragment =
getSourcesFromFragmentsAsMap(module.fragments)
open fun getSourcesFromRefinesClosureAsMap(fragment: GradleKpmFragment): SourceRootsProvidersByFragment =
getSourcesFromFragmentsAsMap(fragment.withRefinesClosure)
open fun getSourcesFromRefinesClosure(fragment: GradleKpmFragment): MultipleSourceRootsProvider =
fragment.project.provider { getSourcesFromRefinesClosureAsMap(fragment).values }
open fun getCommonSourcesFromRefinesClosure(fragment: GradleKpmFragment): MultipleSourceRootsProvider {
val containingModule = fragment.containingModule
val project = containingModule.project
getSourcesFromRefinesClosureAsMap(fragment)
return project.provider {
fragment.withRefinesClosure.filter {
// Every fragment refined by some other fragment should be considered common, even if it is included in just one variant
it.containingVariants != setOf(it)
}.map { project.provider { it.kotlinSourceRoots } }
}
}
}
open class LifecycleTasksManager(private val project: Project) {
open fun registerClassesTask(compilationData: GradleKpmCompilationData<*>) = with(project) {
val classesTaskName = compilationData.compileAllTaskName
val classesTask = project.tasks.register(classesTaskName) { classesTask ->
classesTask.inputs.files(compilationData.output.allOutputs)
}
project.tasks.named(LifecycleBasePlugin.BUILD_TASK_NAME).configure { it.dependsOn(classesTask) }
}
}
@@ -1,43 +0,0 @@
/*
* 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.Dependency
import org.gradle.jvm.tasks.Jar
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.disambiguateName
import org.jetbrains.kotlin.gradle.targets.metadata.filesWithUnpackedArchives
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION
/**
* Will register a 'hostSpecificMetadataJar' [Jar] task containing compilation outputs of host specific metadata.
* Will add this jar artifact to the given configuration
*/
val GradleKpmHostSpecificMetadataArtifact = GradleKpmConfigurationArtifactsSetup<GradleKpmNativeVariantInternal> artifacts@{
val hostSpecificMetadataElements = fragment.hostSpecificMetadataElementsConfiguration ?: return@artifacts
val hostSpecificMetadataJar = project.registerTask<Jar>(fragment.disambiguateName("hostSpecificMetadataJar")) { jar ->
jar.archiveClassifier.set("metadata")
jar.archiveAppendix.set(fragment.disambiguateName(""))
project.metadataCompilationRegistryByModuleId.getValue(fragment.containingModule.moduleIdentifier)
.withAll { metadataCompilation ->
val metadataFragment = metadataCompilation.fragment
if (metadataCompilation is GradleKpmNativeFragmentMetadataCompilationData) {
jar.from(project.files(project.provider {
if (metadataFragment in fragment.withRefinesClosure && metadataFragment.isNativeHostSpecific())
project.filesWithUnpackedArchives(metadataCompilation.output.allOutputs, setOf(KLIB_FILE_EXTENSION))
else emptyList<Any>()
})) { spec -> spec.into(metadataFragment.name) }
}
}
}
artifact(hostSpecificMetadataJar)
hostSpecificMetadataElements.dependencies.addAllLater(project.objects.listProperty(Dependency::class.java).apply {
set(project.provider { fragment.apiElementsConfiguration.allDependencies })
})
}
@@ -1,64 +0,0 @@
/*
* 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.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.archivesName
import org.jetbrains.kotlin.gradle.utils.configureExperimentalTryK2
import javax.inject.Inject
abstract class GradleKpmJvmVariant @Inject constructor(
containingModule: GradleKpmModule,
fragmentName: String,
dependencyConfigurations: GradleKpmFragmentDependencyConfigurations,
compileDependenciesConfiguration: Configuration,
apiElementsConfiguration: Configuration,
runtimeDependenciesConfiguration: Configuration,
runtimeElementsConfiguration: Configuration
) : GradleKpmPublishedVariantWithRuntime(
containingModule = containingModule,
fragmentName = fragmentName,
dependencyConfigurations = dependencyConfigurations,
compileDependencyConfiguration = compileDependenciesConfiguration,
apiElementsConfiguration = apiElementsConfiguration,
runtimeDependencyConfiguration = runtimeDependenciesConfiguration,
runtimeElementsConfiguration = runtimeElementsConfiguration
) {
override val compilationData: GradleKpmJvmVariantCompilationData by lazy { GradleKpmJvmVariantCompilationData(this) }
override val platformType: KotlinPlatformType
get() = KotlinPlatformType.jvm
}
class GradleKpmJvmVariantCompilationData(val variant: GradleKpmJvmVariant) : GradleKpmVariantCompilationDataInternal<KotlinJvmOptions> {
override val owner: GradleKpmJvmVariant get() = variant
override val compilerOptions: HasCompilerOptions<KotlinJvmCompilerOptions> =
object : HasCompilerOptions<KotlinJvmCompilerOptions> {
override val options: KotlinJvmCompilerOptions = variant.project.objects
.newInstance(KotlinJvmCompilerOptionsDefault::class.java)
.configureExperimentalTryK2(variant.project)
}
// TODO pull out to the variant
@Suppress("DEPRECATION")
@Deprecated("Replaced with compilerOptions.options", replaceWith = ReplaceWith("compilerOptions.options"))
override val kotlinOptions: KotlinJvmOptions = object : KotlinJvmOptions {
override val options: KotlinJvmCompilerOptions
get() = compilerOptions.options
}
}
internal fun GradleKpmVariant.ownModuleName(): String {
val project = containingModule.project
val baseName = project.archivesName.orNull
?: project.name
val suffix = if (containingModule.moduleClassifier == null) "" else "_${containingModule.moduleClassifier}"
return filterModuleName("$baseName$suffix")
}
@@ -1,97 +0,0 @@
/*
* 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.
*/
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.FragmentNameDisambiguationOmittingMain
typealias GradleKpmJvmVariantFactory = GradleKpmFragmentFactory<GradleKpmJvmVariant>
fun GradleKpmJvmVariantFactory(
module: GradleKpmModule, config: GradleKpmJvmVariantConfig = GradleKpmJvmVariantConfig()
): GradleKpmJvmVariantFactory = GradleKpmJvmVariantFactory(
GradleKpmJvmVariantInstantiator(module, config),
GradleKpmJvmVariantConfigurator(config)
)
data class GradleKpmJvmVariantConfig(
val dependenciesConfigurationFactory: GradleKpmFragmentDependencyConfigurationsFactory
= GradleKpmDefaultFragmentDependencyConfigurationsFactory,
val compileDependencies: GradleKpmConfigurationSetup<GradleKpmJvmVariant>
= DefaultKotlinCompileDependenciesDefinition,
val runtimeDependencies: GradleKpmConfigurationSetup<GradleKpmJvmVariant>
= DefaultKotlinRuntimeDependenciesDefinition,
val apiElements: GradleKpmConfigurationSetup<GradleKpmJvmVariant>
= DefaultKotlinApiElementsDefinition + GradleKpmCompilationOutputsJarArtifact,
val runtimeElements: GradleKpmConfigurationSetup<GradleKpmJvmVariant>
= DefaultKotlinRuntimeElementsDefinition,
val compileTaskConfigurator: GradleKpmCompileTaskConfigurator<GradleKpmJvmVariant>
= GradleKpmJvmCompileTaskConfigurator,
val sourceArchiveTaskConfigurator: GradleKpmSourceArchiveTaskConfigurator<GradleKpmJvmVariant>
= GradleKpmDefaultKotlinSourceArchiveTaskConfigurator,
val sourceDirectoriesConfigurator: GradleKpmSourceDirectoriesConfigurator<GradleKpmJvmVariant>
= GradleKpmDefaultSourceDirectoriesConfigurator,
val publicationConfigurator: GradleKpmPublicationConfigurator<GradleKpmJvmVariant>
= GradleKpmPublicationConfigurator.SingleVariantPublication
)
class GradleKpmJvmVariantInstantiator internal constructor(
private val module: GradleKpmModule,
private val config: GradleKpmJvmVariantConfig
) : GradleKpmFragmentFactory.FragmentInstantiator<GradleKpmJvmVariant> {
override fun create(name: String): GradleKpmJvmVariant {
val names = FragmentNameDisambiguationOmittingMain(module, name)
val context = GradleKpmFragmentConfigureContextImpl(
module, config.dependenciesConfigurationFactory.create(module, names), names
)
return module.project.objects.newInstance(
GradleKpmJvmVariant::class.java,
module,
name,
context.dependencies,
config.compileDependencies.provider.getConfiguration(context).also { configuration ->
config.compileDependencies.relations.setupExtendsFromRelations(configuration, context)
},
config.apiElements.provider.getConfiguration(context).also { configuration ->
config.apiElements.relations.setupExtendsFromRelations(configuration, context)
},
config.runtimeDependencies.provider.getConfiguration(context).also { configuration ->
config.runtimeElements.relations.setupExtendsFromRelations(configuration, context)
},
config.runtimeElements.provider.getConfiguration(context).also { configuration ->
config.runtimeElements.relations.setupExtendsFromRelations(configuration, context)
}
)
}
}
class GradleKpmJvmVariantConfigurator internal constructor(
private val config: GradleKpmJvmVariantConfig
) : GradleKpmFragmentFactory.FragmentConfigurator<GradleKpmJvmVariant> {
override fun configure(fragment: GradleKpmJvmVariant) {
fragment.compileDependenciesConfiguration.configure(config.compileDependencies, fragment)
fragment.runtimeDependenciesConfiguration.configure(config.runtimeDependencies, fragment)
fragment.apiElementsConfiguration.configure(config.apiElements, fragment)
fragment.runtimeElementsConfiguration.configure(config.runtimeElements, fragment)
config.sourceDirectoriesConfigurator.configure(fragment)
config.compileTaskConfigurator.registerCompileTasks(fragment)
config.sourceArchiveTaskConfigurator.registerSourceArchiveTask(fragment)
config.publicationConfigurator.configure(fragment)
}
}
@@ -1,230 +0,0 @@
/*
* 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.DefaultTask
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.archivesName
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.disambiguateName
import org.jetbrains.kotlin.gradle.targets.metadata.ResolvedMetadataFilesProvider
import org.jetbrains.kotlin.gradle.targets.native.NativeCompilerOptions
import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.gradle.utils.newProperty
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
interface GradleKpmMetadataCompilationData<T : KotlinCommonOptions> : GradleKpmCompilationData<T> {
val isActive: Boolean
}
interface GradleKpmCommonFragmentMetadataCompilationData : GradleKpmMetadataCompilationData<KotlinMultiplatformCommonOptions>
internal abstract class GradleKpmAbstractFragmentMetadataCompilationData<T : KotlinCommonOptions>(
final override val project: Project,
val fragment: GradleKpmFragment,
private val module: GradleKpmModule,
private val compileAllTask: TaskProvider<DefaultTask>,
val metadataCompilationRegistry: MetadataCompilationRegistry,
private val resolvedMetadataFiles: Lazy<Iterable<ResolvedMetadataFilesProvider>>
) : GradleKpmMetadataCompilationData<T> {
override val owner
get() = project.topLevelExtension
override val compilationPurpose: String
get() = fragment.fragmentName
override val compilationClassifier: String
get() = lowerCamelCaseName(module.name, "metadata")
override val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet>
get() = mapOf(fragment.fragmentName to fragment.kotlinSourceRoots)
override val compileKotlinTaskName: String
get() = lowerCamelCaseName("compile", fragment.disambiguateName(""), "KotlinMetadata")
override val compileAllTaskName: String
get() = compileAllTask.name
override var compileDependencyFiles: FileCollection by project.newProperty {
TODO("""Provide Compile Dependency Files.
| See KotlinMetadataTargetConfigurator::configureMetadataDependenciesForCompilation for reference""".trimMargin())
}
override val output: KotlinCompilationOutput = DefaultKotlinCompilationOutput(
project,
project.provider { project.buildDir.resolve("processedResources/${fragment.disambiguateName("metadata")}") }
)
final override val languageSettings: LanguageSettingsBuilder = fragment.languageSettings
override val platformType: KotlinPlatformType
get() = KotlinPlatformType.common
override val moduleName: String
get() { // FIXME deduplicate with ownModuleName
val baseName = project.archivesName.orNull
?: project.name
val suffix = if (module.moduleClassifier == null) "" else "_${module.moduleClassifier}"
return filterModuleName("$baseName$suffix")
}
override val friendPaths: Iterable<FileCollection>
get() = metadataCompilationRegistry.run {
fragment.refinesClosure
.map {
val compilation = metadataCompilationRegistry.getForFragmentOrNull(it)
?: return@map project.files()
compilation.output.classesDirs
}
}
}
internal open class GradleKpmCommonFragmentMetadataCompilationDataImpl(
project: Project,
fragment: GradleKpmFragment,
module: GradleKpmModule,
compileAllTask: TaskProvider<DefaultTask>,
metadataCompilationRegistry: MetadataCompilationRegistry,
resolvedMetadataFiles: Lazy<Iterable<ResolvedMetadataFilesProvider>>
) : GradleKpmAbstractFragmentMetadataCompilationData<KotlinMultiplatformCommonOptions>(
project,
fragment,
module,
compileAllTask,
metadataCompilationRegistry,
resolvedMetadataFiles
), GradleKpmCommonFragmentMetadataCompilationData {
override val isActive: Boolean
get() = !fragment.isNativeShared() &&
fragment.containingVariants.run {
!all { it.platformType in setOf(KotlinPlatformType.androidJvm, KotlinPlatformType.jvm) } &&
mapTo(hashSetOf()) { it.platformType }.size > 1
}
override val compilerOptions: HasCompilerOptions<KotlinMultiplatformCommonCompilerOptions> =
object : HasCompilerOptions<KotlinMultiplatformCommonCompilerOptions> {
override val options: KotlinMultiplatformCommonCompilerOptions = project.objects
.newInstance(KotlinMultiplatformCommonCompilerOptionsDefault::class.java)
.configureExperimentalTryK2(project)
}
@Suppress("DEPRECATION")
@Deprecated("Replaced with compilerOptions.options", replaceWith = ReplaceWith("compilerOptions.options"))
override val kotlinOptions: KotlinMultiplatformCommonOptions = object : KotlinMultiplatformCommonOptions {
override val options: KotlinMultiplatformCommonCompilerOptions
get() = compilerOptions.options
}
}
interface GradleKpmNativeFragmentMetadataCompilationData :
GradleKpmMetadataCompilationData<KotlinCommonOptions>,
GradleKpmNativeCompilationData<KotlinCommonOptions>
internal fun GradleKpmFragment.isNativeShared(): Boolean =
containingVariants.run {
any() && all { it.platformType == KotlinPlatformType.native }
}
internal fun GradleKpmFragment.isNativeHostSpecific(): Boolean =
this.project.future { this@isNativeHostSpecific in getHostSpecificFragments(containingModule) }.lenient.getOrNull() ?: false
internal open class GradleKpmNativeFragmentMetadataCompilationDataImpl(
project: Project,
fragment: GradleKpmFragment,
module: GradleKpmModule,
compileAllTask: TaskProvider<DefaultTask>,
metadataCompilationRegistry: MetadataCompilationRegistry,
resolvedMetadataFiles: Lazy<Iterable<ResolvedMetadataFilesProvider>>
) : GradleKpmAbstractFragmentMetadataCompilationData<KotlinCommonOptions>(
project,
fragment,
module,
compileAllTask,
metadataCompilationRegistry,
resolvedMetadataFiles
), GradleKpmNativeFragmentMetadataCompilationData {
override val compileKotlinTaskName: String
get() = lowerCamelCaseName("compile", fragment.disambiguateName(""), "KotlinNativeMetadata")
override val isActive: Boolean
get() = fragment.isNativeShared() && fragment.containingVariants.count() > 1
override val compilerOptions: HasCompilerOptions<KotlinCommonCompilerOptions> = NativeCompilerOptions(project)
@Suppress("DEPRECATION")
@Deprecated("Replaced with compilerOptions.options", replaceWith = ReplaceWith("compilerOptions.options"))
override val kotlinOptions: KotlinCommonOptions = object : KotlinCommonOptions {
override val options: KotlinCommonCompilerOptions
get() = compilerOptions.options
}
override val konanTarget: KonanTarget
get() {
val nativeVariants =
fragment.containingVariants.filterIsInstance<GradleKpmNativeVariantInternal>()
return nativeVariants.firstOrNull { it.konanTarget.enabledOnCurrentHost }?.konanTarget
?: nativeVariants.firstOrNull()?.konanTarget
?: HostManager.host
}
@Suppress("DeprecatedCallableAddReplaceWith")
@Deprecated(
"Please declare explicit dependency on kotlinx-cli. This option has no longer effect since 1.9.0",
level = DeprecationLevel.ERROR
)
override val enableEndorsedLibs: Boolean
get() = false
}
// TODO think about more generic case: a fragment that can be compiled by an arbitrary compiler
// what tasks should we create? should there be a generic task for that?
internal class MetadataCompilationRegistry {
private val commonCompilationDataPerFragment = LinkedHashMap<GradleKpmFragment, GradleKpmCommonFragmentMetadataCompilationDataImpl>()
private val nativeCompilationDataPerFragment = LinkedHashMap<GradleKpmFragment, GradleKpmNativeFragmentMetadataCompilationDataImpl>()
fun registerCommon(fragment: GradleKpmFragment, compilationData: GradleKpmCommonFragmentMetadataCompilationDataImpl) {
commonCompilationDataPerFragment.compute(fragment) { _, existing ->
existing?.let { error("common compilation data for fragment $fragment already registered") }
compilationData
}
withAllCommonCallbacks.forEach { it.invoke(compilationData) }
}
fun registerNative(fragment: GradleKpmFragment, compilationData: GradleKpmNativeFragmentMetadataCompilationDataImpl) {
nativeCompilationDataPerFragment.compute(fragment) { _, existing ->
existing?.let { error("native compilation data for fragment $fragment already registered") }
compilationData
}
withAllNativeCallbacks.forEach { it.invoke(compilationData) }
}
fun getForFragmentOrNull(fragment: GradleKpmFragment): GradleKpmAbstractFragmentMetadataCompilationData<*>? =
listOf(commonCompilationDataPerFragment.getValue(fragment), nativeCompilationDataPerFragment.getValue(fragment)).singleOrNull {
it.isActive
}
private val withAllCommonCallbacks = mutableListOf<(GradleKpmAbstractFragmentMetadataCompilationData<*>) -> Unit>()
private val withAllNativeCallbacks = mutableListOf<(GradleKpmAbstractFragmentMetadataCompilationData<*>) -> Unit>()
fun withAll(action: (GradleKpmAbstractFragmentMetadataCompilationData<*>) -> Unit) {
commonCompilationDataPerFragment.forEach { action(it.value) }
nativeCompilationDataPerFragment.forEach { action(it.value) }
withAllCommonCallbacks += action
withAllNativeCallbacks += action
}
}
@@ -1,104 +0,0 @@
/*
* 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.DefaultTask
import org.gradle.api.file.FileCollection
import org.gradle.api.model.ObjectFactory
import org.gradle.api.tasks.*
import org.gradle.work.DisableCachingByDefault
import org.gradle.work.NormalizeLineEndings
import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.disambiguateName
import org.jetbrains.kotlin.gradle.plugin.mpp.transformMetadataLibrariesForBuild
import org.jetbrains.kotlin.gradle.targets.metadata.ResolvedMetadataFilesProvider
import org.jetbrains.kotlin.gradle.utils.getValue
import java.io.File
import javax.inject.Inject
@DisableCachingByDefault
internal open class GradleKpmMetadataDependencyTransformationTask
@Inject constructor(
@get:Internal
@field:Transient
val fragment: GradleKpmFragment,
private val objectFactory: ObjectFactory,
//FIXME annotations
private val transformation: GradleKpmFragmentGranularMetadataResolver
) : DefaultTask() {
@get:OutputDirectory
val outputsDir: File by project.provider {
project.buildDir.resolve("kotlinFragmentDependencyMetadata").resolve(fragment.disambiguateName(""))
}
@Suppress("unused") // Gradle input
@get:IgnoreEmptyDirectories
@get:NormalizeLineEndings
@get:InputFiles
@get:PathSensitive(PathSensitivity.RELATIVE)
internal val allSourceSetsMetadataConfiguration: FileCollection by lazy {
project.files(resolvableMetadataConfiguration(fragment.containingModule))
}
@Suppress("unused") // Gradle input
@get:Input
internal val inputFragmentsAndVariants: Map<String, Iterable<String>> by project.provider {
val participatingFragments = fragment.withRefinesClosure
participatingFragments.associateWith { it.containingVariants }
.entries.associate { (fragment, variants) ->
fragment.name to variants.map { it.fragmentName }.sorted()
}
}
@Suppress("unused") // Gradle input
@get:Input
internal val inputVariantDependencies: Map<String, Set<List<String?>>> by project.provider {
val participatingFragments = fragment.withRefinesClosure
val participatingCompilations = participatingFragments.flatMap { it.containingVariants }
participatingCompilations.associate { variant ->
variant.fragmentName to variant.compileDependenciesConfiguration
.allDependencies.map { listOf(it.group, it.name, it.version) }.toSet()
}
}
@get:Internal
@delegate:Transient // exclude from Gradle instant execution state
internal val metadataDependencyResolutions: Iterable<MetadataDependencyResolution> by project.provider {
transformation.resolutions
}
@get:Internal
internal val filesByResolution: Map<out MetadataDependencyResolution, FileCollection>
get() = metadataDependencyResolutions
.filterIsInstance<MetadataDependencyResolution.ChooseVisibleSourceSets>()
.associateWith { chooseVisibleSourceSets ->
project.files(objectFactory.transformMetadataLibrariesForBuild(chooseVisibleSourceSets, outputsDir, materializeFiles = false))
.builtBy(this)
}
@TaskAction
fun transformMetadata() {
if (outputsDir.isDirectory) {
outputsDir.deleteRecursively()
}
outputsDir.mkdirs()
metadataDependencyResolutions
.filterIsInstance<MetadataDependencyResolution.ChooseVisibleSourceSets>()
.forEach { chooseVisibleSourceSets ->
objectFactory.transformMetadataLibrariesForBuild(chooseVisibleSourceSets, outputsDir, materializeFiles = true)
}
}
}
internal class FragmentResolvedMetadataProvider(
taskProvider: TaskProvider<out GradleKpmMetadataDependencyTransformationTask>
) : ResolvedMetadataFilesProvider {
override val buildDependencies: Iterable<TaskProvider<*>> = listOf(taskProvider)
override val metadataResolutions: Iterable<MetadataDependencyResolution> by taskProvider.map { it.metadataDependencyResolutions }
override val metadataFilesByResolution: Map<out MetadataDependencyResolution, FileCollection> by taskProvider.map { it.filesByResolution }
}
@@ -1,69 +0,0 @@
/*
* 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.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
import org.jetbrains.kotlin.project.model.KpmModule
import org.jetbrains.kotlin.project.model.KpmModuleIdentifier
import org.jetbrains.kotlin.project.model.KpmCompilerPlugin
interface GradleKpmModule : KpmModule, Named, HasKotlinDependencies {
val project: Project
val moduleClassifier: String?
override val fragments: ExtensiblePolymorphicDomainObjectContainer<GradleKpmFragment>
// TODO DSL & build script model: find a way to create a flexible typed view on fragments?
override val variants: NamedDomainObjectSet<GradleKpmVariant>
override val plugins: Set<KpmCompilerPlugin>
val isPublic: Boolean
fun ifMadePublic(action: () -> Unit)
fun makePublic()
companion object {
val KpmModuleIdentifier.moduleName get() = moduleClassifier ?: MAIN_MODULE_NAME
const val MAIN_MODULE_NAME = "main"
const val TEST_MODULE_NAME = "test"
}
override fun getName(): String = when (val classifier = moduleClassifier) {
null -> MAIN_MODULE_NAME
else -> classifier
}
// DSL
val common: GradleKpmFragment
get() = fragments.getByName(GradleKpmFragment.COMMON_FRAGMENT_NAME)
fun common(configure: GradleKpmFragment.() -> Unit) =
common.configure()
override fun dependencies(configure: KotlinDependencyHandler.() -> Unit) =
common.dependencies(configure)
override fun dependencies(configure: Action<KotlinDependencyHandler>) =
dependencies { configure.execute(this) }
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
}
@@ -1,21 +0,0 @@
/*
* Copyright 2010-2022 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.capabilities.Capability
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.ComputedCapability
val GradleKpmModuleCapability = GradleKpmConfigurationCapabilitiesSetup<GradleKpmFragment> {
capability(fragment.containingModule.moduleCapability ?: return@GradleKpmConfigurationCapabilitiesSetup)
}
internal fun setModuleCapability(configuration: Configuration, module: GradleKpmModule) {
configuration.outgoing.capability(module.moduleCapability ?: return)
}
internal val GradleKpmModule.moduleCapability: Capability?
get() = if (moduleClassifier != null) ComputedCapability.fromModule(this) else null
@@ -9,106 +9,14 @@ import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.component.*
import org.gradle.api.artifacts.result.ResolvedComponentResult
import org.gradle.api.artifacts.result.ResolvedDependencyResult
import org.gradle.api.artifacts.result.ResolvedVariantResult
import org.gradle.api.capabilities.Capability
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
import org.jetbrains.kotlin.gradle.plugin.mpp.GradleProjectModuleBuilder
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinProjectStructureMetadata
import org.jetbrains.kotlin.gradle.plugin.mpp.ProjectStructureMetadataModuleBuilder
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.utils.buildPathCompat
import org.jetbrains.kotlin.gradle.utils.getOrPutRootProjectProperty
import org.jetbrains.kotlin.project.model.*
class GradleKpmModuleDependencyResolver(
private val gradleComponentResultResolver: GradleKpmComponentResultCachingResolver,
private val projectStructureMetadataModuleBuilder: ProjectStructureMetadataModuleBuilder,
private val projectModuleBuilder: GradleProjectModuleBuilder,
) : KpmModuleDependencyResolver {
override fun resolveDependency(requestingModule: KpmModule, moduleDependency: KpmModuleDependency): KpmModule? {
require(requestingModule is GradleKpmModule)
val project = requestingModule.project
val component = gradleComponentResultResolver.resolveModuleDependencyAsComponentResult(requestingModule, moduleDependency)
val id = component?.id
//FIXME multiple?
val classifier = moduleClassifiersFromCapabilities(component?.variants?.flatMap { it.capabilities }.orEmpty()).single()
@Suppress("DEPRECATION")
return when {
id is ProjectComponentIdentifier && id.build.isCurrentBuild ->
projectModuleBuilder.buildModulesFromProject(project.project(id.projectPath))
.find { it.moduleIdentifier.moduleClassifier == classifier }
id is ModuleComponentIdentifier -> {
val metadata = getProjectStructureMetadata(
project,
component,
// TODO: consistent choice of configurations across multiple resolvers?
configurationToResolveMetadataDependencies(requestingModule),
moduleDependency.moduleIdentifier
) ?: return null
val result = projectStructureMetadataModuleBuilder.getModule(component, metadata)
result
}
else -> null
}
}
companion object {
fun getForCurrentBuild(project: Project): KpmModuleDependencyResolver {
val extraPropertyName = "org.jetbrains.kotlin.dependencyResolution.moduleResolver.${project.getKotlinPluginVersion()}"
return project.getOrPutRootProjectProperty(extraPropertyName) {
val componentResultResolver = GradleKpmComponentResultCachingResolver.getForCurrentBuild(project)
val metadataModuleBuilder = ProjectStructureMetadataModuleBuilder()
val projectModuleBuilder = GradleProjectModuleBuilder(true)
GradleKpmCachingModuleDependencyResolver(
GradleKpmModuleDependencyResolver(componentResultResolver, metadataModuleBuilder, projectModuleBuilder)
)
}
}
}
}
// refactor extract to a separate class/interface
// TODO think about multi-variant stub modules for non-Kotlin modules which got more than one chosen variant
internal fun buildSyntheticPlainModule(
resolvedComponentResult: ResolvedComponentResult,
singleVariantName: String,
): GradleKpmExternalPlainModule {
val moduleDependency = resolvedComponentResult.toKpmModuleDependency()
return GradleKpmExternalPlainModule(KpmBasicModule(moduleDependency.moduleIdentifier).apply {
KpmBasicVariant(this@apply, singleVariantName, DefaultLanguageSettingsBuilder(TODO())).apply {
fragments.add(this)
this.declaredModuleDependencies.addAll(
resolvedComponentResult.dependencies
.filterIsInstance<ResolvedDependencyResult>()
.map { it.selected.toKpmModuleDependency() }
)
}
})
}
internal class GradleKpmExternalPlainModule(private val moduleData: KpmBasicModule) : KpmModule by moduleData {
override fun toString(): String = "external plain $moduleData"
val singleVariant: KpmVariant
get() = moduleData.variants.singleOrNull()
?: error("synthetic $moduleData was expected to have a single variant, got: ${moduleData.variants}")
}
internal class GradleKpmExternalImportedModule(
private val moduleData: KpmBasicModule,
val projectStructureMetadata: KotlinProjectStructureMetadata,
val hostSpecificFragments: Set<KpmFragment>,
) : KpmModule by moduleData {
val hasLegacyMetadataModule = !projectStructureMetadata.isPublishedAsRoot
override fun toString(): String = "imported $moduleData"
}
private fun ModuleComponentIdentifier.toSingleKpmModuleIdentifier(classifier: String? = null): KpmMavenModuleIdentifier =
KpmMavenModuleIdentifier(moduleIdentifier.group, moduleIdentifier.name, classifier)
@@ -157,28 +65,6 @@ internal fun moduleClassifiersFromCapabilities(capabilities: Iterable<Capability
return if (classifierCapabilities.none()) listOf(null) else classifierCapabilities.map { it.name.substringAfterLast("..") /*FIXME invent a more stable scheme*/ }
}
internal fun ComponentSelector.toKpmModuleIdentifiers(): Iterable<KpmModuleIdentifier> {
val moduleClassifiers = moduleClassifiersFromCapabilities(requestedCapabilities)
return when (this) {
is ProjectComponentSelector -> {
val buildPath = if (GradleVersion.current() >= GradleVersion.version("8.2")) buildPath
else @Suppress("DEPRECATION") ":$buildName"
moduleClassifiers.map { KpmLocalModuleIdentifier(buildPath, projectPath, it) }
}
is ModuleComponentSelector -> moduleClassifiers.map { KpmMavenModuleIdentifier(moduleIdentifier.group, moduleIdentifier.name, it) }
else -> error("unexpected component selector")
}
}
internal fun ResolvedComponentResult.toKpmModuleDependency(): KpmModuleDependency = KpmModuleDependency(toSingleKpmModuleIdentifier())
internal fun ComponentSelector.toKpmModuleDependency(): KpmModuleDependency {
val moduleId = toKpmModuleIdentifiers().single() // FIXME handle multiple
return KpmModuleDependency(moduleId)
}
internal fun ComponentIdentifier.matchesModuleDependency(moduleDependency: KpmModuleDependency) =
matchesModuleIdentifier(moduleDependency.moduleIdentifier)
internal fun ComponentIdentifier.matchesModuleIdentifier(id: KpmModuleIdentifier): Boolean =
when (id) {
is KpmLocalModuleIdentifier -> {
@@ -191,13 +77,3 @@ internal fun ComponentIdentifier.matchesModuleIdentifier(id: KpmModuleIdentifier
}
else -> false
}
@Suppress("UNUSED_PARAMETER")
private fun getProjectStructureMetadata(
project: Project,
module: ResolvedComponentResult,
configuration: Configuration,
moduleIdentifier: KpmModuleIdentifier? = null,
): KotlinProjectStructureMetadata? {
TODO("Implement project structure metadata extractor for KPM")
}
@@ -1,47 +0,0 @@
/*
* 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 GradleKpmModuleFactory(private val project: Project) : NamedDomainObjectFactory<GradleKpmModule> {
override fun create(name: String): GradleKpmModule {
val result = project.objects.newInstance(GradleKpmModuleInternal::class.java, project, name)
registerFragmentFactory(result)
registerDefaultCommonFragment(result)
addDefaultDependencyOnMainModule(result)
addDefaultRefinementDependencyOnCommon(result)
return result
}
protected open fun registerDefaultCommonFragment(module: GradleKpmModule) {
module.fragments.register(GradleKpmFragment.COMMON_FRAGMENT_NAME, GradleKpmFragment::class.java)
}
protected open fun addDefaultRefinementDependencyOnCommon(module: GradleKpmModule) {
module.fragments.matching { it.name != GradleKpmFragment.COMMON_FRAGMENT_NAME }.all {
it.refines(module.fragments.named(GradleKpmFragment.COMMON_FRAGMENT_NAME))
}
}
protected open fun addDefaultDependencyOnMainModule(module: GradleKpmModule) {
if (module.name != GradleKpmModule.MAIN_MODULE_NAME) {
module.fragments
.matching { it.fragmentName == GradleKpmFragment.COMMON_FRAGMENT_NAME }
.configureEach { commonFragment ->
commonFragment.dependencies {
api(module.project.pm20Extension.modules.getByName(GradleKpmModule.MAIN_MODULE_NAME))
}
}
}
}
protected open fun registerFragmentFactory(module: GradleKpmModule) {
module.fragments.registerFactory(GradleKpmFragment::class.java, GradleKpmCommonFragmentFactory(module))
}
}
@@ -1,85 +0,0 @@
/*
* 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.
*/
@file:Suppress("UNCHECKED_CAST")
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.ExtensiblePolymorphicDomainObjectContainer
import org.gradle.api.NamedDomainObjectSet
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.currentBuildId
import org.jetbrains.kotlin.gradle.utils.buildPathCompat
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.project.model.*
import org.jetbrains.kotlin.project.model.utils.variantsContainingFragment
import javax.inject.Inject
abstract class GradleKpmModuleInternal(
final override val project: Project,
final override val moduleClassifier: String?
) : GradleKpmModule {
@Inject
constructor(project: Project, moduleName: CharSequence) : this(
project,
moduleName.takeIf { it != GradleKpmModule.MAIN_MODULE_NAME }?.toString()
)
override val moduleIdentifier: KpmModuleIdentifier =
KpmLocalModuleIdentifier(project.currentBuildId().buildPathCompat, project.path, moduleClassifier)
override val fragments: ExtensiblePolymorphicDomainObjectContainer<GradleKpmFragment> =
project.objects.polymorphicDomainObjectContainer(GradleKpmFragment::class.java)
// TODO DSL & build script model: find a way to create a flexible typed view on fragments?
override val variants: NamedDomainObjectSet<GradleKpmVariant> by lazy {
fragments.withType(GradleKpmVariant::class.java)
}
override val plugins: Set<KpmCompilerPlugin> by lazy {
mutableSetOf<KpmCompilerPlugin>().also { set ->
project
.plugins
.withType(GradleKpmCompilerPlugin::class.java)
.mapTo(set, GradleKpmCompilerPlugin::kpmCompilerPlugin)
}
}
override var isPublic: Boolean = false
protected set
private var setPublicHandlers: MutableList<() -> Unit> = mutableListOf()
override fun ifMadePublic(action: () -> Unit) {
// FIXME reentrancy?
if (isPublic) action() else setPublicHandlers.add(action)
}
override 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 toString(): String = "$moduleIdentifier (Gradle)"
}
internal val GradleKpmModule.resolvableMetadataConfigurationName: String
get() = lowerCamelCaseName(name, "DependenciesMetadata")
internal val GradleKpmModule.isMain
get() = moduleIdentifier.moduleClassifier == null
internal fun GradleKpmModule.disambiguateName(simpleName: String) =
lowerCamelCaseName(moduleClassifier, simpleName)
internal fun GradleKpmModule.variantsContainingFragment(fragment: KpmFragment): Iterable<GradleKpmVariant> =
(this as KpmModule).variantsContainingFragment(fragment).onEach { it as GradleKpmVariant } as Iterable<GradleKpmVariant>
@@ -1,43 +0,0 @@
/*
* Copyright 2010-2022 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.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.plugin.HasCompilerOptions
import org.jetbrains.kotlin.gradle.targets.native.NativeCompilerOptions
import org.jetbrains.kotlin.konan.target.KonanTarget
internal class GradleKpmNativeVariantCompilationData(
val variant: GradleKpmNativeVariantInternal
) : GradleKpmVariantCompilationDataInternal<KotlinCommonOptions>, GradleKpmNativeCompilationData<KotlinCommonOptions> {
override val konanTarget: KonanTarget
get() = variant.konanTarget
@Suppress("DeprecatedCallableAddReplaceWith")
@Deprecated(
"Please declare explicit dependency on kotlinx-cli. This option has no longer effect since 1.9.0",
level = DeprecationLevel.ERROR
)
override val enableEndorsedLibs: Boolean
get() = false
override val project: Project
get() = variant.containingModule.project
override val owner: GradleKpmNativeVariant
get() = variant
override val compilerOptions: HasCompilerOptions<KotlinCommonCompilerOptions> = NativeCompilerOptions(project)
@Suppress("DEPRECATION")
@Deprecated("Replaced with compilerOptions.options", replaceWith = ReplaceWith("compilerOptions.options"))
override val kotlinOptions: KotlinCommonOptions = object : KotlinCommonOptions {
override val options: KotlinCommonCompilerOptions
get() = compilerOptions.options
}
}
@@ -1,37 +0,0 @@
/*
* Copyright 2010-2022 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.jetbrains.kotlin.konan.target.KonanTarget
class GradleKpmNativeVariantConstructor<T : GradleKpmNativeVariantInternal>(
val konanTarget: KonanTarget,
val variantClass: Class<T>,
private val constructor: (
containingModule: GradleKpmModule,
fragmentName: String,
dependencyConfigurations: GradleKpmFragmentDependencyConfigurations,
compileDependencyConfiguration: Configuration,
apiElementsConfiguration: Configuration,
hostSpecificMetadataElementsConfiguration: Configuration?
) -> T
) {
operator fun invoke(
containingModule: GradleKpmModule,
fragmentName: String,
dependencyConfigurations: GradleKpmFragmentDependencyConfigurations,
compileDependencyConfiguration: Configuration,
apiElementsConfiguration: Configuration,
hostSpecificMetadataElementsConfiguration: Configuration?
): T = constructor(
containingModule, fragmentName,
dependencyConfigurations,
compileDependencyConfiguration,
apiElementsConfiguration,
hostSpecificMetadataElementsConfiguration
)
}
@@ -1,95 +0,0 @@
/*
* 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.
*/
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.FragmentNameDisambiguation
import org.jetbrains.kotlin.gradle.utils.setupNativeCompiler
fun <T : GradleKpmNativeVariantInternal> GradleKpmNativeVariantFactory(
module: GradleKpmModule,
constructor: GradleKpmNativeVariantConstructor<T>,
config: GradleKpmNativeVariantConfig<T> = GradleKpmNativeVariantConfig()
) = GradleKpmFragmentFactory(
fragmentInstantiator = GradleKpmNativeVariantInstantiator(module, constructor, config),
fragmentConfigurator = GradleKpmNativeVariantConfigurator(config)
)
data class GradleKpmNativeVariantConfig<T : GradleKpmNativeVariantInternal>(
val dependenciesConfigurationFactory: GradleKpmFragmentDependencyConfigurationsFactory =
GradleKpmDefaultFragmentDependencyConfigurationsFactory,
val compileDependencies: GradleKpmConfigurationSetup<T> =
DefaultKotlinCompileDependenciesDefinition + GradleKpmKonanTargetAttribute,
val apiElements: GradleKpmConfigurationSetup<T> =
DefaultKotlinApiElementsDefinition
+ GradleKpmKonanTargetAttribute
+ GradleKpmConfigurationRelationSetup { extendsFrom(dependencies.transitiveImplementationConfiguration) },
val hostSpecificMetadataElements: GradleKpmConfigurationSetup<T> =
DefaultKotlinHostSpecificMetadataElementsDefinition,
val compileTaskConfigurator: GradleKpmCompileTaskConfigurator<T> =
GradleKpmNativeCompileTaskConfigurator,
val sourceArchiveTaskConfigurator: GradleKpmSourceArchiveTaskConfigurator<T> =
GradleKpmDefaultKotlinSourceArchiveTaskConfigurator,
val sourceDirectoriesConfigurator: GradleKpmSourceDirectoriesConfigurator<T> =
GradleKpmDefaultSourceDirectoriesConfigurator,
val publicationConfigurator: GradleKpmPublicationConfigurator<GradleKpmNativeVariantInternal> =
GradleKpmPublicationConfigurator.NativeVariantPublication
)
class GradleKpmNativeVariantInstantiator<T : GradleKpmNativeVariantInternal>(
private val module: GradleKpmModule,
private val variantConstructor: GradleKpmNativeVariantConstructor<T>,
private val config: GradleKpmNativeVariantConfig<T>
) : GradleKpmFragmentFactory.FragmentInstantiator<T> {
override fun create(name: String): T {
val names = FragmentNameDisambiguation(module, name)
val dependencies = config.dependenciesConfigurationFactory.create(module, names)
val context = GradleKpmFragmentConfigureContextImpl(module, dependencies, names)
return variantConstructor.invoke(
containingModule = module,
fragmentName = name,
dependencyConfigurations = dependencies,
compileDependencyConfiguration = config.compileDependencies.provider.getConfiguration(context).also { configuration ->
config.compileDependencies.relations.setupExtendsFromRelations(configuration, context)
},
apiElementsConfiguration = config.apiElements.provider.getConfiguration(context).also { configuration ->
config.apiElements.relations.setupExtendsFromRelations(configuration, context)
},
hostSpecificMetadataElementsConfiguration =
config.hostSpecificMetadataElements.provider.getConfiguration(context).also { configuration ->
config.hostSpecificMetadataElements.relations.setupExtendsFromRelations(configuration, context)
}
)
}
}
class GradleKpmNativeVariantConfigurator<T : GradleKpmNativeVariantInternal>(
private val config: GradleKpmNativeVariantConfig<T>
) : GradleKpmFragmentFactory.FragmentConfigurator<T> {
override fun configure(fragment: T) {
fragment.project.setupNativeCompiler(fragment.konanTarget)
fragment.compileDependenciesConfiguration.configure(config.compileDependencies, fragment)
fragment.apiElementsConfiguration.configure(config.apiElements, fragment)
fragment.hostSpecificMetadataElementsConfiguration?.configure(config.hostSpecificMetadataElements, fragment)
config.sourceDirectoriesConfigurator.configure(fragment)
config.compileTaskConfigurator.registerCompileTasks(fragment)
config.sourceArchiveTaskConfigurator.registerSourceArchiveTask(fragment)
config.publicationConfigurator.configure(fragment)
}
}
@@ -1,56 +0,0 @@
/*
* 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.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultCInteropSettings
import org.jetbrains.kotlin.gradle.plugin.mpp.GradleKpmDefaultCInteropSettingsFactory
import org.jetbrains.kotlin.gradle.plugin.mpp.publishedConfigurationName
import org.jetbrains.kotlin.konan.target.KonanTarget
abstract class GradleKpmNativeVariantInternal(
containingModule: GradleKpmModule,
fragmentName: String,
val konanTarget: KonanTarget,
dependencyConfigurations: GradleKpmFragmentDependencyConfigurations,
compileDependencyConfiguration: Configuration,
apiElementsConfiguration: Configuration,
final override val hostSpecificMetadataElementsConfiguration: Configuration?
) : GradleKpmNativeVariant,
GradleKpmVariantInternal(
containingModule = containingModule,
fragmentName = fragmentName,
dependencyConfigurations = dependencyConfigurations,
compileDependenciesConfiguration = compileDependencyConfiguration,
apiElementsConfiguration = apiElementsConfiguration
),
GradleKpmSingleMavenPublishedModuleHolder by GradleKpmDefaultSingleMavenPublishedModuleHolder(containingModule, fragmentName) {
@Deprecated("Please declare explicit dependency on kotlinx-cli. This option is scheduled to be removed in 1.9.0")
override var enableEndorsedLibraries: Boolean = false
override val gradleVariantNames: Set<String>
get() = listOf(apiElementsConfiguration.name).flatMap { listOf(it, publishedConfigurationName(it)) }.toSet()
val cinterops by lazy {
project.container(
DefaultCInteropSettings::class.java, GradleKpmDefaultCInteropSettingsFactory(compilationData)
)
}
override val compilationData by lazy { GradleKpmNativeVariantCompilationData(this) }
}
interface GradleKpmNativeCompilationData<T : KotlinCommonOptions> : GradleKpmCompilationData<T> {
val konanTarget: KonanTarget
@Deprecated(
"Please declare explicit dependency on kotlinx-cli. This option has no longer effect since 1.9.0",
level = DeprecationLevel.ERROR
)
val enableEndorsedLibs: Boolean
}
@@ -1,40 +0,0 @@
/*
* 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.Project
import org.gradle.api.publish.maven.MavenPublication
import org.jetbrains.kotlin.gradle.dsl.pm20Extension
import org.jetbrains.kotlin.project.model.KpmModuleIdentifier
internal interface GradleKpmProjectModelContainer {
val modules: NamedDomainObjectContainer<GradleKpmModule>
val metadataCompilationRegistryByModuleId: MutableMap<KpmModuleIdentifier, MetadataCompilationRegistry>
val rootPublication: MavenPublication?
}
internal val Project.metadataCompilationRegistryByModuleId: MutableMap<KpmModuleIdentifier, MetadataCompilationRegistry>
get() = this.pm20Extension.kpmModelContainer.metadataCompilationRegistryByModuleId
internal class GradleKpmDefaultProjectModelContainer(
override val modules: NamedDomainObjectContainer<GradleKpmModule>,
override val metadataCompilationRegistryByModuleId: MutableMap<KpmModuleIdentifier, MetadataCompilationRegistry>,
) : GradleKpmProjectModelContainer {
override var rootPublication: MavenPublication? = null
companion object {
fun create(project: Project): GradleKpmDefaultProjectModelContainer {
return GradleKpmDefaultProjectModelContainer(createKpmModulesContainer(project), mutableMapOf())
}
private fun createKpmModulesContainer(project: Project): NamedDomainObjectContainer<GradleKpmModule> =
project.objects.domainObjectContainer(
GradleKpmModule::class.java,
GradleKpmModuleFactory(project)
)
}
}
@@ -1,25 +0,0 @@
/*
* 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
interface GradleKpmPublicationConfigurator<in T : GradleKpmVariant> : GradleKpmFragmentFactory.FragmentConfigurator<T> {
object NoPublication : GradleKpmPublicationConfigurator<GradleKpmVariant> {
override fun configure(fragment: GradleKpmVariant) = Unit
}
object SingleVariantPublication : GradleKpmPublicationConfigurator<GradleKpmPublishedVariantWithRuntime> {
override fun configure(fragment: GradleKpmPublishedVariantWithRuntime) {
GradleKpmVariantPublishingConfigurator.get(fragment.project).configureSingleVariantPublication(fragment)
}
}
object NativeVariantPublication : GradleKpmPublicationConfigurator<GradleKpmNativeVariantInternal> {
override fun configure(fragment: GradleKpmNativeVariantInternal) {
GradleKpmVariantPublishingConfigurator.get(fragment.project).configureNativeVariantPublication(fragment)
}
}
}
@@ -1,37 +0,0 @@
/*
* Copyright 2010-2022 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.jetbrains.kotlin.gradle.plugin.mpp.publishedConfigurationName
import org.jetbrains.kotlin.gradle.utils.dashSeparatedName
abstract class GradleKpmPublishedVariantWithRuntime(
containingModule: GradleKpmModule, fragmentName: String,
dependencyConfigurations: GradleKpmFragmentDependencyConfigurations,
compileDependencyConfiguration: Configuration,
apiElementsConfiguration: Configuration,
runtimeDependencyConfiguration: Configuration,
runtimeElementsConfiguration: Configuration
) : GradleKpmVariantWithRuntimeInternal(
containingModule = containingModule,
fragmentName = fragmentName,
dependencyConfigurations = dependencyConfigurations,
compileDependencyConfiguration = compileDependencyConfiguration,
apiElementsConfiguration = apiElementsConfiguration,
runtimeDependenciesConfiguration = runtimeDependencyConfiguration,
runtimeElementsConfiguration = runtimeElementsConfiguration
), GradleKpmSingleMavenPublishedModuleHolder by GradleKpmDefaultSingleMavenPublishedModuleHolder(
containingModule, defaultModuleSuffix(containingModule, fragmentName)
) {
override val gradleVariantNames: Set<String>
get() = listOf(apiElementsConfiguration.name, runtimeElementsConfiguration.name).flatMapTo(mutableSetOf()) {
listOf(it, publishedConfigurationName(it))
}
}
private fun defaultModuleSuffix(module: GradleKpmModule, variantName: String): String =
dashSeparatedName(variantName, module.moduleClassifier)
@@ -1,15 +0,0 @@
/*
* Copyright 2010-2022 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.publish.maven.MavenPublication
interface GradleKpmSingleMavenPublishedModuleHolder {
fun assignMavenPublication(publication: MavenPublication)
fun whenPublicationAssigned(handlePublication: (MavenPublication) -> Unit)
val defaultPublishedModuleSuffix: String?
val publishedMavenModuleCoordinates: PublishedModuleCoordinatesProvider
}
@@ -1,31 +0,0 @@
/*
* 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.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.unambiguousNameInProject
import org.jetbrains.kotlin.gradle.plugin.mpp.sourcesJarTaskNamed
import org.jetbrains.kotlin.gradle.utils.future
interface GradleKpmSourceArchiveTaskConfigurator<in T : GradleKpmVariant> {
fun registerSourceArchiveTask(variant: T): TaskProvider<*>?
}
object GradleKpmDefaultKotlinSourceArchiveTaskConfigurator : GradleKpmSourceArchiveTaskConfigurator<GradleKpmVariant> {
override fun registerSourceArchiveTask(variant: GradleKpmVariant): TaskProvider<*> {
return sourcesJarTaskNamed(
taskName = variant.sourceArchiveTaskName,
componentName = variant.name,
project = variant.project,
sourceSets = variant.project.future {
GradleKpmFragmentSourcesProvider().getSourcesFromRefinesClosureAsMap(variant)
.entries.associate { it.key.unambiguousNameInProject to it.value.get() }
},
artifactNameAppendix = variant.name,
componentTypeName = "variant",
)
}
}
@@ -1,33 +0,0 @@
/*
* 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.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import java.io.File
interface GradleKpmSourceDirectoriesConfigurator<in T : GradleKpmFragment>: GradleKpmFragmentFactory.FragmentConfigurator<T>
object GradleKpmDefaultSourceDirectoriesConfigurator : GradleKpmSourceDirectoriesConfigurator<GradleKpmFragment> {
override fun configure(fragment: GradleKpmFragment) {
fragment.kotlinSourceRoots.srcDir(
fragment.project.provider {
defaultSourceFolder(
fragment,
type = "kotlin"
)
}
)
}
private fun fragmentDirectoryName(fragment: GradleKpmFragment): String {
return lowerCamelCaseName(fragment.name, fragment.containingModule.name)
}
fun defaultSourceFolder(fragment: GradleKpmFragment, type: String): File {
val fragmentDirectoryName = fragmentDirectoryName(fragment)
return fragment.project.file("src/$fragmentDirectoryName/$type")
}
}
@@ -5,54 +5,6 @@
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.FileCollection
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationOutput
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.project.model.KpmVariant
interface GradleKpmVariant : GradleKpmFragment, KpmVariant {
val platformType: KotlinPlatformType
// TODO generalize with KotlinCompilation?
val compileDependenciesConfiguration: Configuration
var compileDependencyFiles: FileCollection
// TODO rewrite using our own artifacts API?
val compilationOutputs: KotlinCompilationOutput
// TODO rewrite using our own artifacts API
val sourceArchiveTaskName: String
// TODO generalize exposing outputs: what if a variant has more than one such configurations or none?
val apiElementsConfiguration: Configuration
val gradleVariantNames: Set<String>
}
interface GradleKpmVariantWithRuntime : GradleKpmVariant {
// TODO deduplicate with KotlinCompilation?
val runtimeDependenciesConfiguration: Configuration
var runtimeDependencyFiles: FileCollection
val runtimeFiles: ConfigurableFileCollection
// TODO generalize exposing outputs: what if a variant has more than one such configurations or none?
val runtimeElementsConfiguration: Configuration
}
interface GradleKpmNativeVariant : GradleKpmVariant {
override val platformType: KotlinPlatformType
get() = KotlinPlatformType.native
val hostSpecificMetadataElementsConfiguration: Configuration?
var enableEndorsedLibraries: Boolean
}
interface PublishedModuleCoordinatesProvider {
val group: String
val name: String
@@ -1,44 +0,0 @@
/*
* Copyright 2010-2022 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.project.model.LanguageSettings
interface GradleKpmVariantCompilationData<T : KotlinCommonOptions> : GradleKpmCompilationData<T> {
override val owner: GradleKpmVariant
override val project: Project get() = owner.containingModule.project
override val compilationPurpose: String
get() = owner.containingModule.name
override val compilationClassifier: String
get() = owner.name
override val output: KotlinCompilationOutput
get() = owner.compilationOutputs
override val compileKotlinTaskName: String
override val compileAllTaskName: String
override val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet>
override val compileDependencyFiles: FileCollection
get() = owner.compileDependencyFiles
override val languageSettings: LanguageSettings
get() = owner.languageSettings
override val platformType: KotlinPlatformType
get() = owner.platformType
}
@@ -1,77 +0,0 @@
/*
* 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.component.ProjectComponentIdentifier
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.mpp.KpmGradleModuleVariantResolver
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.allDependencyModules
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.disambiguateName
import org.jetbrains.kotlin.gradle.utils.filesProvider
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.project.model.KpmVariantResolution
interface GradleKpmVariantCompilationDataInternal<T : KotlinCommonOptions> : GradleKpmVariantCompilationData<T> {
override val compileKotlinTaskName: String
get() = lowerCamelCaseName("compile", compilationPurpose.takeIf { it != "main" }, "Kotlin", compilationClassifier)
override val compileAllTaskName: String
get() = owner.disambiguateName("classes")
override val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet>
get() = owner.withRefinesClosure.filterIsInstance<GradleKpmVariant>().associate { it.disambiguateName("") to it.kotlinSourceRoots }
override val friendPaths: Iterable<FileCollection>
get() {
// TODO note for Android: see the friend artifacts code in KotlinAndroidCompilation; should we port it here?
return listOf(
project.filesProvider {
val friendVariants = resolveFriendVariants()
val friendModuleClassifiers = friendVariants.map { it.containingModule.moduleClassifier }.toSet()
owner.compileDependenciesConfiguration
.incoming.artifactView { view ->
view.componentFilter { id ->
// FIXME rewrite using the proper module resolution after those changes are merged
val asProject = id as? ProjectComponentIdentifier
@Suppress("DEPRECATION")
asProject?.build?.isCurrentBuild == true &&
asProject.projectPath == owner.project.path
}
}.artifacts.filter {
// FIXME rewrite using the proper module resolution after those changes are merged
moduleClassifiersFromCapabilities(it.variant.capabilities).any { it in friendModuleClassifiers }
}.map { it.file }
}
)
}
override val moduleName: String
get() = owner.ownModuleName()
private fun resolveFriendVariants(): Iterable<GradleKpmVariant> {
val moduleResolver = GradleKpmModuleDependencyResolver.getForCurrentBuild(project)
val variantResolver = KpmGradleModuleVariantResolver.getForCurrentBuild(project)
val dependencyGraphResolver = GradleKpmDependencyGraphResolver(moduleResolver)
val friendModules =
((dependencyGraphResolver.resolveDependencyGraph(owner.containingModule) as? GradleKpmDependencyGraph)
?: error("Failed to resolve dependencies of ${owner.containingModule}"))
.allDependencyModules
.filterIsInstance<GradleKpmModule>()
.filter { dependencyModule ->
// the module comes from the same Gradle project // todo: extend to other friends once supported
dependencyModule.project == owner.containingModule.project
}
return friendModules
.map { friendModule -> variantResolver.getChosenVariant(owner, friendModule) }
// also, important to check that the owner variant really requests this module:
.filterIsInstance<KpmVariantResolution.KpmVariantMatch>()
.mapNotNull { variantMatch -> variantMatch.chosenVariant as? GradleKpmVariant }
}
}
@@ -1,51 +0,0 @@
/*
* 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.file.FileCollection
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.disambiguateName
import org.jetbrains.kotlin.project.model.KotlinAttributeKey
import org.jetbrains.kotlin.project.model.KotlinPlatformTypeAttribute
abstract class GradleKpmVariantInternal(
containingModule: GradleKpmModule,
fragmentName: String,
dependencyConfigurations: GradleKpmFragmentDependencyConfigurations,
final override val compileDependenciesConfiguration: Configuration,
final override val apiElementsConfiguration: Configuration
) : GradleKpmFragmentInternal(
containingModule, fragmentName, dependencyConfigurations
), GradleKpmVariant {
override val variantAttributes: Map<KotlinAttributeKey, String>
get() = mapOf(KotlinPlatformTypeAttribute to kotlinPlatformTypeAttributeFromPlatform(platformType)) // TODO user attributes
override var compileDependencyFiles: FileCollection = project.files({ compileDependenciesConfiguration })
internal abstract val compilationData: GradleKpmVariantCompilationDataInternal<*>
// TODO rewrite using our own artifacts API?
override val compilationOutputs: KotlinCompilationOutput = DefaultKotlinCompilationOutput(
project, project.provider { project.buildDir.resolve("processedResources/${containingModule.name}/${fragmentName}") }
)
// TODO rewrite using our own artifacts API
override val sourceArchiveTaskName: String
get() = defaultSourceArtifactTaskName
override fun toString(): String = "variant $fragmentName in $containingModule"
}
private fun kotlinPlatformTypeAttributeFromPlatform(platformType: KotlinPlatformType) = platformType.name
// TODO: rewrite with the artifacts API
internal val GradleKpmVariant.defaultSourceArtifactTaskName: String
get() = disambiguateName("sourcesJar")
@@ -1,33 +0,0 @@
/*
* Copyright 2010-2022 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.file.ConfigurableFileCollection
import org.gradle.api.file.FileCollection
abstract class GradleKpmVariantWithRuntimeInternal(
containingModule: GradleKpmModule,
fragmentName: String,
dependencyConfigurations: GradleKpmFragmentDependencyConfigurations,
compileDependencyConfiguration: Configuration,
apiElementsConfiguration: Configuration,
final override val runtimeDependenciesConfiguration: Configuration,
final override val runtimeElementsConfiguration: Configuration
) : GradleKpmVariantInternal(
containingModule = containingModule,
fragmentName = fragmentName,
dependencyConfigurations = dependencyConfigurations,
compileDependenciesConfiguration = compileDependencyConfiguration,
apiElementsConfiguration = apiElementsConfiguration
), GradleKpmVariantWithRuntime {
// TODO deduplicate with KotlinCompilation?
override var runtimeDependencyFiles: FileCollection = project.files(runtimeDependenciesConfiguration)
override val runtimeFiles: ConfigurableFileCollection =
project.files(listOf({ compilationOutputs.allOutputs }, { runtimeDependencyFiles }))
}
@@ -1,177 +0,0 @@
/*
* 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.component.SoftwareComponentFactory
import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
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.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.utils.checkGradleCompatibility
import javax.inject.Inject
abstract class KotlinPm20GradlePlugin @Inject constructor(
@Inject private val softwareComponentFactory: SoftwareComponentFactory,
@Inject private val toolingModelBuilderRegistry: ToolingModelBuilderRegistry
) : 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)
setupFragmentsMetadataForKpmModules(project)
setupKpmModulesPublication(project)
}
private fun createDefaultModules(project: Project) {
project.pm20Extension.apply {
modules.create(GradleKpmModule.MAIN_MODULE_NAME)
modules.create(GradleKpmModule.TEST_MODULE_NAME)
main { makePublic() }
}
}
private fun setupPublicationForModule(module: GradleKpmModule) {
val project = module.project
val metadataElements = project.configurations.getByName(metadataElementsConfigurationName(module))
val sourceElements = project.configurations.getByName(sourceElementsConfigurationName(module))
val componentName = rootPublicationComponentName(module)
val rootSoftwareComponent = softwareComponentFactory.adhoc(componentName).also {
project.components.add(it)
it.addVariantsFromConfiguration(metadataElements) { }
it.addVariantsFromConfiguration(sourceElements) { }
}
module.ifMadePublic {
val metadataDependencyConfiguration = resolvableMetadataConfiguration(module)
project.pluginManager.withPlugin("maven-publish") {
project.extensions.getByType(PublishingExtension::class.java).publications.create(
componentName,
MavenPublication::class.java
) { publication ->
publication.from(rootSoftwareComponent)
publication.versionMapping { versionMapping ->
versionMapping.allVariants {
it.fromResolutionOf(metadataDependencyConfiguration)
}
}
}
}
}
}
}
fun rootPublicationComponentName(module: GradleKpmModule) =
module.disambiguateName("root")
// NB: inheriting `KotlinProjectExtension` is a hack, as well as overriding 'sourceSets'
// This is done because 'project.kotlinProjectExtension' casts extension to KotlinProjectExtension,
// resulting in CCE, and some code (like KotlinGradleProjectCheckers) that is launched universally
// in KPM and TCS actually calls this method, breaking KPM tests.
//
// Ideally, respective code should just treat top-level extensions more carefully, but as KPM
// is not in focus for now, we don't want to complicate the new code with those matters.
//
// Inheriting KotlinProjectExtension allows such code to not fail. When KPM work is resumed,
// this inheritance should be removed
open class KotlinPm20ProjectExtension(project: Project) : KotlinProjectExtension(project) {
override var sourceSets: NamedDomainObjectContainer<KotlinSourceSet>
get() = super.sourceSets
set(value) {
super.sourceSets = value
}
internal val kpmModelContainer = GradleKpmDefaultProjectModelContainer.create(project)
val modules: NamedDomainObjectContainer<GradleKpmModule>
get() = kpmModelContainer.modules
@Suppress("unused") // DSL function
fun mainAndTest(configure: GradleKpmModule.() -> Unit) {
main(configure)
test(configure)
}
val main: GradleKpmModule
get() = modules.getByName(GradleKpmModule.MAIN_MODULE_NAME)
val test: GradleKpmModule
get() = modules.getByName(GradleKpmModule.TEST_MODULE_NAME)
fun main(configure: GradleKpmModule.() -> Unit = { }) = main.apply(configure)
fun test(configure: GradleKpmModule.() -> Unit = { }) = test.apply(configure)
@PublishedApi
@JvmName("isAllowCommonizer")
internal fun isAllowCommonizerForIde(@Suppress("UNUSED_PARAMETER") project: Project): Boolean = false
}
val GradleKpmModule.jvm: GradleKpmJvmVariant
get() = fragments.maybeCreate("jvm", GradleKpmJvmVariant::class.java)
fun GradleKpmModule.jvm(configure: GradleKpmJvmVariant.() -> Unit): GradleKpmJvmVariant = jvm.apply(configure)
fun KotlinPm20ProjectExtension.jvm(configure: KotlinFragmentSlice<GradleKpmJvmVariant>.() -> Unit) {
val getOrCreateVariant: GradleKpmModule.() -> GradleKpmJvmVariant = { jvm }
mainAndTest { getOrCreateVariant(this) }
val slice = KotlinFragmentSlice(this, getOrCreateVariant)
configure(slice)
}
open class KotlinFragmentSlice<T : GradleKpmFragment>(
val pm20ProjectExtension: KotlinPm20ProjectExtension,
val getOrCreateFragment: (GradleKpmModule) -> T
) {
fun inMain(configure: T.() -> Unit) {
pm20ProjectExtension.modules.getByName(GradleKpmModule.MAIN_MODULE_NAME).apply {
getOrCreateFragment(this).configure()
}
}
fun inTest(configure: T.() -> Unit) {
pm20ProjectExtension.modules.getByName(GradleKpmModule.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<GradleKpmModule>, configure: T.() -> Unit) {
module.get().apply { inModule(this, configure) }
}
fun inModule(module: GradleKpmModule, configure: T.() -> Unit) {
getOrCreateFragment(module).configure()
}
}
@@ -1,130 +0,0 @@
/*
* 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.provider.Provider
import org.jetbrains.kotlin.gradle.plugin.FilesSubpluginOption
import org.jetbrains.kotlin.gradle.plugin.SubpluginOption
import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerPluginData
import org.jetbrains.kotlin.gradle.utils.addGradlePluginMetadataAttributes
import org.jetbrains.kotlin.gradle.utils.newProperty
import org.jetbrains.kotlin.project.model.*
import java.io.File
internal fun Project.compilerPluginProviderForMetadata(
fragment: GradleKpmFragment,
compilationData: GradleKpmCommonFragmentMetadataCompilationData
) = compilerPluginDataProvider(compilationData, fragment::metadataCompilationPluginData)
internal fun Project.compilerPluginProviderForNativeMetadata(
fragment: GradleKpmFragment,
compilationData: GradleKpmNativeFragmentMetadataCompilationData
) = compilerPluginDataProvider(compilationData, fragment::nativeMetadataCompilationPluginData)
internal fun Project.compilerPluginProviderForPlatformCompilation(
variant: GradleKpmVariant,
compilationData: GradleKpmCompilationData<*>
) = compilerPluginDataProvider(compilationData, variant::platformCompilationPluginData)
internal fun GradleKpmCompilationData<*>.pluginClasspathConfigurationName() = "${compileKotlinTaskName}PluginClasspath"
private fun Project.compilerPluginDataProvider(
compilationData: GradleKpmCompilationData<*>,
pluginDataList: () -> List<PluginData>
): Provider<KotlinCompilerPluginData> {
return newProperty {
val configurationName = compilationData.pluginClasspathConfigurationName()
val builder = CompilerPluginOptionsBuilder(project, configurationName)
builder += pluginDataList()
builder.build()
}.apply { disallowUnsafeRead() }
}
private class CompilerPluginOptionsBuilder(
private val project: Project,
private val configurationName: String
) {
private val pluginOptions = CompilerPluginOptions()
private val artifacts = mutableListOf<String>()
private val gradleInputs = mutableMapOf<String, MutableList<String>>()
private val gradleInputFiles = mutableSetOf<File>()
private val gradleOutputFiles = mutableSetOf<File>()
operator fun plusAssign(pluginData: PluginData) {
artifacts += pluginData.artifact.toGradleCoordinates()
for (option in pluginData.options) {
pluginOptions.addPluginArgument(pluginData.pluginId, option.toSubpluginOption())
if (!option.isTransient) {
addToInputsOutputs(pluginData.pluginId, option)
}
}
}
operator fun plusAssign(pluginDataCollection: Collection<PluginData>) {
for (pluginData in pluginDataCollection) {
this += pluginData
}
}
private fun addToInputsOutputs(pluginId: String, option: PluginOption) {
when (option) {
is FilesOption ->
if (option.isOutput) {
gradleOutputFiles += option.files
} else {
gradleInputFiles += option.files
}
is StringOption -> gradleInputs
.getOrPut("${pluginId}.${option.key}") { mutableListOf() }
.add(option.value)
}
}
fun build(): KotlinCompilerPluginData {
val pluginClasspathConfiguration =
project.configurations.maybeCreate(configurationName).apply {
isCanBeConsumed = false
isCanBeResolved = true
isVisible = false
addGradlePluginMetadataAttributes(project)
}
artifacts.forEach { project.dependencies.add(configurationName, it) }
return KotlinCompilerPluginData(
classpath = pluginClasspathConfiguration,
options = pluginOptions,
inputsOutputsState = KotlinCompilerPluginData.InputsOutputsState(
inputs = gradleInputs.flattenWithIndex(),
inputFiles = gradleInputFiles,
outputFiles = gradleOutputFiles
)
)
}
private fun Map<String, List<String>>.flattenWithIndex(): Map<String, String> {
val result = mutableMapOf<String, String>()
for ((key, values) in this) {
for ((index, value) in values.withIndex()) {
result["${key}.$index"] = value
}
}
return result
}
private fun PluginOption.toSubpluginOption() = when (this) {
is FilesOption -> FilesSubpluginOption(key, files)
is StringOption -> SubpluginOption(key, value)
}
private fun PluginData.ArtifactCoordinates.toGradleCoordinates(): String =
listOfNotNull(group, artifact, version).joinToString(":")
}
@@ -1,53 +0,0 @@
/*
* 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.
*/
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE
import org.gradle.api.attributes.java.TargetJvmEnvironment
import org.gradle.api.attributes.java.TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages.consumerApiUsage
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages.consumerRuntimeUsage
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages.producerApiUsage
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages.producerRuntimeUsage
import org.jetbrains.kotlin.gradle.plugin.usageByName
import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
val GradleKpmPlatformAttributes = GradleKpmConfigurationAttributesSetup<GradleKpmVariant> {
if (isGradleVersionAtLeast(7, 0) && fragment.platformType == KotlinPlatformType.jvm) {
namedAttribute(TARGET_JVM_ENVIRONMENT_ATTRIBUTE, TargetJvmEnvironment.STANDARD_JVM)
}
attribute(KotlinPlatformType.attribute, fragment.platformType)
}
val GradleKpmConsumerApiUsageAttribute = GradleKpmConfigurationAttributesSetup<GradleKpmVariant> {
attribute(USAGE_ATTRIBUTE, consumerApiUsage(project, fragment.platformType))
}
val GradleKpmProducerApiUsageAttribute = GradleKpmConfigurationAttributesSetup<GradleKpmVariant> {
attribute(USAGE_ATTRIBUTE, producerApiUsage(fragment.project, fragment.platformType))
}
val GradleKpmConsumerRuntimeUsageAttribute = GradleKpmConfigurationAttributesSetup<GradleKpmVariant> {
attribute(USAGE_ATTRIBUTE, consumerRuntimeUsage(fragment.project, fragment.platformType))
}
val GradleKpmProducerRuntimeUsageAttribute = GradleKpmConfigurationAttributesSetup<GradleKpmVariant> {
attribute(USAGE_ATTRIBUTE, producerRuntimeUsage(fragment.project, fragment.platformType))
}
val GradleKpmMetadataUsageAttribute = GradleKpmConfigurationAttributesSetup<GradleKpmFragment> {
attribute(USAGE_ATTRIBUTE, fragment.project.usageByName(KotlinUsages.KOTLIN_METADATA))
}
val GradleKpmKonanTargetAttribute = GradleKpmConfigurationAttributesSetup<GradleKpmNativeVariantInternal> {
attributes.attribute(KotlinNativeTarget.konanTargetAttribute, fragment.konanTarget.name)
}
@@ -1,85 +0,0 @@
/*
* Copyright 2010-2022 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.attributes.Bundling
import org.gradle.api.attributes.Category
val DefaultKotlinCompileDependenciesDefinition = GradleKpmConfigurationSetup(
provider = GradleKpmConfigurationProvider {
project.configurations.maybeCreate(disambiguateName("compileDependencies")).apply {
isCanBeConsumed = false
isCanBeResolved = true
}
},
relations = GradleKpmConfigurationRelationSetup {
extendsFrom(dependencies.transitiveApiConfiguration)
extendsFrom(dependencies.transitiveImplementationConfiguration)
},
attributes = GradleKpmPlatformAttributes + GradleKpmConsumerApiUsageAttribute
)
val DefaultKotlinRuntimeDependenciesDefinition = GradleKpmConfigurationSetup(
provider = GradleKpmConfigurationProvider {
project.configurations.maybeCreate(disambiguateName("runtimeDependencies")).apply {
isCanBeConsumed = false
isCanBeResolved = true
}
},
attributes = GradleKpmPlatformAttributes + GradleKpmConsumerRuntimeUsageAttribute,
relations = GradleKpmConfigurationRelationSetup {
extendsFrom(dependencies.transitiveApiConfiguration)
extendsFrom(dependencies.transitiveImplementationConfiguration)
extendsFrom(dependencies.transitiveRuntimeOnlyConfiguration)
}
)
val DefaultKotlinApiElementsDefinition = GradleKpmConfigurationSetup(
provider = GradleKpmConfigurationProvider {
project.configurations.maybeCreate(disambiguateName("apiElements")).apply {
isCanBeResolved = false
isCanBeConsumed = false
module.ifMadePublic { isCanBeConsumed = true }
}
},
relations = GradleKpmConfigurationRelationSetup { extendsFrom(dependencies.transitiveApiConfiguration) },
capabilities = GradleKpmModuleCapability,
attributes = GradleKpmPlatformAttributes + GradleKpmProducerApiUsageAttribute + GradleKpmConfigurationAttributesSetup {
attribute(Category.CATEGORY_ATTRIBUTE, fragment.project.objects.named(Category::class.java, Category.LIBRARY))
attribute(Bundling.BUNDLING_ATTRIBUTE, fragment.project.objects.named(Bundling::class.java, Bundling.EXTERNAL))
},
)
val DefaultKotlinRuntimeElementsDefinition = GradleKpmConfigurationSetup(
provider = GradleKpmConfigurationProvider {
project.configurations.maybeCreate(disambiguateName("runtimeElements")).apply {
isCanBeResolved = false
isCanBeConsumed = false
module.ifMadePublic { isCanBeConsumed = true }
}
},
relations = GradleKpmConfigurationRelationSetup {
extendsFrom(dependencies.transitiveApiConfiguration)
extendsFrom(dependencies.transitiveImplementationConfiguration)
extendsFrom(dependencies.transitiveRuntimeOnlyConfiguration)
},
attributes = GradleKpmPlatformAttributes + GradleKpmProducerRuntimeUsageAttribute + GradleKpmConfigurationAttributesSetup {
attribute(Category.CATEGORY_ATTRIBUTE, fragment.project.objects.named(Category::class.java, Category.LIBRARY))
attribute(Bundling.BUNDLING_ATTRIBUTE, fragment.project.objects.named(Bundling::class.java, Bundling.EXTERNAL))
},
capabilities = GradleKpmModuleCapability
)
val DefaultKotlinHostSpecificMetadataElementsDefinition = GradleKpmConfigurationSetup(
provider = GradleKpmConfigurationProvider {
project.configurations.maybeCreate(disambiguateName("hostSpecificMetadataElements")).apply {
isCanBeResolved = false
isCanBeConsumed = false
}
},
attributes = GradleKpmPlatformAttributes + GradleKpmKonanTargetAttribute + GradleKpmMetadataUsageAttribute,
artifacts = GradleKpmHostSpecificMetadataArtifact
)
@@ -1,26 +0,0 @@
/*
* 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.jetbrains.kotlin.gradle.dsl.pm20Extension
internal fun registerDefaultVariantFactories(project: Project) {
project.pm20Extension.modules.configureEach { module ->
module.fragments.registerFactory(
GradleKpmJvmVariant::class.java,
GradleKpmJvmVariantFactory(module)
)
fun <T : GradleKpmNativeVariantInternal> registerNativeVariantFactory(
constructor: GradleKpmNativeVariantConstructor<T>
) = module.fragments.registerFactory(
constructor.variantClass, GradleKpmNativeVariantFactory(module, constructor)
)
allKpmNativeVariantConstructors.forEach { constructor -> registerNativeVariantFactory(constructor) }
}
}
@@ -1,296 +0,0 @@
/*
* 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.DefaultTask
import org.gradle.api.Project
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.Usage
import org.gradle.api.tasks.TaskProvider
import org.gradle.jvm.tasks.Jar
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.plugin.mpp.pm20.util.ComputedCapability
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.disambiguateName
import org.jetbrains.kotlin.gradle.targets.metadata.KotlinMetadataTargetConfigurator
import org.jetbrains.kotlin.gradle.targets.metadata.createGenerateProjectStructureMetadataTask
import org.jetbrains.kotlin.gradle.targets.metadata.filesWithUnpackedArchives
import org.jetbrains.kotlin.gradle.tasks.*
import org.jetbrains.kotlin.gradle.tasks.withType
import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.gradle.utils.dashSeparatedName
import org.jetbrains.kotlin.gradle.utils.filesProvider
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION
import org.jetbrains.kotlin.project.model.KpmFragment
import java.util.concurrent.Callable
internal fun setupFragmentsMetadataForKpmModules(project: Project) {
project.pm20Extension.modules.all { module ->
configureMetadataResolutionAndBuild(module)
configureMetadataExposure(module)
}
}
private fun configureMetadataResolutionAndBuild(module: GradleKpmModule) {
val project = module.project
createResolvableMetadataConfigurationForModule(module)
val metadataCompilationRegistry = MetadataCompilationRegistry()
project.metadataCompilationRegistryByModuleId[module.moduleIdentifier] =
metadataCompilationRegistry
configureMetadataCompilationsAndCreateRegistry(module, metadataCompilationRegistry)
configureMetadataJarTask(module, metadataCompilationRegistry)
generateAndExportProjectStructureMetadata(module)
}
private fun configureMetadataExposure(module: GradleKpmModule) {
val project = module.project
project.configurations.create(metadataElementsConfigurationName(module)).apply {
isCanBeConsumed = false
module.ifMadePublic {
isCanBeConsumed = true
}
isCanBeResolved = false
project.artifacts.add(name, project.tasks.named(metadataJarName(module)))
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_METADATA))
attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.common)
module.fragments.all { fragment ->
// FIXME: native api-implementation
project.addExtendsFromRelation(name, fragment.apiConfigurationName)
}
setModuleCapability(this, module)
}
val sourcesArtifactAppendix = dashSeparatedName(module.moduleClassifier, "all", "sources")
val sourcesArtifact = sourcesJarTaskNamed(
module.disambiguateName("allSourcesJar"),
module.name,
project,
project.future {
GradleKpmFragmentSourcesProvider().getAllFragmentSourcesAsMap(module).entries.associate { it.key.fragmentName to it.value.get() }
},
sourcesArtifactAppendix,
"module",
)
DocumentationVariantConfigurator().createSourcesElementsConfiguration(
project, sourceElementsConfigurationName(module),
sourcesArtifact.get(), "sources", ComputedCapability.fromModuleOrNull(module)
)
}
fun metadataElementsConfigurationName(module: GradleKpmModule) =
module.disambiguateName("metadataElements")
fun sourceElementsConfigurationName(module: GradleKpmModule) =
module.disambiguateName("sourceElements")
private fun generateAndExportProjectStructureMetadata(
module: GradleKpmModule
) {
val project = module.project
val projectStructureMetadata = project.createGenerateProjectStructureMetadataTask(module)
project.tasks.withType<Jar>().named(metadataJarName(module)).configure { jar ->
jar.from(projectStructureMetadata.map { it.resultFile }) { spec ->
spec.into("META-INF")
.rename { MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME }
}
}
GlobalProjectStructureMetadataStorage.registerProjectStructureMetadata(project) {
buildProjectStructureMetadata(module)
}
}
private fun createResolvableMetadataConfigurationForModule(module: GradleKpmModule) {
val project = module.project
project.configurations.create(module.resolvableMetadataConfigurationName).apply {
isCanBeConsumed = false
isCanBeResolved = true
attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.common)
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_METADATA))
attributes.attribute(Category.CATEGORY_ATTRIBUTE, project.categoryByName(Category.LIBRARY))
module.fragments.all { fragment ->
project.addExtendsFromRelation(name, fragment.apiConfigurationName)
project.addExtendsFromRelation(name, fragment.implementationConfigurationName)
}
}
}
private fun configureMetadataCompilationsAndCreateRegistry(
module: GradleKpmModule,
metadataCompilationRegistry: MetadataCompilationRegistry
) {
val project = module.project
val metadataResolverFactory = GradleKpmFragmentGranularMetadataResolverFactory()
module.fragments.all { fragment ->
val metadataResolver = metadataResolverFactory.getOrCreate(fragment)
createExtractMetadataTask(project, fragment, metadataResolver)
}
val compileAllTask = project.registerTask<DefaultTask>(lowerCamelCaseName(module.moduleClassifier, "metadataClasses"))
module.fragments.all { fragment ->
createCommonMetadataCompilation(fragment, compileAllTask, metadataCompilationRegistry)
createNativeMetadataCompilation(fragment, compileAllTask, metadataCompilationRegistry)
}
metadataCompilationRegistry.withAll { compilation ->
project.tasks.matching { it.name == compilation.compileKotlinTaskName }.configureEach { task ->
task.onlyIf { compilation.isActive }
}
}
}
private fun configureMetadataJarTask(
module: GradleKpmModule,
registry: MetadataCompilationRegistry
) {
val project = module.project
val allMetadataJar = project.registerTask<Jar>(metadataJarName(module)) { task ->
if (module.moduleClassifier != null) {
task.archiveClassifier.set(module.moduleClassifier)
}
task.archiveAppendix.set("metadata")
task.from()
}
module.fragments.all { fragment ->
allMetadataJar.configure { jar ->
val metadataOutput = project.filesProvider {
val compilationData = registry.getForFragmentOrNull(fragment)
.takeIf { !fragment.isNativeHostSpecific() }
?: return@filesProvider emptyList<Any>()
project.filesWithUnpackedArchives(compilationData.output.allOutputs, setOf(KLIB_FILE_EXTENSION))
}
jar.from(metadataOutput) { spec ->
spec.into(fragment.fragmentName)
}
}
}
}
internal fun metadataJarName(module: GradleKpmModule) =
lowerCamelCaseName(module.moduleClassifier, KotlinMetadataTargetConfigurator.ALL_METADATA_JAR_NAME)
private fun createCommonMetadataCompilation(
fragment: GradleKpmFragment,
compileAllTask: TaskProvider<DefaultTask>,
metadataCompilationRegistry: MetadataCompilationRegistry
) {
val module = fragment.containingModule
val project = module.project
val metadataCompilationData =
GradleKpmCommonFragmentMetadataCompilationDataImpl(
project,
fragment,
module,
compileAllTask,
metadataCompilationRegistry,
lazy { resolvedMetadataProviders(fragment) }
)
GradleKpmMetadataCompilationTasksConfigurator(project).createKotlinCommonCompilationTask(fragment, metadataCompilationData)
metadataCompilationRegistry.registerCommon(fragment, metadataCompilationData)
}
private fun createNativeMetadataCompilation(
fragment: GradleKpmFragment,
compileAllTask: TaskProvider<DefaultTask>,
metadataCompilationRegistry: MetadataCompilationRegistry
) {
val module = fragment.containingModule
val project = module.project
val metadataCompilationData =
GradleKpmNativeFragmentMetadataCompilationDataImpl(
project,
fragment,
module,
compileAllTask,
metadataCompilationRegistry,
lazy { resolvedMetadataProviders(fragment) }
)
GradleKpmMetadataCompilationTasksConfigurator(project).createKotlinNativeMetadataCompilationTask(fragment, metadataCompilationData)
metadataCompilationRegistry.registerNative(fragment, metadataCompilationData)
}
private class GradleKpmMetadataCompilationTasksConfigurator(project: Project) : GradleKpmCompilationTaskConfigurator(project) {
fun createKotlinCommonCompilationTask(
fragment: GradleKpmFragment,
compilationData: GradleKpmCommonFragmentMetadataCompilationData
) {
KotlinCommonSourceSetProcessor(KotlinCompilationInfo.KPM(compilationData), KotlinTasksProvider()).run()
val allSources = getSourcesForFragmentCompilation(fragment)
val commonSources = getCommonSourcesForFragmentCompilation(fragment)
addSourcesToKotlinCompileTask(project, compilationData.compileKotlinTaskName, emptyList()) { allSources }
addCommonSourcesToKotlinCompileTask(project, compilationData.compileKotlinTaskName, emptyList()) { commonSources }
project.tasks.named(compilationData.compileKotlinTaskName, AbstractKotlinCompile::class.java).configure {
it.kotlinPluginData = project.compilerPluginProviderForMetadata(fragment, compilationData)
}
}
fun createKotlinNativeMetadataCompilationTask(
fragment: GradleKpmFragment,
compilationData: GradleKpmNativeFragmentMetadataCompilationData
): TaskProvider<KotlinNativeCompile> = createKotlinNativeCompilationTask(fragment, compilationData) {
kotlinPluginData = project.compilerPluginProviderForNativeMetadata(fragment, compilationData)
}
override fun getSourcesForFragmentCompilation(fragment: GradleKpmFragment): MultipleSourceRootsProvider {
return project.provider { listOf(fragmentSourcesProvider.getFragmentOwnSources(fragment)) }
}
override fun getCommonSourcesForFragmentCompilation(fragment: GradleKpmFragment): MultipleSourceRootsProvider {
return project.provider { listOf(fragmentSourcesProvider.getFragmentOwnSources(fragment)) }
}
}
private fun resolvedMetadataProviders(fragment: GradleKpmFragment) =
fragment.withRefinesClosure.map {
FragmentResolvedMetadataProvider(
fragment.project.tasks.withType<GradleKpmMetadataDependencyTransformationTask>().named(transformFragmentMetadataTaskName(it))
)
}
private fun createExtractMetadataTask(
project: Project,
fragment: GradleKpmFragment,
transformation: GradleKpmFragmentGranularMetadataResolver
) {
project.tasks.register(
transformFragmentMetadataTaskName(fragment),
GradleKpmMetadataDependencyTransformationTask::class.java,
fragment,
transformation
).configure { task ->
task.dependsOn(Callable {
fragment.withRefinesClosure.mapNotNull { refined ->
if (refined !== fragment)
project.tasks.named(transformFragmentMetadataTaskName(refined))
else null
}
})
}
}
// FIXME: use this function once more than one platform is supported
private fun disableMetadataCompilationIfNotYetSupported(
metadataCompilationData: GradleKpmAbstractFragmentMetadataCompilationData<*>
) {
val fragment = metadataCompilationData.fragment
val platforms = fragment.containingVariants.map { it.platformType }.toSet()
if (platforms != setOf(KotlinPlatformType.native) && platforms.size == 1
|| platforms == setOf(KotlinPlatformType.jvm, KotlinPlatformType.androidJvm)
) {
fragment.containingModule.project.tasks.named(metadataCompilationData.compileKotlinTaskName).configure {
it.enabled = false
}
}
}
private fun transformFragmentMetadataTaskName(fragment: KpmFragment) =
lowerCamelCaseName("resolve", fragment.disambiguateName("Metadata"))
@@ -1,71 +0,0 @@
/*
* 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.component.SoftwareComponentFactory
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
import org.jetbrains.kotlin.gradle.dsl.pm20Extension
import org.jetbrains.kotlin.gradle.tooling.buildKotlinToolingMetadataTask
import javax.inject.Inject
internal fun setupKpmModulesPublication(project: Project) {
project.pm20Extension.modules.all { module ->
setupPublicationForModule(module)
}
}
private fun setupPublicationForModule(module: GradleKpmModule) {
val project = module.project
val metadataElements = project.configurations.getByName(metadataElementsConfigurationName(module))
val sourceElements = project.configurations.getByName(sourceElementsConfigurationName(module))
val componentName = rootPublicationComponentName(module)
val rootSoftwareComponent = SoftwareComponentFactoryHolder(project).softwareComponentFactory.adhoc(componentName).also {
project.components.add(it)
it.addVariantsFromConfiguration(metadataElements) { }
it.addVariantsFromConfiguration(sourceElements) { }
}
module.ifMadePublic {
val metadataDependencyConfiguration = resolvableMetadataConfiguration(module)
project.pluginManager.withPlugin("maven-publish") {
project.extensions.getByType(PublishingExtension::class.java).publications.create(
componentName,
MavenPublication::class.java
) { publication ->
publication.from(rootSoftwareComponent)
publication.versionMapping { versionMapping ->
versionMapping.allVariants {
it.fromResolutionOf(metadataDependencyConfiguration)
}
}
publication.setupKotlinToolingMetadataIfNeeded(module)
}
}
}
}
private fun MavenPublication.setupKotlinToolingMetadataIfNeeded(module: GradleKpmModule) {
val buildKotlinToolingMetadataTask = module.buildKotlinToolingMetadataTask ?: return
artifact(buildKotlinToolingMetadataTask.map { it.outputFile }) { artifact ->
artifact.classifier = "kotlin-tooling-metadata"
artifact.builtBy(buildKotlinToolingMetadataTask)
}
}
private open class SoftwareComponentFactoryHolder @Inject constructor(
@Inject val softwareComponentFactory: SoftwareComponentFactory
) {
companion object {
operator fun invoke(project: Project): SoftwareComponentFactoryHolder {
return project.objects.newInstance(SoftwareComponentFactoryHolder::class.java)
}
}
}
@@ -1,61 +0,0 @@
/*
* 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.Project
import org.gradle.api.file.FileCollection
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmAbstractFragmentMetadataCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmVariant
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmVariantWithRuntime
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.resolvableMetadataConfigurationName
import org.jetbrains.kotlin.gradle.utils.filesProvider
interface GradleKpmDependencyFilesHolder {
val dependencyConfigurationName: String
var dependencyFiles: FileCollection
companion object
}
internal fun GradleKpmDependencyFilesHolder.Companion.ofVariantCompileDependencies(variant: GradleKpmVariant): GradleKpmDependencyFilesHolder =
object : GradleKpmDependencyFilesHolder {
override val dependencyConfigurationName: String
get() = variant.compileDependenciesConfiguration.name
override var dependencyFiles: FileCollection
get() = variant.compileDependencyFiles
set(value) { variant.compileDependencyFiles = value }
}
internal fun GradleKpmDependencyFilesHolder.Companion.ofVariantRuntimeDependencies(variant: GradleKpmVariantWithRuntime): GradleKpmDependencyFilesHolder =
object : GradleKpmDependencyFilesHolder {
override val dependencyConfigurationName: String
get() = variant.runtimeDependenciesConfiguration.name
override var dependencyFiles: FileCollection
get() = variant.runtimeDependencyFiles
set(value) { variant.runtimeDependencyFiles = value }
}
internal fun GradleKpmDependencyFilesHolder.Companion.ofMetadataCompilationDependencies(
compilationData: GradleKpmAbstractFragmentMetadataCompilationData<*>
) = object : GradleKpmDependencyFilesHolder {
override val dependencyConfigurationName: String
get() = compilationData.fragment.containingModule.resolvableMetadataConfigurationName
override var dependencyFiles: FileCollection
get() = compilationData.compileDependencyFiles
set(value) { compilationData.compileDependencyFiles = value }
}
class SimpleDependencyFilesHolder(
override val dependencyConfigurationName: String,
override var dependencyFiles: FileCollection
) : GradleKpmDependencyFilesHolder
internal fun Project.newDependencyFilesHolder(dependencyConfigurationName: String): GradleKpmDependencyFilesHolder =
SimpleDependencyFilesHolder(
dependencyConfigurationName,
project.filesProvider { project.configurations.getByName(dependencyConfigurationName) }
)
@@ -1,76 +0,0 @@
/*
* 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.
*/
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmModule
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.project.model.KpmModule
import org.jetbrains.kotlin.project.model.KpmFragment
/**
* Mechanism for disambiguating/scoping names for certain entities (e.g. fragments)
* e.g. Certain fragments might want to create a configuration called 'api'. However, the name scope
* of Gradle configurations is bound to the Gradle project which requires providing different names of mentioned configurations
* for FragmentFoo and FragmentBar.
*
* In such case a disambiguation _could_ produce:
*
* ```kotlin
* // in main module
* fragmentFoo.disambiguateName("api") == "fragmentFooApi"
* fragmentBar.disambiguateName("api") == "fragmentBarApi"
*
* // in test module
* fragmentFoo.disambiguateName("api") == "fragmentFooTestApi"
* fragmentBar.disambiguateName("api") == "fragmentBarTestApi"
* ```
*/
interface GradleKpmNameDisambiguation {
fun disambiguateName(simpleName: String): String
}
/* Default implementation for fragments */
internal fun FragmentNameDisambiguation(module: KpmModule, fragmentName: String): GradleKpmNameDisambiguation {
return GradleKpmDefaultFragmentNameDisambiguation(module, fragmentName)
}
internal fun FragmentNameDisambiguationOmittingMain(module: KpmModule, fragmentName: String): GradleKpmNameDisambiguation {
return GradleKpmDefaultFragmentNameDisambiguationOmittingMain(module, fragmentName)
}
private class GradleKpmDefaultFragmentNameDisambiguation(
private val module: KpmModule,
private val fragmentName: String
) : GradleKpmNameDisambiguation {
override fun disambiguateName(simpleName: String): String {
return KpmFragment.disambiguateName(module, fragmentName, simpleName)
}
}
private class GradleKpmDefaultFragmentNameDisambiguationOmittingMain(
private val module: KpmModule,
private val fragmentName: String
) : GradleKpmNameDisambiguation {
override fun disambiguateName(simpleName: String): String {
return KpmFragment.disambiguateNameOmittingMain(module, fragmentName, simpleName)
}
}
internal fun KpmFragment.disambiguateName(simpleName: String) =
KpmFragment.disambiguateName(containingModule, fragmentName, simpleName)
internal val KpmFragment.unambiguousNameInProject
get() = disambiguateName("")
internal fun KpmFragment.Companion.disambiguateName(module: KpmModule, fragmentName: String, simpleName: String) =
lowerCamelCaseName(fragmentName, module.moduleIdentifier.moduleClassifier ?: GradleKpmModule.MAIN_MODULE_NAME, simpleName)
internal fun KpmFragment.Companion.disambiguateNameOmittingMain(module: KpmModule, fragmentName: String, simpleName: String) =
lowerCamelCaseName(fragmentName, module.moduleIdentifier.moduleClassifier, simpleName)
@@ -1,45 +0,0 @@
/*
* 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.GradleKpmModule
internal class ComputedCapability(
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: GradleKpmModule): ComputedCapability {
val project = module.project
return ComputedCapability(
project.provider { project.group.toString() },
project.name,
project.provider { project.version.toString() },
module.moduleClassifier
)
}
fun fromModuleOrNull(module: GradleKpmModule): ComputedCapability? =
if (module.moduleClassifier != null)
fromModule(module)
else null
fun capabilityStringFromModule(module: GradleKpmModule): String? =
if (module.moduleClassifier != null) fromModule(module).notation() else null
}
fun notation(): String = "$group:$name:$version"
}
@@ -1,17 +0,0 @@
/*
* Copyright 2010-2022 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.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmDependencyGraph
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmDependencyGraphNode
import org.jetbrains.kotlin.project.model.KpmModule
import org.jetbrains.kotlin.tooling.core.withClosure
internal val GradleKpmDependencyGraph.allDependencyNodes: Iterable<GradleKpmDependencyGraphNode>
get() = root.withClosure { it.dependenciesByFragment.values.flatten() }
internal val GradleKpmDependencyGraph.allDependencyModules: Iterable<KpmModule>
get() = allDependencyNodes.map { it.module }
@@ -1,283 +0,0 @@
/*
* 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.artifacts.Configuration
import org.gradle.api.artifacts.ModuleDependency
import org.gradle.api.artifacts.PublishArtifact
import org.gradle.api.attributes.*
import org.gradle.api.capabilities.Capability
import org.gradle.api.component.AdhocComponentWithVariants
import org.gradle.api.component.SoftwareComponentFactory
import org.gradle.api.provider.Provider
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.publish.maven.internal.publication.DefaultMavenPublication
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.ComputedCapability
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.copyAttributes
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.copyConfigurationForPublishing
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.disambiguateName
import org.jetbrains.kotlin.gradle.plugin.mpp.publishedConfigurationName
import org.jetbrains.kotlin.gradle.plugin.usageByName
import org.jetbrains.kotlin.gradle.tasks.withType
import org.jetbrains.kotlin.gradle.utils.dashSeparatedName
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
import java.util.*
import javax.inject.Inject
interface GradleKpmPlatformPublicationToMavenRequest {
val componentName: String
val fromModule: GradleKpmModule
val publicationHolder: GradleKpmSingleMavenPublishedModuleHolder
val variantPublicationRequests: Iterable<KpmGradleConfigurationPublicationRequest>
}
data class GradleKpmBasicPlatformPublicationToMavenRequest(
override val componentName: String,
override val fromModule: GradleKpmModule,
override val publicationHolder: GradleKpmSingleMavenPublishedModuleHolder,
override val variantPublicationRequests: Iterable<KpmGradleConfigurationPublicationRequest>
) : GradleKpmPlatformPublicationToMavenRequest {
init {
check(variantPublicationRequests.all { it.fromVariant.containingModule === fromModule }) {
"Variants for publication should all belong to the fromModule ($fromModule)"
}
}
}
/** TODO: consider also using this class for exposing a KPM variant's configurations for project-to-project dependencies,
* so that a variant may expose an arbitrary set of configurations rather just { API, runtime } or { API } */
interface KpmGradleConfigurationPublicationRequest {
val fromVariant: GradleKpmVariant
val publishConfiguration: Configuration
}
data class KpmGradleBasicConfigurationPublicationRequest(
override val fromVariant: GradleKpmVariant,
override val publishConfiguration: Configuration
) : KpmGradleConfigurationPublicationRequest
fun GradleKpmVariantPublishingConfigurator.configureNativeVariantPublication(variant: GradleKpmNativeVariantInternal) {
val publishConfigurations = listOfNotNull(
variant.apiElementsConfiguration,
variant.hostSpecificMetadataElementsConfiguration // host-specific metadata may be absent
)
configureSingleVariantPublishing(variant, variant, publishConfigurations)
}
fun GradleKpmVariantPublishingConfigurator.configureSingleVariantPublication(variant: GradleKpmPublishedVariantWithRuntime) {
val publishConfigurations = listOf(variant.apiElementsConfiguration, variant.runtimeElementsConfiguration)
configureSingleVariantPublishing(variant, variant, publishConfigurations)
}
fun GradleKpmVariantPublishingConfigurator.configureSingleVariantPublishing(
variant: GradleKpmVariant,
publishedModuleHolder: GradleKpmSingleMavenPublishedModuleHolder,
publishConfigurations: Iterable<Configuration>
) {
configurePublishing(
GradleKpmBasicPlatformPublicationToMavenRequest(
platformComponentName(variant),
variant.containingModule,
publishedModuleHolder,
publishConfigurations.map {
KpmGradleBasicConfigurationPublicationRequest(variant, it)
}
)
)
}
open class GradleKpmVariantPublishingConfigurator @Inject constructor(
private val project: Project,
private val softwareComponentFactory: SoftwareComponentFactory
) {
companion object {
fun get(project: Project): GradleKpmVariantPublishingConfigurator =
project.objects.newInstance(GradleKpmVariantPublishingConfigurator::class.java, project)
}
fun platformComponentName(variant: GradleKpmVariant) = variant.disambiguateName("")
fun configurePublishing(
request: GradleKpmPlatformPublicationToMavenRequest
) {
val componentName = request.componentName
registerPlatformModulePublication(
componentName,
request.publicationHolder,
request.variantPublicationRequests,
request.fromModule::ifMadePublic
)
val publishFromVariants = request.variantPublicationRequests.mapTo(mutableSetOf()) { it.fromVariant }
// Collecting sources for multiple variants is not yet supported;
// TODO make callers provide the source variants?
// The MPP plugin doesn't publish the source artifacts as variants; keep that behavior for legacy-mapped variants for now
if (publishFromVariants.size == 1) {
val singlePublishedVariant = publishFromVariants.single()
configureSourceElementsPublishing(componentName, singlePublishedVariant)
}
registerPlatformVariantsInRootModule(
request.publicationHolder,
request.fromModule,
request.variantPublicationRequests
)
}
private fun inferMavenScope(variant: GradleKpmVariant, configurationName: String): String? =
when {
configurationName == variant.apiElementsConfiguration.name -> "compile"
variant is GradleKpmVariantWithRuntime && configurationName == variant.runtimeElementsConfiguration.name -> "runtime"
else -> null
}
private fun configureSourceElementsPublishing(componentName: String, variant: GradleKpmVariant) {
val configurationName = variant.disambiguateName("sourceElements")
val docsVariants = DocumentationVariantConfigurator().createSourcesElementsConfiguration(configurationName, variant)
project.components.withType(AdhocComponentWithVariants::class.java).named(componentName).configure { component ->
component.addVariantsFromConfiguration(docsVariants) { }
}
}
/**
* Creates the [AdhocComponentWithVariants] named [componentName] for the given [publishConfigurationsWithMavenScopes].
* At the point [whenShouldRegisterPublication] creates a Maven publication named [componentName] that publishes the created component.
* Assigns the created Maven publication to the [publishedModuleHolder].
*/
private fun registerPlatformModulePublication(
componentName: String,
publishedModuleHolder: GradleKpmSingleMavenPublishedModuleHolder,
variantRequests: Iterable<KpmGradleConfigurationPublicationRequest>,
whenShouldRegisterPublication: (() -> Unit) -> Unit
) {
val platformComponent = softwareComponentFactory.adhoc(componentName)
project.components.add(platformComponent)
variantRequests.forEach { request ->
val originalConfiguration = request.publishConfiguration
val mavenScopeOrNull = inferMavenScope(request.fromVariant, originalConfiguration.name)
val publishedConfiguration = copyConfigurationForPublishing(
request.fromVariant.project,
newName = publishedConfigurationName(originalConfiguration.name) + "-platform",
configuration = originalConfiguration,
overrideArtifacts = (request as? KpmGradleAdvancedConfigurationPublicationRequest)
?.overrideConfigurationArtifactsForPublication
?.let { override -> { artifacts -> artifacts.addAllLater(override) } },
overrideAttributes = (request as? KpmGradleAdvancedConfigurationPublicationRequest)
?.overrideConfigurationAttributesForPublication
?.let { override -> { attributes -> copyAttributes(override, attributes) } }
)
platformComponent.addVariantsFromConfiguration(publishedConfiguration) details@{ variantDetails ->
mavenScopeOrNull?.let { variantDetails.mapToMavenScope(it) }
}
}
whenShouldRegisterPublication {
project.pluginManager.withPlugin("maven-publish") {
project.extensions.getByType(PublishingExtension::class.java).apply {
publications.create(componentName, MavenPublication::class.java).apply {
(this as DefaultMavenPublication).isAlias = true
from(platformComponent)
publishedModuleHolder.assignMavenPublication(this)
artifactId = dashSeparatedName(
project.name, publishedModuleHolder.defaultPublishedModuleSuffix
).toLowerCaseAsciiOnly()
}
}
}
}
}
private fun registerPlatformVariantsInRootModule(
publishedModuleHolder: GradleKpmSingleMavenPublishedModuleHolder,
kotlinModule: GradleKpmModule,
variantRequests: Iterable<KpmGradleConfigurationPublicationRequest>
) {
val platformModuleDependencyProvider = project.provider {
val coordinates = publishedModuleHolder.publishedMavenModuleCoordinates
(project.dependencies.create("${coordinates.group}:${coordinates.name}:${coordinates.version}") as ModuleDependency).apply {
if (kotlinModule.moduleClassifier != null) {
capabilities { it.requireCapability(ComputedCapability.fromModule(kotlinModule)) }
}
}
}
val rootSoftwareComponent =
project.components
.withType(AdhocComponentWithVariants::class.java)
.getByName(rootPublicationComponentName(kotlinModule))
variantRequests.forEach { variantRequest ->
val configuration = variantRequest.publishConfiguration
project.configurations.create(publishedConfigurationName(configuration.name)).apply {
isCanBeConsumed = false
isCanBeResolved = false
setModuleCapability(this, kotlinModule)
dependencies.addLater(platformModuleDependencyProvider)
copyAttributes(configuration.attributes, this.attributes)
rootSoftwareComponent.addVariantsFromConfiguration(this) { }
}
}
}
}
internal data class KpmGradleAdvancedConfigurationPublicationRequest(
override val fromVariant: GradleKpmVariant,
override val publishConfiguration: Configuration,
val overrideConfigurationAttributesForPublication: AttributeContainer?,
val overrideConfigurationArtifactsForPublication: Provider<out Iterable<PublishArtifact>>?,
val includeIntoProjectStructureMetadata: Boolean
) : KpmGradleConfigurationPublicationRequest
open class DocumentationVariantConfigurator {
open fun createSourcesElementsConfiguration(
project: Project,
configurationName: String,
sourcesArtifactProvider: AbstractArchiveTask,
artifactClassifier: String,
capability: Capability?
): Configuration {
return project.configurations.create(configurationName).apply {
isCanBeResolved = false
isCanBeConsumed = true
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_SOURCES))
attributes.attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category::class.java, Category.DOCUMENTATION))
attributes.attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling::class.java, Bundling.EXTERNAL))
attributes.attribute(DocsType.DOCS_TYPE_ATTRIBUTE, project.objects.named(DocsType::class.java, DocsType.SOURCES))
outgoing.artifact(sourcesArtifactProvider) {
it.classifier = artifactClassifier
}
if (capability != null) {
outgoing.capability(capability)
}
}
}
open fun createSourcesElementsConfiguration(
configurationName: String,
variant: GradleKpmVariant
): Configuration {
val sourcesArtifactTask = variant.project.tasks.withType<AbstractArchiveTask>().named(variant.sourceArchiveTaskName)
val artifactClassifier = dashSeparatedName(variant.containingModule.moduleClassifier, "sources")
return createSourcesElementsConfiguration(
variant.project,
configurationName,
sourcesArtifactTask.get(),
artifactClassifier,
ComputedCapability.fromModuleOrNull(variant.containingModule)
)
}
}
@@ -14,12 +14,12 @@ import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.targets
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsCompilerAttribute
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
import org.jetbrains.kotlin.gradle.utils.getOrCreate
import org.jetbrains.kotlin.gradle.utils.targets
import java.io.File
internal abstract class KotlinSourceSetFactory<T : KotlinSourceSet> internal constructor(
@@ -20,10 +20,8 @@ import org.jetbrains.kotlin.commonizer.SharedCommonizerTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.pm20ExtensionOrNull
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmModule
import org.jetbrains.kotlin.gradle.plugin.sources.*
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.targets.native.internal.createCInteropMetadataDependencyClasspath
@@ -40,14 +38,14 @@ import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
internal const val COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME = "commonMainMetadataElements"
internal val Project.isKotlinGranularMetadataEnabled: Boolean
get() = project.pm20ExtensionOrNull != null || with(PropertiesProvider(this)) {
get() = with(PropertiesProvider(this)) {
mppHierarchicalStructureByDefault || // then we want to use KLIB granular compilation & artifacts even if it's just commonMain
hierarchicalStructureSupport ||
enableGranularSourceSetsMetadata == true
}
internal val Project.shouldCompileIntermediateSourceSetsToMetadata: Boolean
get() = project.pm20ExtensionOrNull != null || with(PropertiesProvider(this)) {
get() = with(PropertiesProvider(this)) {
when {
!hierarchicalStructureSupport && mppHierarchicalStructureByDefault -> false
else -> true
@@ -393,25 +391,12 @@ internal class NativeSharedCompilationProcessor(
override fun run() = Unit
}
internal fun Project.createGenerateProjectStructureMetadataTask(module: GradleKpmModule): TaskProvider<GenerateProjectStructureMetadata> =
project.registerTask(lowerCamelCaseName("generate", module.moduleClassifier, "ProjectStructureMetadata")) { task ->
task.lazyKotlinProjectStructureMetadata = lazy { buildProjectStructureMetadata(module) }
task.description = "Generates serialized project structure metadata of module '${module.name}' (for tooling)"
}
internal fun Project.createGenerateProjectStructureMetadataTask(): TaskProvider<GenerateProjectStructureMetadata> =
project.registerTask(lowerCamelCaseName("generateProjectStructureMetadata")) { task ->
task.lazyKotlinProjectStructureMetadata = lazy { project.multiplatformExtension.kotlinProjectStructureMetadata }
task.description = "Generates serialized project structure metadata of the current project (for tooling)"
}
internal interface ResolvedMetadataFilesProvider {
val buildDependencies: Iterable<TaskProvider<*>>
val metadataResolutions: Iterable<MetadataDependencyResolution>
val metadataFilesByResolution: Map<out MetadataDependencyResolution, FileCollection>
}
internal val KotlinSourceSet.isNativeSourceSet: Future<Boolean> by futureExtension("isNativeSourceSet") {
val compilations = internal.awaitPlatformCompilations()
compilations.isNotEmpty() && compilations.all { it.platformType == KotlinPlatformType.native }
@@ -18,8 +18,6 @@ import org.gradle.api.provider.ProviderFactory
import org.jetbrains.kotlin.gradle.plugin.CInteropSettings
import org.jetbrains.kotlin.gradle.plugin.CInteropSettings.IncludeDirectories
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmNativeVariantCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.disambiguateName
import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropIdentifier
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.gradle.utils.newInstance
@@ -160,23 +158,3 @@ internal class DefaultCInteropSettingsFactory(private val compilation: KotlinCom
return compilation.project.objects.newInstance(params)
}
}
internal class GradleKpmDefaultCInteropSettingsFactory(private val compilation: GradleKpmNativeVariantCompilationData) :
NamedDomainObjectFactory<DefaultCInteropSettings> {
override fun create(name: String): DefaultCInteropSettings {
val params = DefaultCInteropSettings.Params(
name = name,
identifier = CInteropIdentifier(CInteropIdentifier.Scope.create(compilation), name),
dependencyConfigurationName = compilation.owner.disambiguateName("${name.capitalizeAsciiOnly()}CInterop"),
interopProcessingTaskName = lowerCamelCaseName(
"cinterop",
compilation.compilationPurpose.takeIf { it != "main" }.orEmpty(),
name,
compilation.compilationClassifier
),
services = compilation.project.objects.newInstance()
)
return compilation.project.objects.newInstance(params)
}
}
@@ -200,17 +200,6 @@ private suspend fun <T> getHostSpecificElements(
getKonanTargets: suspend (T) -> Set<KonanTarget>
): Set<T> = fragments.filterTo(mutableSetOf()) { isNativeShared(it) && isHostSpecificKonanTargetsSet(getKonanTargets(it)) }
internal suspend fun getHostSpecificFragments(
module: GradleKpmModule
): Set<GradleKpmFragment> = getHostSpecificElements<GradleKpmFragment>(
module.fragments,
isNativeShared = { it.isNativeShared() },
getKonanTargets = {
val nativeVariants = module.variantsContainingFragment(it).filterIsInstance<GradleKpmNativeVariantInternal>()
nativeVariants.mapTo(mutableSetOf()) { it.konanTarget }
}
)
internal suspend fun getHostSpecificSourceSets(project: Project): Set<KotlinSourceSet> {
return getHostSpecificElements(
project.kotlinExtension.awaitSourceSets(),
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
import org.jetbrains.kotlin.gradle.dsl.KotlinNativeCompilerOptions
import org.jetbrains.kotlin.gradle.dsl.topLevelExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.TEST_COMPILATION_NAME
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationInfo.KPM
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.ReadyForExecution
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.KOTLIN_NATIVE_IGNORE_INCORRECT_DEPENDENCIES
import org.jetbrains.kotlin.gradle.plugin.internal.artifactTypeAttribute
@@ -33,7 +32,6 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XcodeVersionTask
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.registerEmbedAndSignAppleFrameworkTask
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.version
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmVariant
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.copyAttributes
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
import org.jetbrains.kotlin.gradle.targets.native.*
@@ -425,11 +423,8 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget> : AbstractKotl
project.project.tasks.named(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(compileTaskProvider)
}
val shouldAddCompileOutputsToElements =
(compilationInfo is KPM && compilationInfo.compilationData.owner is GradleKpmVariant) ||
compilationInfo.isMain
val shouldAddCompileOutputsToElements = compilationInfo.isMain
if (shouldAddCompileOutputsToElements) {
createRegularKlibArtifact(compilationInfo, konanTarget, compileTaskProvider)
}
@@ -484,7 +479,6 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget> : AbstractKotl
}
val apiElementsName = when (compilationInfo) {
is KPM -> (compilationInfo.compilationData.owner as GradleKpmVariant).apiElementsConfiguration.name
is KotlinCompilationInfo.TCS -> compilationInfo.compilation.target.apiElementsConfigurationName
}
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.targets.native.internal
import org.gradle.api.tasks.Input
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmCompilationData
import org.jetbrains.kotlin.tooling.core.UnsafeApi
import java.io.Serializable
@@ -24,11 +23,6 @@ internal data class CInteropIdentifier internal constructor(
fun create(compilation: KotlinCompilation<*>): Scope {
return Scope("compilation/${compilation.compileKotlinTaskName}")
}
@OptIn(UnsafeApi::class)
fun create(compilation: GradleKpmCompilationData<*>): Scope {
return Scope("compilation/${compilation.compileKotlinTaskName}")
}
}
override fun toString(): String = name
@@ -37,8 +37,6 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.Create
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.CreateCompilerArgumentsContext.Companion.create
import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmMetadataCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmNativeCompilationData
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.report.*
import org.jetbrains.kotlin.gradle.report.UsesBuildMetricsService
@@ -158,7 +156,6 @@ abstract class AbstractKotlinNativeCompile<
@get:Internal
protected val konanTarget by project.provider {
when (val compilation = compilation) {
is KotlinCompilationInfo.KPM -> (compilation.compilationData as GradleKpmNativeCompilationData<*>).konanTarget
is KotlinCompilationInfo.TCS -> (compilation.compilation as AbstractKotlinNativeCompilation).konanTarget
}
}
@@ -507,7 +504,6 @@ internal constructor(
private val isMetadataCompilation: Boolean = when (compilation) {
is KotlinCompilationInfo.KPM -> compilation.compilationData is GradleKpmMetadataCompilationData<*>
is KotlinCompilationInfo.TCS -> compilation.compilation is KotlinMetadataCompilation<*>
}
@@ -111,7 +111,7 @@ internal abstract class AbstractKotlinCompileConfig<TASK : AbstractKotlinCompile
) {
configureTask { task ->
task.friendPaths.from({ compilationInfo.friendPaths })
compilationInfo.tcsOrNull?.compilation?.let { compilation ->
compilationInfo.tcs.compilation.let { compilation ->
task.friendSourceSets
.value(providers.provider { compilation.allAssociatedCompilations.map { it.name } })
.disallowChanges()
@@ -127,8 +127,7 @@ internal abstract class AbstractKotlinCompileConfig<TASK : AbstractKotlinCompile
providers.provider {
compilationInfo.project.plugins.any {
it is KotlinPlatformPluginBase ||
it is AbstractKotlinMultiplatformPluginWrapper ||
it is AbstractKotlinPm20PluginWrapper
it is AbstractKotlinMultiplatformPluginWrapper
}
}
)
@@ -138,10 +137,10 @@ internal abstract class AbstractKotlinCompileConfig<TASK : AbstractKotlinCompile
project.providers.provider {
// Plugin explicitly does not configures 'explicitApi' mode for test sources
// compilation, as test sources are not published
val compilation = compilationInfo.tcsOrNull?.compilation
val isCommonCompilation = compilation?.target is KotlinMetadataTarget
val compilation = compilationInfo.tcs.compilation
val isCommonCompilation = compilation.target is KotlinMetadataTarget
val androidCompilation = compilationInfo.tcsOrNull?.compilation as? KotlinJvmAndroidCompilation
val androidCompilation = compilationInfo.tcs.compilation as? KotlinJvmAndroidCompilation
val isMainAndroidCompilation = androidCompilation?.let {
getTestedVariantData(it.androidVariant) == null
} ?: false
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.tasks.configuration
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationInfo
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmMetadataCompilationData
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileCommon
internal class KotlinCompileCommonConfig(
@@ -17,8 +16,7 @@ internal class KotlinCompileCommonConfig(
configureTask { task ->
task.expectActualLinker.value(
providers.provider {
(compilationInfo.origin as? KotlinCommonCompilation)?.isKlibCompilation == true ||
compilationInfo.origin is GradleKpmMetadataCompilationData<*>
(compilationInfo.origin as? KotlinCommonCompilation)?.isKlibCompilation == true
}
).disallowChanges()
task.refinesMetadataPaths.from(compilationInfo.refinesPaths).disallowChanges()
@@ -29,10 +29,10 @@ import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaCompilation
import org.jetbrains.kotlin.gradle.utils.markResolvable
import org.jetbrains.kotlin.gradle.plugin.tcsOrNull
import org.jetbrains.kotlin.gradle.plugin.tcs
import org.jetbrains.kotlin.gradle.tasks.DefaultKotlinJavaToolchain
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.utils.markResolvable
import org.jetbrains.kotlin.gradle.utils.providerWithLazyConvention
internal typealias KotlinCompileConfig = BaseKotlinCompileConfig<KotlinCompile>
@@ -90,7 +90,7 @@ internal open class BaseKotlinCompileConfig<TASK : KotlinCompile> : AbstractKotl
}
constructor(compilationInfo: KotlinCompilationInfo) : super(compilationInfo) {
val javaTaskProvider = when (val compilation = compilationInfo.tcsOrNull?.compilation) {
val javaTaskProvider = when (val compilation = compilationInfo.tcs.compilation) {
is KotlinJvmCompilation -> compilation.compileJavaTaskProviderSafe
is KotlinJvmAndroidCompilation -> compilation.compileJavaTaskProvider
is KotlinWithJavaCompilation<*, *> -> compilation.compileJavaTaskProvider
@@ -19,15 +19,10 @@ import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmJvmVariant
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmModule
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmNativeVariantInternal
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmVariant
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsSubTargetContainerDsl
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
import org.jetbrains.kotlin.gradle.targets.metadata.isCompatibilityMetadataVariantEnabled
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
import org.jetbrains.kotlin.gradle.tasks.dependsOn
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.library.KotlinAbiVersion
@@ -38,22 +33,9 @@ import javax.inject.Inject
internal fun Project.registerBuildKotlinToolingMetadataTask() {
if (!project.kotlinPropertiesProvider.enableKotlinToolingMetadataArtifact) return
if (project.pm20ExtensionOrNull != null) buildKotlinToolingMetadataForMainKpmModuleTask
else buildKotlinToolingMetadataTask
buildKotlinToolingMetadataTask
}
internal val Project.buildKotlinToolingMetadataForMainKpmModuleTask: TaskProvider<BuildKotlinToolingMetadataTask.FromKpmModule>?
get() {
val mainModule = pm20Extension.modules.getByName(GradleKpmModule.MAIN_MODULE_NAME)
return mainModule.buildKotlinToolingMetadataTask
}
private val Project.buildKotlinToolingMetadataForAllKpmModulesTask
get() = locateOrRegisterTask<Task>(BuildKotlinToolingMetadataTask.defaultTaskName) { task ->
task.group = "build"
task.description = "Build metadata json file containing information about the used Kotlin tooling"
}
/**
* The default task managed by the Kotlin Gradle plugin or `null` if the task is disabled.
* @see [PropertiesProvider.enableKotlinToolingMetadataArtifact]
@@ -68,48 +50,13 @@ internal val Project.buildKotlinToolingMetadataTask: TaskProvider<BuildKotlinToo
}
}
internal val GradleKpmModule.buildKotlinToolingMetadataTask: TaskProvider<BuildKotlinToolingMetadataTask.FromKpmModule>?
get() {
if (!project.kotlinPropertiesProvider.enableKotlinToolingMetadataArtifact) return null
val taskName = BuildKotlinToolingMetadataTask.taskNameForKotlinModule(name)
return project.locateOrRegisterTask(
name = taskName,
args = listOf(this),
invokeWhenRegistered = { project.buildKotlinToolingMetadataForAllKpmModulesTask.dependsOn(this) },
configureTask = {
group = "build"
description = "Build metadata json file containing information about the used Kotlin tooling in module $name"
}
)
}
@DisableCachingByDefault
abstract class BuildKotlinToolingMetadataTask : DefaultTask() {
@DisableCachingByDefault
abstract class FromKpmModule
@Inject constructor(
@get:Internal
val module: GradleKpmModule,
private val projectLayout: ProjectLayout
) : BuildKotlinToolingMetadataTask() {
override val outputDirectory: File
get() = projectLayout
.buildDirectory
.get()
.asFile
.resolve("kotlinToolingMetadata")
.resolve(module.name)
override fun buildKotlinToolingMetadata() = module.getKotlinToolingMetadata()
}
@DisableCachingByDefault
abstract class FromKotlinExtension
@Inject constructor(
private val projectLayout: ProjectLayout
private val projectLayout: ProjectLayout,
) : BuildKotlinToolingMetadataTask() {
override val outputDirectory: File get() = projectLayout.buildDirectory.get().asFile.resolve("kotlinToolingMetadata")
@@ -156,70 +103,6 @@ abstract class BuildKotlinToolingMetadataTask : DefaultTask() {
}
}
private fun GradleKpmModule.getKotlinToolingMetadata(): KotlinToolingMetadata {
return KotlinToolingMetadata(
schemaVersion = KotlinToolingMetadata.currentSchemaVersion,
buildSystem = "Gradle",
buildSystemVersion = project.gradle.gradleVersion,
buildPlugin = project.plugins.withType(KotlinBasePluginWrapper::class.java).joinToString(";") { it.javaClass.canonicalName },
buildPluginVersion = project.getKotlinPluginVersion(),
projectSettings = project.buildProjectSettings(),
projectTargets = buildProjectTargets()
)
}
private fun Project.buildProjectSettings(): KotlinToolingMetadata.ProjectSettings {
return KotlinToolingMetadata.ProjectSettings(
isHmppEnabled = project.isKotlinGranularMetadataEnabled,
isCompatibilityMetadataVariantEnabled = project.isCompatibilityMetadataVariantEnabled,
isKPMEnabled = pm20ExtensionOrNull != null
)
}
private fun GradleKpmModule.buildProjectTargets(): List<KotlinToolingMetadata.ProjectTargetMetadata> =
variants.map { variant ->
KotlinToolingMetadata.ProjectTargetMetadata(
target = variant.javaClass.canonicalName,
platformType = variant.platformType.name,
extras = KotlinToolingMetadata.ProjectTargetMetadata.Extras(
jvm = variant.jvmExtrasOrNull(),
android = variant.androidExtrasOrNull(),
js = variant.jsExtrasOrNull(),
native = variant.nativeExtrasOrNull()
)
)
}.distinct() // some variants may look identical. e.g. androidRelease and androidDebug, so just keep one of them.
private fun GradleKpmVariant.jvmExtrasOrNull() =
when (this) {
is GradleKpmJvmVariant -> KotlinToolingMetadata.ProjectTargetMetadata.JvmExtras(
jvmTarget = compilationData.kotlinOptions.jvmTarget,
withJavaEnabled = false
)
else -> null
}
private fun GradleKpmVariant.androidExtrasOrNull() =
when (this) {
else -> null
}
private fun GradleKpmVariant.jsExtrasOrNull() =
when (this) {
else -> null
}
private fun GradleKpmVariant.nativeExtrasOrNull() =
when (this) {
is GradleKpmNativeVariantInternal -> KotlinToolingMetadata.ProjectTargetMetadata.NativeExtras(
konanTarget = konanTarget.name,
konanVersion = project.konanVersion.toString(),
konanAbiVersion = KotlinAbiVersion.CURRENT.toString()
)
else -> null
}
private fun KotlinProjectExtension.getKotlinToolingMetadata(): KotlinToolingMetadata {
return KotlinToolingMetadata(
@@ -303,8 +186,7 @@ private fun buildNativeExtrasOrNull(target: KotlinTarget): KotlinToolingMetadata
if (target !is KotlinNativeTarget) return null
return KotlinToolingMetadata.ProjectTargetMetadata.NativeExtras(
konanTarget = target.konanTarget.name,
konanVersion = target.project.konanVersion.toString(),
konanVersion = target.project.konanVersion,
konanAbiVersion = KotlinAbiVersion.CURRENT.toString()
)
}
@@ -7,16 +7,10 @@ package org.jetbrains.kotlin.gradle.tooling
import com.android.build.gradle.AppExtension
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.pm20ExtensionOrNull
internal fun Project.includeKotlinToolingMetadataInApk() {
plugins.withId("com.android.application") {
val buildKotlinToolingMetadataTask = if (project.pm20ExtensionOrNull != null) {
buildKotlinToolingMetadataForMainKpmModuleTask
} else {
buildKotlinToolingMetadataTask
} ?: return@withId
val buildKotlinToolingMetadataTask = buildKotlinToolingMetadataTask ?: return@withId
val android = project.extensions.getByName("android") as AppExtension
android.applicationVariants.configureEach { variant ->
if (!variant.buildType.isDebuggable) {
@@ -1,16 +1,16 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2023 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
package org.jetbrains.kotlin.gradle.utils
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinSingleTargetExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
val KotlinProjectExtension.targets: Iterable<KotlinTarget>
internal val KotlinProjectExtension.targets: Iterable<KotlinTarget>
get() = when (this) {
is KotlinSingleTargetExtension<*> -> listOf(this.target)
is KotlinMultiplatformExtension -> targets
@@ -0,0 +1,14 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("PackageDirectoryMismatch")
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.utils.targets
@Deprecated("Scheduled for removal in Kotlin 2.1", ReplaceWith("targets", "org.jetbrains.kotlin.gradle.utils.targets"))
val KotlinProjectExtension.targets: Iterable<KotlinTarget> get() = targets
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.targets
import org.jetbrains.kotlin.gradle.utils.targets
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsCompilerAttribute
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
@@ -272,7 +272,6 @@ class ConfigurationsTest : MultiplatformExtensionTest() {
runtimeDependencyConfigurationName,
)
@Suppress("DEPRECATION")
project.kotlinExtension.targets.flatMap { it.compilations }.forEach { compilation ->
val compilationSourceSets = compilation.allKotlinSourceSets
val compilationConfigurationNames = compilation.allCompilationDependenciesConfigurationNames()
@@ -8,8 +8,8 @@
package org.jetbrains.kotlin.gradle.regressionTests
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.targets
import org.jetbrains.kotlin.gradle.util.buildProjectWithJvm
import org.jetbrains.kotlin.gradle.utils.targets
import kotlin.test.Test
class KotlinJvmFunctionalTest {
@@ -238,17 +238,6 @@ class KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheckTest {
assertEquals(setOf(project.path), executedProjectPaths)
}
@Test
fun `test - is automatically executed when android plugin is applied - kpm plugin`() {
val project = buildProjectWithKPM { }
val executedProjectPaths = project.getOrPutRootProjectProperty(PROPERTY_KEY_EXECUTED_PROJECT_PATHS) { mutableSetOf<String>() }
if (executedProjectPaths.isNotEmpty()) fail("Expected 'executed' project paths to be empty")
project.plugins.apply(LibraryPlugin::class.java)
/* Expect project was checked */
assertEquals(setOf(project.path), executedProjectPaths)
}
@Test
fun `test - is not executed when android plugin is applied - kotlin-android plugin`() {
val project = ProjectBuilder.builder().build()
@@ -3,14 +3,16 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.gradle.unitTests
import org.gradle.kotlin.dsl.withType
import org.gradle.language.jvm.tasks.ProcessResources
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.plugin.mpp.InternalKotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.targets
import org.jetbrains.kotlin.gradle.util.buildProjectWithJvm
import org.jetbrains.kotlin.gradle.utils.targets
import kotlin.test.Test
import kotlin.test.assertEquals
@@ -23,7 +25,7 @@ class ResourcesTasksTest {
val actualProcessResourceTaskNames = project.tasks.withType<ProcessResources>().names
val kotlinReportedProcessResourceTaskNames = hashSetOf<String>()
for (compilation in jvmTarget.compilations) {
val processResourcesTaskName = (compilation as? InternalKotlinCompilation<*>)?.let { it.processResourcesTaskName }
val processResourcesTaskName = (compilation as? InternalKotlinCompilation<*>)?.processResourcesTaskName
if (processResourcesTaskName != null) {
kotlinReportedProcessResourceTaskNames.add(processResourcesTaskName)
}
@@ -1,29 +0,0 @@
/*
* Copyright 2010-2022 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.unitTests.kpm
import org.gradle.api.Project
import org.gradle.api.artifacts.verification.DependencyVerificationMode
import org.gradle.api.internal.project.ProjectInternal
import org.gradle.kotlin.dsl.apply
import org.gradle.testfixtures.ProjectBuilder
import org.jetbrains.kotlin.gradle.plugin.KotlinPm20PluginWrapper
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20ProjectExtension
import org.jetbrains.kotlin.gradle.util.addBuildEventsListenerRegistryMock
abstract class AbstractKpmExtensionTest {
protected val project: ProjectInternal = (ProjectBuilder.builder().build() as ProjectInternal).also { project ->
project.gradle.startParameter.dependencyVerificationMode = DependencyVerificationMode.OFF
}
protected val kotlin: KotlinPm20ProjectExtension by lazy { project.applyKpmPlugin() }
}
fun Project.applyKpmPlugin(configure: KotlinPm20ProjectExtension.() -> Unit = {}): KotlinPm20ProjectExtension {
addBuildEventsListenerRegistryMock(project)
apply<KotlinPm20PluginWrapper>()
return (extensions.getByName("kotlin") as KotlinPm20ProjectExtension).also(configure)
}
@@ -1,66 +0,0 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.gradle.unitTests.kpm
import org.gradle.api.Project
import org.gradle.kotlin.dsl.create
import org.jetbrains.kotlin.gradle.dsl.pm20Extension
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.jvm
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.native
import org.jetbrains.kotlin.gradle.plugin.KotlinPm20PluginWrapper
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
import org.jetbrains.kotlin.gradle.tooling.buildKotlinToolingMetadataTask
import org.jetbrains.kotlin.tooling.KotlinToolingMetadata
import kotlin.test.Test
import kotlin.test.assertEquals
private fun Project.kotlinToolingMetadataOfModule(moduleName: String): KotlinToolingMetadata {
val module = pm20Extension.modules.getByName(moduleName)
return module.buildKotlinToolingMetadataTask!!.get().kotlinToolingMetadata
}
private val Project.kotlinToolingMetadataOfMainModule get() = kotlinToolingMetadataOfModule(GradleKpmModule.MAIN_MODULE_NAME)
class BuildKotlinToolingMetadataTest : AbstractKpmExtensionTest() {
@Test
fun `multiple targets`() {
// Given
with(kotlin) {
mainAndTest {
jvm
val linux = fragments.create("linux")
fragments.create<GradleKpmLinuxX64Variant>("linuxX64").apply { refines(linux) }
fragments.create<GradleKpmLinuxArm64Variant>("linuxArm64").apply { refines(linux) }
// No JS & Android variants available at the moment, only through [LegacyMappedVariant] which is tested below
}
}
// When
val metadata = project.kotlinToolingMetadataOfMainModule
// Then
assertEquals("Gradle", metadata.buildSystem)
assertEquals(project.gradle.gradleVersion, metadata.buildSystemVersion)
assertEquals(KotlinPm20PluginWrapper::class.java.canonicalName, metadata.buildPlugin)
assertEquals(project.getKotlinPluginVersion(), metadata.buildPluginVersion)
assertEquals(3, metadata.projectTargets.size, "Expected 3 targets in KPM")
val jvmTarget = metadata.projectTargets.single { it.platformType == jvm.name }
assertEquals(GradleKpmJvmVariant::class.decoratedClassCanonicalName, jvmTarget.target)
val nativeTargets = metadata.projectTargets.filter { it.platformType == native.name }.map { it.target }.toSet()
assertEquals(
setOf(
GradleKpmLinuxArm64Variant::class.decoratedClassCanonicalName,
GradleKpmLinuxX64Variant::class.decoratedClassCanonicalName,
),
nativeTargets
)
}
}
@@ -1,27 +0,0 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.gradle.unitTests.kpm
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmCommonFragmentFactory
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class KotlinCommonFragmentFactoryTest : AbstractKpmExtensionTest() {
@Test
fun `test fragmentName`() {
val fragment = GradleKpmCommonFragmentFactory(kotlin.main).create("common")
assertEquals("common", fragment.fragmentName)
}
@Test
fun `test has source roots`() {
val fragment = GradleKpmCommonFragmentFactory(kotlin.main).create("common")
assertTrue(fragment.kotlinSourceRoots.srcDirs.isNotEmpty())
}
}
@@ -1,206 +0,0 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.gradle.unitTests.kpm
import org.gradle.api.attributes.Attribute
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.FragmentNameDisambiguation
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull
import kotlin.test.assertSame
import kotlin.test.fail
class KotlinFragmentConfigurationDefinitionTest : AbstractKpmExtensionTest() {
private val testContext by lazy {
val names = FragmentNameDisambiguation(kotlin.main, "test")
GradleKpmFragmentConfigureContextImpl(
kotlin.main, GradleKpmDefaultFragmentDependencyConfigurationsFactory.create(kotlin.main, names), names
)
}
private val dummyFragment by lazy {
GradleKpmCommonFragmentFactory(kotlin.main).create("testFragment")
}
@Test
fun `test withProvider`() {
val testDefinition = GradleKpmConfigurationSetup<GradleKpmFragment>(
provider = GradleKpmConfigurationProvider { project.configurations.create("a") }
).withConfigurationProvider { project.configurations.create("b") }
assertEquals(
"b", testDefinition.provider.getConfiguration(testContext).name,
"Expected configuration 'b' to be provided"
)
assertNull(
project.configurations.findByName("a"),
"Expected configuration 'a' never being created"
)
assertEquals(
"c", testDefinition.withConfigurationProvider { project.configurations.create("c") }
.provider.getConfiguration(testContext).name,
"Expected configuration 'c' to be provided"
)
}
@Test
fun `test attributes + attributes`() {
val testAttribute1 = Attribute.of("testAttribute1", String::class.java)
val testAttribute2 = Attribute.of("testAttribute2", String::class.java)
val testConfiguration = project.configurations.create("dummy")
val fragmentAttributes1 = GradleKpmConfigurationAttributesSetup<GradleKpmFragment> {
assertSame(testConfiguration.attributes, attributes)
assertNull(attributes.getAttribute(testAttribute1))
assertNull(attributes.getAttribute(testAttribute2))
attribute(testAttribute1, "value1")
}
val fragmentAttributes2 = GradleKpmConfigurationAttributesSetup<GradleKpmFragment> {
assertSame(testConfiguration.attributes, attributes)
assertEquals(attributes.getAttribute(testAttribute1), "value1")
assertNull(attributes.getAttribute(testAttribute2))
attribute(testAttribute2, "value2")
}
val composite = fragmentAttributes1 + fragmentAttributes2
if (composite !is GradleKpmCompositeConfigurationAttributesSetup)
fail("Expected ${GradleKpmCompositeConfigurationAttributesSetup::class} but found $composite")
assertEquals(
listOf(fragmentAttributes1, fragmentAttributes2), composite.children
)
composite.setupAttributes(testConfiguration.attributes, dummyFragment)
assertEquals(
"value1", testConfiguration.attributes.getAttribute(testAttribute1),
"Expected 'testAttribute1' to be set"
)
assertEquals(
"value2", testConfiguration.attributes.getAttribute(testAttribute2),
"Expected 'testAttribute2' to be set"
)
}
@Test
fun `test definition + attributes`() {
val definition = GradleKpmConfigurationSetup<GradleKpmFragment>(
provider = GradleKpmConfigurationProvider { project.configurations.create("a") }
)
val attributes1 = GradleKpmConfigurationAttributesSetup<GradleKpmFragment> { }
val attributes2 = GradleKpmConfigurationAttributesSetup<GradleKpmFragment> { }
val newDefinition = definition + attributes1 + attributes2
assertEquals(
listOf(attributes1, attributes2), (newDefinition.attributes as? GradleKpmCompositeConfigurationAttributesSetup)?.children,
"Expected 'newDefinition' to list the two added attributes"
)
}
@Test
fun `test artifacts + artifacts`() {
val artifacts1 = GradleKpmConfigurationArtifactsSetup<GradleKpmFragment> {
artifact(project.file("artifact1.jar"))
}
val artifacts2 = GradleKpmConfigurationArtifactsSetup<GradleKpmFragment> {
artifact(project.file("artifact2-a.jar"))
artifact(project.file("artifact2-b.jar"))
}
val composite = artifacts1 + artifacts2
if (composite !is CompositeFragmentConfigurationArtifactsSetup) {
fail("Expected ${CompositeFragmentConfigurationArtifactsSetup::class.java}, but found $composite")
}
assertEquals(
listOf(artifacts1, artifacts2), composite.children
)
project.configurations.create("dummy").apply {
composite.setupArtifacts(outgoing, dummyFragment)
assertEquals(
project.files("artifact1.jar", "artifact2-a.jar", "artifact2-b.jar").toSet(),
outgoing.artifacts.files.toSet()
)
}
}
@Test
fun `test definition + artifacts`() {
val definition = GradleKpmConfigurationSetup<GradleKpmFragment>(
provider = GradleKpmConfigurationProvider { throw NotImplementedError() }
)
val artifacts1 = GradleKpmConfigurationArtifactsSetup<GradleKpmFragment> {}
val artifacts2 = GradleKpmConfigurationArtifactsSetup<GradleKpmFragment> {}
val newDefinition = definition + artifacts1 + artifacts2
assertEquals(
listOf(artifacts1, artifacts2), (newDefinition.artifacts as? CompositeFragmentConfigurationArtifactsSetup)?.children,
"Expected 'newDefinition' to list new added artifacts"
)
}
@Test
fun `test capability + capability`() {
val capabilities1 = GradleKpmConfigurationCapabilitiesSetup<GradleKpmFragment> {
capability("capability1")
}
val capabilities2 = GradleKpmConfigurationCapabilitiesSetup<GradleKpmFragment> {
capability("capability2")
}
val composite = capabilities1 + capabilities2
if (composite !is CompositeKpmCapabilitiesSetup) {
fail("Expected ${CompositeKpmCapabilitiesSetup::class}, but found $composite")
}
assertEquals(
listOf(capabilities1, capabilities2), composite.children
)
val testCapabilitiesContainer = object : GradleKpmConfigurationCapabilitiesSetup.CapabilitiesContainer {
val setCapabilities = mutableListOf<Any>()
override fun capability(notation: Any) {
setCapabilities.add(notation)
}
}
composite.setCapabilities(testCapabilitiesContainer, dummyFragment)
assertEquals(
listOf<Any>("capability1", "capability2"), testCapabilitiesContainer.setCapabilities,
"Expected 'dummyContext' to receive all capabilities"
)
}
@Test
fun `test definition + capability`() {
val definition = GradleKpmConfigurationSetup<GradleKpmFragment>(
provider = GradleKpmConfigurationProvider { throw NotImplementedError() }
)
val capabilities1 = GradleKpmConfigurationCapabilitiesSetup<GradleKpmFragment> {}
val capabilities2 = GradleKpmConfigurationCapabilitiesSetup<GradleKpmFragment> {}
val newDefinition = definition + capabilities1 + capabilities2
assertEquals(
listOf(capabilities1, capabilities2), (newDefinition.capabilities as? CompositeKpmCapabilitiesSetup)?.children,
"Expected 'newDefinition' to list all added capabilities"
)
}
}

Some files were not shown because too many files have changed in this diff Show More