Add some API interfaces for Gradle PM20 entities in the API module

This commit is contained in:
Sergey Igushkin
2021-03-19 18:20:44 +03:00
parent a52c6858a9
commit ea458e6848
16 changed files with 555 additions and 181 deletions
@@ -16,6 +16,7 @@ dependencies {
compileOnly(gradleApi())
compileOnly("com.android.tools.build:gradle:3.4.0")
compileOnly(project(":kotlin-project-model"))
}
pill {
@@ -0,0 +1,71 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationOutput
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
interface KotlinCompilationData<T : KotlinCommonOptions> {
val project: Project
val owner: Any?
val compilationPurpose: String
val compilationClassifier: String?
val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet>
val compileKotlinTaskName: String
val compileAllTaskName: String
val compileDependencyFiles: FileCollection
val output: KotlinCompilationOutput
val languageSettings: LanguageSettingsBuilder
val platformType: KotlinPlatformType
val moduleName: String
val ownModuleName: String
val kotlinOptions: T
val friendPaths: Iterable<FileCollection>
}
interface KotlinVariantCompilationData<T : KotlinCommonOptions> : KotlinCompilationData<T> {
override val owner: KotlinGradleVariant
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: LanguageSettingsBuilder
get() = owner.languageSettings
override val platformType: KotlinPlatformType
get() = owner.platformType
override val ownModuleName: String
}
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import groovy.lang.Closure
import org.gradle.api.Named
import org.gradle.api.NamedDomainObjectProvider
import org.gradle.api.Project
import org.gradle.api.file.SourceDirectorySet
import org.gradle.util.ConfigureUtil
import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
import org.jetbrains.kotlin.project.model.KotlinModuleFragment
interface KotlinGradleFragment : KotlinModuleFragment, HasKotlinDependencies, Named {
override val kotlinSourceRoots: SourceDirectorySet
override val containingModule: KotlinGradleModule
override fun getName(): String = fragmentName
// TODO pull up to KotlinModuleFragment
// FIXME apply to compilation
// FIXME check for consistency
val languageSettings: LanguageSettingsBuilder
val project: Project
get() = containingModule.project
fun refines(other: KotlinGradleFragment)
fun refines(other: NamedDomainObjectProvider<KotlinGradleFragment>)
override fun dependencies(configureClosure: Closure<Any?>) =
dependencies f@{ ConfigureUtil.configure(configureClosure, this@f) }
companion object {
const val COMMON_FRAGMENT_NAME = "common"
}
/** This configuration includes the dependencies from the refines-parents */
val transitiveApiConfigurationName: String
/** This configuration includes the dependencies from the refines-parents */
val transitiveImplementationConfigurationName: String
override val relatedConfigurationNames: List<String>
get() = super.relatedConfigurationNames +
// TODO: resolvable metadata configurations?
listOf(transitiveApiConfigurationName, transitiveImplementationConfigurationName)
}
@@ -0,0 +1,67 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import groovy.lang.Closure
import org.gradle.api.ExtensiblePolymorphicDomainObjectContainer
import org.gradle.api.Named
import org.gradle.api.NamedDomainObjectSet
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
import org.jetbrains.kotlin.project.model.KotlinModule
interface KotlinGradleModule : KotlinModule, Named, HasKotlinDependencies {
val project: Project
val moduleClassifier: String?
override val fragments: ExtensiblePolymorphicDomainObjectContainer<KotlinGradleFragment>
// TODO DSL & build script model: find a way to create a flexible typed view on fragments?
override val variants: NamedDomainObjectSet<KotlinGradleVariant>
val isPublic: Boolean
fun ifMadePublic(action: () -> Unit)
fun makePublic()
companion object {
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: KotlinGradleFragment
get() = fragments.getByName(KotlinGradleFragment.COMMON_FRAGMENT_NAME)
fun common(configure: KotlinGradleFragment.() -> Unit) =
common.configure()
override fun dependencies(configure: KotlinDependencyHandler.() -> Unit) =
common.dependencies(configure)
override fun dependencies(configureClosure: Closure<Any?>) =
common.dependencies(configureClosure)
override val apiConfigurationName: String
get() = common.apiConfigurationName
override val implementationConfigurationName: String
get() = common.implementationConfigurationName
override val compileOnlyConfigurationName: String
get() = common.compileOnlyConfigurationName
override val runtimeOnlyConfigurationName: String
get() = common.runtimeOnlyConfigurationName
}
@@ -0,0 +1,67 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.FileCollection
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationOutput
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.project.model.KotlinModuleVariant
interface KotlinGradleVariant : KotlinGradleFragment, KotlinModuleVariant {
val platformType: KotlinPlatformType
// TODO generalize with KotlinCompilation?
val compileDependencyConfigurationName: String
var compileDependencyFiles: FileCollection
// TODO rewrite using our own artifacts API?
val compilationOutputs: KotlinCompilationOutput
// TODO rewrite using our own artifacts API
val sourceArchiveTask: TaskProvider<AbstractArchiveTask>
// TODO generalize exposing outputs: what if a variant has more than one such configurations or none?
val apiElementsConfigurationName: String
val gradleVariantNames: Set<String>
}
interface KotlinGradleVariantWithRuntime : KotlinGradleVariant {
// TODO deduplicate with KotlinCompilation?
val runtimeDependencyConfigurationName: String
var runtimeDependencyFiles: FileCollection
val runtimeFiles: ConfigurableFileCollection
// TODO generalize exposing outputs: what if a variant has more than one such configurations or none?
val runtimeElementsConfigurationName: String
}
interface KotlinNativeVariant : KotlinGradleVariant {
override val platformType: KotlinPlatformType
get() = KotlinPlatformType.native
var enableEndorsedLibraries: Boolean
}
interface SingleMavenPublicationHolder {
fun assignMavenPublication(publication: MavenPublication)
val defaultPublishedModuleSuffix: String?
val publishedMavenModuleCoordinates: PublishedModuleCoordinatesProvider
}
interface PublishedModuleCoordinatesProvider {
val group: String
val name: String
val version: String
val capabilities: Iterable<String>
}
@@ -17,9 +17,7 @@ import org.gradle.api.attributes.AttributeContainer
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
import org.jetbrains.kotlin.gradle.plugin.sources.getVisibleSourceSetsFromAssociateCompilations
@@ -32,50 +30,52 @@ class ProjectStructureMetadataModuleBuilder {
component: ResolvedComponentResult,
metadata: KotlinProjectStructureMetadata
): KotlinModule {
return ExternalImportedKotlinModule(
BasicKotlinModule(component.toModuleIdentifier()).apply {
metadata.sourceSetNamesByVariantName.keys.forEach { variantName ->
fragments.add(BasicKotlinModuleVariant(this@apply, variantName))
val moduleData = BasicKotlinModule(component.toSingleModuleIdentifier()).apply {
metadata.sourceSetNamesByVariantName.keys.forEach { variantName ->
fragments.add(BasicKotlinModuleVariant(this@apply, variantName))
}
fun fragment(sourceSetName: String): BasicKotlinModuleFragment {
if (fragments.none { it.fragmentName == sourceSetName })
fragments.add(BasicKotlinModuleFragment(this@apply, sourceSetName))
return fragmentByName(sourceSetName)
}
metadata.sourceSetNamesByVariantName.forEach { (variantName, sourceSets) ->
val variant = fragmentByName(variantName)
sourceSets.forEach { sourceSetName ->
variant.directRefinesDependencies.add(fragment(sourceSetName))
}
fun fragment(sourceSetName: String): BasicKotlinModuleFragment {
if (fragments.none { it.fragmentName == sourceSetName })
fragments.add(BasicKotlinModuleFragment(this@apply, sourceSetName))
return fragmentByName(sourceSetName)
}
metadata.sourceSetNamesByVariantName.forEach { (variantName, sourceSets) ->
val variant = fragmentByName(variantName)
sourceSets.forEach { sourceSetName ->
variant.directRefinesDependencies.add(fragment(sourceSetName))
}
}
metadata.sourceSetModuleDependencies.forEach { (sourceSetName, dependencies) ->
val fragment = fragment(sourceSetName)
dependencies.forEach { dependency ->
fragment.declaredModuleDependencies.add(
KotlinModuleDependency(
MavenModuleIdentifier(
dependency.groupId.orEmpty(),
dependency.moduleId,
null /* TODO */
)
}
metadata.sourceSetModuleDependencies.forEach { (sourceSetName, dependencies) ->
val fragment = fragment(sourceSetName)
dependencies.forEach { dependency ->
fragment.declaredModuleDependencies.add(
KotlinModuleDependency(
MavenModuleIdentifier(
dependency.groupId.orEmpty(),
dependency.moduleId,
null /* TODO */
)
)
}
)
}
}
metadata.sourceSetsDependsOnRelation.forEach { (depending, dependencies) ->
val dependingFragment = fragment(depending)
dependencies.forEach { dependency ->
dependingFragment.directRefinesDependencies.add(fragment(dependency))
}
metadata.sourceSetsDependsOnRelation.forEach { (depending, dependencies) ->
val dependingFragment = fragment(depending)
dependencies.forEach { dependency ->
dependingFragment.directRefinesDependencies.add(fragment(dependency))
}
},
metadata
}
}
return ExternalImportedKotlinModule(
moduleData,
metadata,
moduleData.fragments.filterTo(mutableSetOf()) { it.fragmentName in metadata.hostSpecificSourceSets }
)
}
fun getModule(component: ResolvedComponentResult, projectStructureMetadata: KotlinProjectStructureMetadata): KotlinModule {
val moduleId = component.toModuleIdentifier()
val moduleId = component.toSingleModuleIdentifier()
return modulesCache.getOrPut(moduleId) {
buildModuleFromProjectStructureMetadata(
component,
@@ -109,13 +109,6 @@ internal object ModuleIds {
}
}
interface PublishedModuleCoordinatesProvider {
val group: String
val name: String
val version: String
val capabilities: Iterable<String>
}
open class MavenPublicationCoordinatesProvider(
project: Project,
val getPublication: () -> MavenPublication?,
@@ -9,38 +9,40 @@ 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.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationOutput
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.dsl.pm20Extension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.isMain
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.project.model.refinesClosure
interface KotlinCompilationData<T : KotlinCommonOptions> {
val project: Project
val owner: Any?
interface KotlinVariantCompilationDataInternal<T : KotlinCommonOptions> : KotlinVariantCompilationData<T> {
override val compileKotlinTaskName: String
get() = lowerCamelCaseName("compile", compilationPurpose.takeIf { it != "main" }, "Kotlin", compilationClassifier)
val compilationPurpose: String
val compilationClassifier: String?
override val compileAllTaskName: String
get() = owner.disambiguateName("classes")
val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet>
val compileKotlinTaskName: String
val compileAllTaskName: String
override val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet>
get() = owner.refinesClosure.filterIsInstance<KotlinGradleVariant>().associate { it.disambiguateName("") to it.kotlinSourceRoots }
val compileDependencyFiles: FileCollection
val output: KotlinCompilationOutput
override val friendPaths: Iterable<FileCollection>
// TODO for now, all output classes of the module are considered friends, even those not on the classpath
get() {
// FIXME support compiling against the artifact task outputs
// TODO note for Android: see the friend artifacts code in KotlinAndroidCompilation
return owner.containingModule.project.pm20Extension.modules.flatMap { it.variants.map { it.compilationOutputs.classesDirs } }
}
val languageSettings: LanguageSettingsBuilder
val platformType: KotlinPlatformType
override val moduleName: String
get() = // TODO accurate module names that don't rely on all variants having a main counterpart
owner.containingModule.project.pm20Extension.modules
.getByName(KotlinGradleModule.MAIN_MODULE_NAME).variants.findByName(owner.name)?.ownModuleName() ?: ownModuleName
val moduleName: String
val ownModuleName: String
val kotlinOptions: T
val friendPaths: Iterable<FileCollection>
override val ownModuleName: String
get() = owner.ownModuleName()
}
fun KotlinCompilationData<*>.isMain(): Boolean = when (this) {
fun KotlinCompilationData<*>.isMainCompilationData(): Boolean = when (this) {
is KotlinCompilation<*> -> isMain()
else -> compilationPurpose == KotlinGradleModule.MAIN_MODULE_NAME
}
@@ -6,15 +6,11 @@
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import groovy.lang.Closure
import org.gradle.api.Named
import org.gradle.api.NamedDomainObjectProvider
import org.gradle.api.Project
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.provider.Provider
import org.gradle.util.ConfigureUtil
import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultKotlinDependencyHandler
import org.jetbrains.kotlin.gradle.plugin.mpp.toModuleDependency
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
@@ -25,27 +21,24 @@ import org.jetbrains.kotlin.project.model.KotlinModuleFragment
import org.jetbrains.kotlin.project.model.refinesClosure
import javax.inject.Inject
open class KotlinGradleFragment @Inject constructor(
open class KotlinGradleFragmentInternal @Inject constructor(
override val containingModule: KotlinGradleModule,
override val fragmentName: String
) : KotlinModuleFragment, HasKotlinDependencies, Named {
) : KotlinGradleFragment {
override fun getName(): String = fragmentName
// TODO pull up to KotlinModuleFragment
// FIXME apply to compilation
// FIXME check for consistency
val languageSettings: LanguageSettingsBuilder = DefaultLanguageSettingsBuilder()
override val languageSettings: LanguageSettingsBuilder = DefaultLanguageSettingsBuilder()
protected val project: Project
get() = containingModule.project
open fun refines(other: KotlinGradleFragment) {
override fun refines(other: KotlinGradleFragment) {
checkCanRefine(other)
refines(containingModule.fragments.named(other.name))
}
open fun refines(other: NamedDomainObjectProvider<KotlinGradleFragment>) {
override fun refines(other: NamedDomainObjectProvider<KotlinGradleFragment>) {
_directRefinesDependencies.add(other)
other.configure { checkCanRefine(it) }
listOf(
@@ -92,23 +85,12 @@ open class KotlinGradleFragment @Inject constructor(
)
}
/** This configuration includes the dependencies from the refines-parents */
internal val transitiveApiConfigurationName: String
override val transitiveApiConfigurationName: String
get() = disambiguateName("transitiveApi")
/** This configuration includes the dependencies from the refines-parents */
internal val transitiveImplementationConfigurationName: String
override val transitiveImplementationConfigurationName: String
get() = disambiguateName("transitiveImplementation")
override val relatedConfigurationNames: List<String>
get() = super.relatedConfigurationNames +
// TODO: resolvable metadata configurations?
listOf(transitiveApiConfigurationName, transitiveImplementationConfigurationName)
companion object {
const val COMMON_FRAGMENT_NAME = "common"
}
override fun toString(): String = "fragment $fragmentName in $containingModule"
}
@@ -5,25 +5,25 @@
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import groovy.lang.Closure
import org.gradle.api.ExtensiblePolymorphicDomainObjectContainer
import org.gradle.api.Named
import org.gradle.api.NamedDomainObjectSet
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.project.model.*
import org.jetbrains.kotlin.project.model.KotlinModuleFragment
import org.jetbrains.kotlin.project.model.KotlinModuleIdentifier
import org.jetbrains.kotlin.project.model.LocalModuleIdentifier
import javax.inject.Inject
open class KotlinGradleModule(
internal val project: Project,
val moduleClassifier: String?
) : KotlinModule, Named, HasKotlinDependencies {
open class KotlinGradleModuleInternal(
final override val project: Project,
final override val moduleClassifier: String?
) : KotlinGradleModule {
@Inject
constructor(project: Project, moduleClassifier: CharSequence)
: this(project, moduleClassifier.toString().takeIf { it != MAIN_MODULE_NAME })
constructor(project: Project, moduleName: CharSequence) : this(
project,
moduleName.takeIf { it != KotlinGradleModule.MAIN_MODULE_NAME }?.toString()
)
override val moduleIdentifier: KotlinModuleIdentifier =
LocalModuleIdentifier(project.currentBuildId().name, project.path, moduleClassifier)
@@ -36,17 +36,17 @@ open class KotlinGradleModule(
fragments.withType(KotlinGradleVariant::class.java)
}
var isPublic: Boolean = false
private set
override var isPublic: Boolean = false
protected set
private var setPublicHandlers: MutableList<() -> Unit> = mutableListOf()
fun ifMadePublic(action: () -> Unit) {
override fun ifMadePublic(action: () -> Unit) {
// FIXME reentrancy?
if (isPublic) action() else setPublicHandlers.add(action)
}
fun makePublic() {
override fun makePublic() {
if (isPublic) return
setPublicHandlers.forEach { it() }
isPublic = true
@@ -57,37 +57,6 @@ open class KotlinGradleModule(
const val TEST_MODULE_NAME = "test"
}
override fun getName(): String = when (moduleClassifier) {
null -> MAIN_MODULE_NAME
else -> moduleClassifier
}
// DSL
val common: KotlinGradleFragment
get() = fragments.getByName(KotlinGradleFragment.COMMON_FRAGMENT_NAME)
fun common(configure: KotlinGradleFragment.() -> Unit) =
common.configure()
override fun dependencies(configure: KotlinDependencyHandler.() -> Unit) =
common.dependencies(configure)
override fun dependencies(configureClosure: Closure<Any?>) =
common.dependencies(configureClosure)
override val apiConfigurationName: String
get() = common.apiConfigurationName
override val implementationConfigurationName: String
get() = common.implementationConfigurationName
override val compileOnlyConfigurationName: String
get() = common.compileOnlyConfigurationName
override val runtimeOnlyConfigurationName: String
get() = common.runtimeOnlyConfigurationName
override fun toString(): String = "$moduleIdentifier (Gradle)"
}
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.gradle.dsl.pm20Extension
open class KotlinGradleModuleFactory(private val project: Project) : NamedDomainObjectFactory<KotlinGradleModule> {
override fun create(name: String): KotlinGradleModule {
val result = project.objects.newInstance(KotlinGradleModule::class.java, project, name)
val result = project.objects.newInstance(KotlinGradleModuleInternal::class.java, project, name)
registerFragmentFactory(result)
registerDefaultCommonFragment(result)
addDefaultDependencyOnMainModule(result)
@@ -26,9 +26,7 @@ open class KotlinJvmVariant(containingModule: KotlinGradleModule, fragmentName:
get() = KotlinPlatformType.jvm
}
class KotlinJvmVariantCompilationData(val variant: KotlinJvmVariant) : KotlinCompilationData<KotlinJvmOptions> {
override val project: Project get() = variant.containingModule.project
class KotlinJvmVariantCompilationData(val variant: KotlinJvmVariant) : KotlinVariantCompilationDataInternal<KotlinJvmOptions> {
override val owner: KotlinJvmVariant get() = variant
override val compilationPurpose: String
@@ -0,0 +1,173 @@
/*
* 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.Dependency
import org.gradle.api.artifacts.ModuleDependency
import org.gradle.api.attributes.Usage
import org.gradle.api.component.AdhocComponentWithVariants
import org.gradle.api.component.SoftwareComponentFactory
import org.gradle.api.internal.project.ProjectInternal
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.jvm.tasks.Jar
import org.jetbrains.kotlin.gradle.dsl.pm20Extension
import org.jetbrains.kotlin.gradle.plugin.KotlinNativeTargetConfigurator
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.CalculatedCapability
import org.jetbrains.kotlin.gradle.plugin.mpp.publishedConfigurationName
import org.jetbrains.kotlin.gradle.plugin.usageByName
import org.jetbrains.kotlin.gradle.targets.metadata.filesWithUnpackedArchives
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.utils.dashSeparatedName
import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION
import org.jetbrains.kotlin.project.model.refinesClosure
import org.jetbrains.kotlin.project.model.utils.variantsContainingFragment
import kotlin.reflect.KClass
open class KotlinNativeVariantFactory<T : KotlinNativeVariantInternal>(
module: KotlinGradleModule,
val variantClass: KClass<out T>
) :
AbstractKotlinGradleVariantFactory<T>(module) {
override fun instantiateFragment(name: String): T =
module.project.objects.newInstance(variantClass.java, module, name)
override fun setPlatformAttributesInConfiguration(fragment: T, configuration: Configuration) {
super.setPlatformAttributesInConfiguration(fragment, configuration)
configuration.attributes.attribute(KotlinNativeTarget.konanTargetAttribute, fragment.konanTarget.name)
}
override fun create(name: String): T =
super.create(name).also { result ->
configureVariantPublishing(result)
}
override fun configureKotlinCompilation(fragment: T) {
val compilationData = fragment.compilationData
//FIXME: deduplicate with KotlinJvmVariantFactory
val classesTaskName = compilationData.compileAllTaskName
project.tasks.register(classesTaskName) { classesTask ->
classesTask.dependsOn(fragment.compilationOutputs.allOutputs)
}
//FIXME: needs refactoring so as not to create the configurator
val compileTask = with(KotlinNativeTargetConfigurator<Nothing>(project.getKotlinPluginVersion()!!)) {
project.createKlibCompilationTask(compilationData)
}
// FIXME: duplication with KotlinJvmVariantFactory
val allSources = { project.files(Callable { fragment.refinesClosure.map { it.kotlinSourceRoots } }) }
val commonSources = {
project.files(Callable {
fragment.refinesClosure.filter { module.variantsContainingFragment(it).count() > 1 }.map { it.kotlinSourceRoots }
})
}
compileTask.configure {
it.source(allSources)
it.commonSources.from(commonSources)
}
}
open fun configureVariantPublishing(variant: T) {
val rootSoftwareComponent =
project.components
.withType(AdhocComponentWithVariants::class.java)
.getByName(rootPublicationComponentName(module))
val platformModuleDependencyProvider = project.provider {
val coordinates = variant.publishedMavenModuleCoordinates
(project.dependencies.create("${coordinates.group}:${coordinates.name}:${coordinates.version}") as ModuleDependency).apply {
if (module.moduleClassifier != null) {
capabilities { it.requireCapability(CalculatedCapability.fromModule(module)) }
}
}
}
val apiElements = project.configurations.getByName(variant.apiElementsConfigurationName)
val hostSpecificMetadataJar = project.registerTask<Jar>(variant.disambiguateName("hostSpecificMetadataJar")) { jar ->
jar.archiveClassifier.set("metadata")
jar.archiveAppendix.set(variant.disambiguateName(""))
project.pm20Extension.metadataCompilationRegistryByModuleId.getValue(variant.containingModule.moduleIdentifier)
.withAll { metadataCompilation ->
val fragment = metadataCompilation.fragment
if (metadataCompilation is KotlinNativeFragmentMetadataCompilationData) {
jar.from(project.files(Callable {
if (fragment in variant.refinesClosure && fragment.isNativeHostSpecific())
project.filesWithUnpackedArchives(metadataCompilation.output.allOutputs, setOf(KLIB_FILE_EXTENSION))
else emptyList<Any>()
})) { spec -> spec.into(fragment.name) }
}
}
}
val hostSpecificMetadataElements = project.configurations.create(variant.hostSpecificMetadataConfigurationName).apply {
isCanBeResolved = false
isCanBeConsumed = false
setPlatformAttributesAndMetadataUsage(variant)
project.artifacts.add(name, hostSpecificMetadataJar)
dependencies.addAllLater(project.objects.listProperty(Dependency::class.java).apply {
set(project.provider { apiElements.allDependencies })
})
}
// FIXME inject vs internal API
val platformComponentName = platformComponentName(variant)
val platformComponent = (project as ProjectInternal).services
.get(SoftwareComponentFactory::class.java)
.adhoc(platformComponentName)
project.components.add(platformComponent)
platformComponent.addVariantsFromConfiguration(apiElements) {
it.mapToMavenScope("compile")
}
platformComponent.addVariantsFromConfiguration(hostSpecificMetadataElements) { }
module.ifMadePublic {
project.pluginManager.withPlugin("maven-publish") {
project.extensions.getByType(PublishingExtension::class.java).apply {
publications.create(platformComponentName, MavenPublication::class.java).apply {
(this as DefaultMavenPublication).isAlias = true
from(platformComponent)
variant.assignMavenPublication(this)
artifactId = dashSeparatedName(project.name, variant.defaultPublishedModuleSuffix)
}
}
}
}
val publishedApiConfiguration =
project.configurations.create(publishedConfigurationName(variant.apiElementsConfigurationName)).apply {
isCanBeConsumed = false
isCanBeResolved = false
configureApiElementsConfiguration(variant, this)
setModuleCapability(this, module)
dependencies.addLater(platformModuleDependencyProvider)
}
val publishedMetadataConfiguration =
project.configurations.create(publishedConfigurationName(variant.hostSpecificMetadataConfigurationName)).apply {
isCanBeConsumed = false
isCanBeResolved = false
setPlatformAttributesAndMetadataUsage(variant)
setModuleCapability(this, module)
dependencies.addLater(platformModuleDependencyProvider)
}
rootSoftwareComponent.addVariantsFromConfiguration(publishedApiConfiguration) { }
rootSoftwareComponent.addVariantsFromConfiguration(publishedMetadataConfiguration) { }
}
private fun Configuration.setPlatformAttributesAndMetadataUsage(variant: T) {
configureApiElementsConfiguration(variant, this) // then override the Usage attribute
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_METADATA))
}
open fun platformComponentName(variant: T) = variant.disambiguateName("")
}
@@ -5,66 +5,58 @@
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.FileCollection
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationOutput
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultKotlinCompilationOutput
import org.jetbrains.kotlin.gradle.plugin.mpp.MavenPublicationCoordinatesProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.PublishedModuleCoordinatesProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.CalculatedCapability
import org.jetbrains.kotlin.gradle.plugin.mpp.publishedConfigurationName
import org.jetbrains.kotlin.gradle.tasks.withType
import org.jetbrains.kotlin.gradle.utils.dashSeparatedName
import org.jetbrains.kotlin.project.model.KotlinAttributeKey
import org.jetbrains.kotlin.project.model.KotlinModuleVariant
import org.jetbrains.kotlin.project.model.KotlinPlatformTypeAttribute
abstract class KotlinGradleVariant(
abstract class KotlinGradleVariantInternal(
containingModule: KotlinGradleModule,
override val fragmentName: String
) : KotlinGradleFragment(containingModule, fragmentName), KotlinModuleVariant {
) : KotlinGradleFragmentInternal(containingModule, fragmentName), KotlinGradleVariant {
abstract val platformType: KotlinPlatformType
final override val project: Project // overriding with final to avoid warnings
get() = super<KotlinGradleFragmentInternal>.project
override val variantAttributes: Map<KotlinAttributeKey, String>
get() = mapOf(KotlinPlatformTypeAttribute to kotlinPlatformTypeAttributeFromPlatform(platformType)) // TODO user attributes
// TODO generalize with KotlinCompilation?
val compileDependencyConfigurationName: String
override val compileDependencyConfigurationName: String
get() = disambiguateName("CompileDependencies")
open lateinit var compileDependencyFiles: FileCollection
override lateinit var compileDependencyFiles: FileCollection
// TODO rewrite using our own artifacts API?
val compilationOutputs: KotlinCompilationOutput =
override val compilationOutputs: KotlinCompilationOutput =
DefaultKotlinCompilationOutput(
project,
project.provider { project.buildDir.resolve("processedResources/${containingModule.name}/${fragmentName}") }
)
// TODO rewrite using our own artifacts API
open val sourceArchiveTask: TaskProvider<AbstractArchiveTask>
override val sourceArchiveTask: TaskProvider<AbstractArchiveTask>
get() = project.tasks.withType<AbstractArchiveTask>().named(defaultSourceArtifactTaskName)
// TODO generalize exposing outputs: what if a variant has more than one such configurations or none?
val apiElementsConfigurationName: String
override val apiElementsConfigurationName: String
get() = disambiguateName("apiElements")
abstract val gradleVariantNames: Set<String>
override fun toString(): String = "variant $fragmentName in $containingModule"
}
interface SingleMavenPublicationHolder {
fun assignMavenPublication(publication: MavenPublication)
val defaultPublishedModuleSuffix: String?
val publishedMavenModuleCoordinates: PublishedModuleCoordinatesProvider
}
class DefaultSingleMavenPublicationHolder(
private var module: KotlinGradleModule,
override val defaultPublishedModuleSuffix: String?
@@ -94,22 +86,23 @@ private fun kotlinPlatformTypeAttributeFromPlatform(platformType: KotlinPlatform
internal val KotlinGradleVariant.defaultSourceArtifactTaskName: String
get() = disambiguateName("sourcesJar")
abstract class KotlinGradleVariantWithRuntime(
abstract class KotlinGradleVariantWithRuntimeInternal(
containingModule: KotlinGradleModule,
fragmentName: String
) : KotlinGradleVariant(containingModule, fragmentName) {
) : KotlinGradleVariantInternal(containingModule, fragmentName), KotlinGradleVariantWithRuntime {
// TODO deduplicate with KotlinCompilation?
val runtimeDependencyConfigurationName: String
override val runtimeDependencyConfigurationName: String
get() = disambiguateName("RuntimeDependencies")
open lateinit var runtimeDependencyFiles: FileCollection
override lateinit var runtimeDependencyFiles: FileCollection
open val runtimeFiles: ConfigurableFileCollection by lazy {
project.files(compilationOutputs.allOutputs, runtimeDependencyFiles)
}
override val runtimeFiles: ConfigurableFileCollection = project.files(
{ compilationOutputs.allOutputs },
{ runtimeDependencyFiles }
)
// TODO generalize exposing outputs: what if a variant has more than one such configurations or none?
val runtimeElementsConfigurationName: String
override val runtimeElementsConfigurationName: String
get() = disambiguateName("runtimeElements")
}
@@ -117,7 +110,7 @@ private fun defaultModuleSuffix(module: KotlinGradleModule, variantName: String)
dashSeparatedName(variantName, module.moduleClassifier)
abstract class KotlinGradlePublishedVariantWithRuntime(containingModule: KotlinGradleModule, fragmentName: String) :
KotlinGradleVariantWithRuntime(containingModule, fragmentName),
KotlinGradleVariantWithRuntimeInternal(containingModule, fragmentName),
SingleMavenPublicationHolder by DefaultSingleMavenPublicationHolder(
containingModule,
defaultModuleSuffix(containingModule, fragmentName)
@@ -60,7 +60,7 @@ abstract class AbstractKotlinGradleFragmentFactory<T : KotlinGradleFragment>(
}
}
class CommonGradleFragmentFactory(module: KotlinGradleModule) : AbstractKotlinGradleFragmentFactory<KotlinGradleFragment>(module) {
override fun instantiateFragment(name: String): KotlinGradleFragment =
project.objects.newInstance(KotlinGradleFragment::class.java, module, name)
class CommonGradleFragmentFactory(module: KotlinGradleModule) : AbstractKotlinGradleFragmentFactory<KotlinGradleFragmentInternal>(module) {
override fun instantiateFragment(name: String): KotlinGradleFragmentInternal =
project.objects.newInstance(KotlinGradleFragmentInternal::class.java, module, name)
}
@@ -12,12 +12,12 @@ import org.gradle.api.tasks.TaskProvider
import org.gradle.jvm.tasks.Jar
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptions
import org.jetbrains.kotlin.gradle.dsl.pm20Extension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.KotlinCommonSourceSetProcessor
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.usageByName
import org.jetbrains.kotlin.gradle.targets.metadata.NativeSharedCompilationProcessor
import org.jetbrains.kotlin.gradle.targets.metadata.createGenerateProjectStructureMetadataTask
import org.jetbrains.kotlin.gradle.targets.metadata.filesWithUnpackedArchives
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.tasks.withType
@@ -124,10 +124,14 @@ private fun configureMetadataJarTask(
task.archiveAppendix.set("metadata")
task.from()
}
registry.withAll { compilationData ->
module.fragments.all { fragment ->
allMetadataJar.configure { jar ->
jar.from(compilationData.output.allOutputs) { spec ->
spec.into(compilationData.fragment.fragmentName)
val metadataOutput = project.files(Callable {
val compilationData = registry.byFragment(fragment)
project.filesWithUnpackedArchives(compilationData.output.allOutputs, setOf(KLIB_FILE_EXTENSION))
})
jar.from(metadataOutput) { spec ->
spec.into(fragment.fragmentName)
}
}
}