[Gradle] ExternalKotlinTargetApi: Configure apiElements and runtimeElements configurations

KT-54981
This commit is contained in:
Sebastian Sellmair
2022-11-16 10:06:30 +01:00
committed by Space Team
parent c8306f1a3b
commit 7368752c24
5 changed files with 119 additions and 47 deletions
@@ -9,7 +9,6 @@ package org.jetbrains.kotlin.gradle.android
import com.android.build.gradle.AppExtension
import com.android.build.gradle.internal.publishing.AndroidArtifacts
import org.gradle.api.attributes.Usage
import org.gradle.api.attributes.java.TargetJvmEnvironment
import org.gradle.api.attributes.java.TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE
import org.gradle.kotlin.dsl.getByType
@@ -46,8 +45,22 @@ fun KotlinMultiplatformExtension.androidTargetPrototype(): PrototypeAndroidTarge
val androidTarget = createExternalKotlinTarget<PrototypeAndroidTarget> {
targetName = "android"
platformType = KotlinPlatformType.jvm
targetFactory = TargetFactory { delegate ->
PrototypeAndroidTarget(delegate, PrototypeAndroidDsl(31))
targetFactory = TargetFactory { delegate -> PrototypeAndroidTarget(delegate, PrototypeAndroidDsl(31)) }
apiElements.configure { _, configuration ->
configuration.attributes.attribute(TARGET_JVM_ENVIRONMENT_ATTRIBUTE, project.objects.named(TargetJvmEnvironment.ANDROID))
}
runtimeElements.configure { _, configuration ->
configuration.attributes.attribute(TARGET_JVM_ENVIRONMENT_ATTRIBUTE, project.objects.named(TargetJvmEnvironment.ANDROID))
}
apiElementsPublished.configure { _, configuration ->
configuration.attributes.attribute(TARGET_JVM_ENVIRONMENT_ATTRIBUTE, project.objects.named(TargetJvmEnvironment.ANDROID))
}
runtimeElementsPublished.configure { _, configuration ->
configuration.attributes.attribute(TARGET_JVM_ENVIRONMENT_ATTRIBUTE, project.objects.named(TargetJvmEnvironment.ANDROID))
}
}
@@ -111,44 +124,30 @@ fun KotlinMultiplatformExtension.androidTargetPrototype(): PrototypeAndroidTarge
/*
Setup apiElements configuration:
Usage: JAVA_API
jvmEnvironment: Android
variants:
- classes (provides access to the compiled .class files)
artifactType: CLASSES_JAR
*/
project.configurations.getByName(androidTarget.apiElementsConfigurationName).apply {
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_API))
attributes.attribute(TARGET_JVM_ENVIRONMENT_ATTRIBUTE, project.objects.named(TargetJvmEnvironment.ANDROID))
outgoing.variants.create("classes").let { variant ->
variant.attributes.attribute(AndroidArtifacts.ARTIFACT_TYPE, AndroidArtifacts.ArtifactType.CLASSES_JAR.type)
variant.artifact(mainCompilation.output.classesDirs.singleFile) {
it.builtBy(mainCompilation.output.classesDirs)
}
androidTarget.apiElementsConfiguration.outgoing.variants.create("classes").let { variant ->
variant.attributes.attribute(AndroidArtifacts.ARTIFACT_TYPE, AndroidArtifacts.ArtifactType.CLASSES_JAR.type)
variant.artifact(mainCompilation.output.classesDirs.singleFile) {
it.builtBy(mainCompilation.output.classesDirs)
}
}
/*
Setup runtimeElements configuration:
Usage: JAVA_RUNTIME
jvmEnvironment: Android
variants:
- classes (provides access to the compiled .class files)
artifactType: CLASSES_JAR
*/
project.configurations.getByName(androidTarget.runtimeElementsConfigurationName).apply {
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_RUNTIME))
attributes.attribute(TARGET_JVM_ENVIRONMENT_ATTRIBUTE, project.objects.named(TargetJvmEnvironment.ANDROID))
outgoing.variants.create("classes").let { variant ->
variant.attributes.attribute(AndroidArtifacts.ARTIFACT_TYPE, AndroidArtifacts.ArtifactType.CLASSES_JAR.type)
variant.artifact(mainCompilation.output.classesDirs.singleFile) {
it.builtBy(mainCompilation.output.classesDirs)
}
androidTarget.runtimeElementsConfiguration.outgoing.variants.create("classes").let { variant ->
variant.attributes.attribute(AndroidArtifacts.ARTIFACT_TYPE, AndroidArtifacts.ArtifactType.CLASSES_JAR.type)
variant.artifact(mainCompilation.output.classesDirs.singleFile) {
it.builtBy(mainCompilation.output.classesDirs)
}
}
/*
"Disable" configurations from plain Android plugin
This hack will not be necessary in the final implementation
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.gradle.plugin.mpp.external
import org.gradle.api.artifacts.Configuration
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
import org.jetbrains.kotlin.gradle.ExternalKotlinTargetApi
@@ -18,5 +19,9 @@ abstract class DecoratedExternalKotlinTarget internal constructor(
class Delegate internal constructor(internal val impl: ExternalKotlinTargetImpl)
val apiElementsConfiguration: Configuration = delegate.apiElementsConfiguration
val runtimeElementsConfiguration: Configuration = delegate.runtimeElementsConfiguration
internal val logger: Logger = Logging.getLogger("${ExternalKotlinTargetImpl::class.qualifiedName}: $name")
}
@@ -0,0 +1,37 @@
/*
* 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.external
import org.gradle.api.artifacts.Configuration
import org.jetbrains.kotlin.gradle.ExternalKotlinTargetApi
@ExternalKotlinTargetApi
interface ExternalKotlinTargetConfigurationDescriptor<T : DecoratedExternalKotlinTarget> {
val configure: ((target: T, configuration: Configuration) -> Unit)?
}
@ExternalKotlinTargetApi
class ExternalKotlinTargetConfigurationDescriptorBuilder<T : DecoratedExternalKotlinTarget> internal constructor() {
var configure: ((target: T, configuration: Configuration) -> Unit)? = null
fun configure(action: (target: T, configuration: Configuration) -> Unit) = apply {
val configure = this.configure
if (configure == null) this.configure = action
else this.configure = { target, configuration ->
configure(target, configuration)
action(target, configuration)
}
}
internal fun build(): ExternalKotlinTargetConfigurationDescriptor<T> {
return ExternalKotlinTargetConfigurationDescriptorImpl(configure)
}
}
private data class ExternalKotlinTargetConfigurationDescriptorImpl<T : DecoratedExternalKotlinTarget>(
override val configure: ((target: T, configuration: Configuration) -> Unit)?
) : ExternalKotlinTargetConfigurationDescriptor<T>
@@ -20,50 +20,63 @@ interface ExternalKotlinTargetDescriptor<T : DecoratedExternalKotlinTarget> {
val targetName: String
val platformType: KotlinPlatformType
val targetFactory: TargetFactory<T>
val configure: ((T) -> Unit)?
}
@ExternalKotlinTargetApi
interface ExternalKotlinTargetDescriptorBuilder<T : DecoratedExternalKotlinTarget> {
var targetName: String
var platformType: KotlinPlatformType
var targetFactory: TargetFactory<T>
var configure: ((T) -> Unit)?
fun configure(action: (T) -> Unit) = apply {
val configure = this.configure
if (configure == null) this.configure = action
else this.configure = { configure(it); action(it) }
}
val configure: ((T) -> Unit)?
val apiElements: ExternalKotlinTargetConfigurationDescriptor<T>
val runtimeElements: ExternalKotlinTargetConfigurationDescriptor<T>
val apiElementsPublished: ExternalKotlinTargetConfigurationDescriptor<T>
val runtimeElementsPublished: ExternalKotlinTargetConfigurationDescriptor<T>
}
@ExternalKotlinTargetApi
fun <T : DecoratedExternalKotlinTarget> ExternalKotlinTargetDescriptor(
configure: ExternalKotlinTargetDescriptorBuilder<T>.() -> Unit
): ExternalKotlinTargetDescriptor<T> {
return ExternalKotlinTargetDescriptorBuilderImpl<T>().also(configure).build()
return ExternalKotlinTargetDescriptorBuilder<T>().also(configure).build()
}
@ExternalKotlinTargetApi
private class ExternalKotlinTargetDescriptorBuilderImpl<T : DecoratedExternalKotlinTarget> : ExternalKotlinTargetDescriptorBuilder<T> {
override var targetName: String by Delegates.notNull()
override var platformType: KotlinPlatformType by Delegates.notNull()
override var targetFactory: TargetFactory<T> by Delegates.notNull()
override var configure: ((T) -> Unit)? = null
class ExternalKotlinTargetDescriptorBuilder<T : DecoratedExternalKotlinTarget> internal constructor() {
var targetName: String by Delegates.notNull()
var platformType: KotlinPlatformType by Delegates.notNull()
var targetFactory: TargetFactory<T> by Delegates.notNull()
fun build(): ExternalKotlinTargetDescriptorImpl<T> = ExternalKotlinTargetDescriptorImpl(
val apiElements: ExternalKotlinTargetConfigurationDescriptorBuilder<T> =
ExternalKotlinTargetConfigurationDescriptorBuilder()
val runtimeElements: ExternalKotlinTargetConfigurationDescriptorBuilder<T> =
ExternalKotlinTargetConfigurationDescriptorBuilder()
val apiElementsPublished: ExternalKotlinTargetConfigurationDescriptorBuilder<T> =
ExternalKotlinTargetConfigurationDescriptorBuilder()
val runtimeElementsPublished: ExternalKotlinTargetConfigurationDescriptorBuilder<T> =
ExternalKotlinTargetConfigurationDescriptorBuilder()
var configure: ((T) -> Unit)? = null
internal fun build(): ExternalKotlinTargetDescriptor<T> = ExternalKotlinTargetDescriptorImpl(
targetName = targetName,
platformType = platformType,
targetFactory = targetFactory,
apiElements = apiElements.build(),
runtimeElements = runtimeElements.build(),
apiElementsPublished = apiElementsPublished.build(),
runtimeElementsPublished = runtimeElementsPublished.build(),
configure = configure
)
}
@ExternalKotlinTargetApi
private data class ExternalKotlinTargetDescriptorImpl<T : DecoratedExternalKotlinTarget>(
override val targetName: String,
override val platformType: KotlinPlatformType,
override val targetFactory: TargetFactory<T>,
override val configure: ((T) -> Unit)?
override val apiElements: ExternalKotlinTargetConfigurationDescriptor<T>,
override val runtimeElements: ExternalKotlinTargetConfigurationDescriptor<T>,
override val apiElementsPublished: ExternalKotlinTargetConfigurationDescriptor<T>,
override val runtimeElementsPublished: ExternalKotlinTargetConfigurationDescriptor<T>,
override val configure: ((T) -> Unit)?,
) : ExternalKotlinTargetDescriptor<T>
@@ -7,11 +7,16 @@
package org.jetbrains.kotlin.gradle.plugin.mpp.external
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.Usage
import org.gradle.jvm.tasks.Jar
import org.jetbrains.kotlin.gradle.ExternalKotlinTargetApi
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
import org.jetbrains.kotlin.gradle.plugin.usesPlatformOf
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.gradle.utils.named
@ExternalKotlinTargetApi
fun <T : DecoratedExternalKotlinTarget> KotlinMultiplatformExtension.createExternalKotlinTarget(
@@ -20,6 +25,7 @@ fun <T : DecoratedExternalKotlinTarget> KotlinMultiplatformExtension.createExter
val defaultConfiguration = project.configurations.maybeCreate(lowerCamelCaseName(descriptor.targetName, "default"))
val apiElementsConfiguration = project.configurations.maybeCreate(lowerCamelCaseName(descriptor.targetName, "apiElements"))
val runtimeElementsConfiguration = project.configurations.maybeCreate(lowerCamelCaseName(descriptor.targetName, "runtimeElements"))
val artifactsTaskLocator = ExternalKotlinTargetImpl.ArtifactsTaskLocator { target ->
target.project.locateOrRegisterTask<Jar>(lowerCamelCaseName(descriptor.targetName, "jar"))
}
@@ -36,9 +42,21 @@ fun <T : DecoratedExternalKotlinTarget> KotlinMultiplatformExtension.createExter
artifactsTaskLocator = artifactsTaskLocator
)
apiElementsConfiguration.usesPlatformOf(target)
apiElementsConfiguration.attributes.attribute(Usage.USAGE_ATTRIBUTE, KotlinUsages.producerApiUsage(target))
apiElementsConfiguration.attributes.attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY))
runtimeElementsConfiguration.usesPlatformOf(target)
runtimeElementsConfiguration.attributes.attribute(Usage.USAGE_ATTRIBUTE, KotlinUsages.producerRuntimeUsage(target))
runtimeElementsConfiguration.attributes.attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY))
val decorated = descriptor.targetFactory.create(DecoratedExternalKotlinTarget.Delegate(target))
target.onCreated()
descriptor.configure?.invoke(decorated)
descriptor.apiElements.configure?.invoke(decorated, apiElementsConfiguration)
descriptor.runtimeElements.configure?.invoke(decorated, runtimeElementsConfiguration)
targets.add(decorated)
decorated.logger.info("Created ${descriptor.platformType} target")
return decorated