Apply user-defined attributes in single-platform plugins
The attributes applied by the user to the target and its compilations were ignored in single-platform plugins while the target was not a part of the API. Since the user will be able to access and configure the target, we need to apply the attributes to the relevant configurations in the same way as in MPP.
This commit is contained in:
+42
@@ -921,4 +921,46 @@ class KotlinGradleIT : BaseGradleIT() {
|
||||
assertFileExists(moduleDir + "new-model-1.0-sources.jar")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUserDefinedAttributesInSinglePlatformProject() =
|
||||
with(Project("multiprojectWithDependency", GradleVersionRequired.AtLeast("4.7"))) {
|
||||
setupWorkingDir()
|
||||
gradleBuildScript("projA").appendText(
|
||||
"\n" + """
|
||||
def targetAttribute = Attribute.of("com.example.target", String)
|
||||
def compilationAttribute = Attribute.of("com.example.compilation", String)
|
||||
kotlin.target.attributes.attribute(targetAttribute, "foo")
|
||||
kotlin.target.compilations["main"].attributes.attribute(compilationAttribute, "foo")
|
||||
""".trimIndent()
|
||||
)
|
||||
gradleBuildScript("projB").appendText(
|
||||
"\n" + """
|
||||
def targetAttribute = Attribute.of("com.example.target", String)
|
||||
def compilationAttribute = Attribute.of("com.example.compilation", String)
|
||||
kotlin.target.attributes.attribute(targetAttribute, "foo")
|
||||
kotlin.target.compilations["main"].attributes.attribute(compilationAttribute, "foo")
|
||||
""".trimIndent()
|
||||
)
|
||||
build(":projB:compileKotlin") {
|
||||
assertSuccessful()
|
||||
}
|
||||
// Break dependency resolution by providing incompatible custom attributes in the target:
|
||||
gradleBuildScript("projB").appendText("\nkotlin.target.attributes.attribute(targetAttribute, \"bar\")")
|
||||
build(":projB:compileKotlin") {
|
||||
assertFailed()
|
||||
assertContains("Required com.example.target 'bar'")
|
||||
}
|
||||
// And using the compilation attributes (fix the target attributes first):
|
||||
gradleBuildScript("projB").appendText(
|
||||
"\n" + """
|
||||
kotlin.target.attributes.attribute(targetAttribute, "foo")
|
||||
kotlin.target.compilations["main"].attributes.attribute(compilationAttribute, "bar")
|
||||
""".trimIndent()
|
||||
)
|
||||
build(":projB:compileKotlin") {
|
||||
assertFailed()
|
||||
assertContains("Required com.example.compilation 'bar'")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -354,6 +354,8 @@ internal abstract class AbstractKotlinPlugin(
|
||||
{ compilation -> buildSourceSetProcessor(project, compilation, kotlinPluginVersion) }
|
||||
)
|
||||
|
||||
applyUserDefinedAttributes(target)
|
||||
|
||||
rewriteMppDependenciesInPom(target)
|
||||
|
||||
configureProjectGlobalSettings(project, kotlinPluginVersion)
|
||||
@@ -644,6 +646,9 @@ internal open class KotlinAndroidPlugin(
|
||||
(project.kotlinExtension as KotlinAndroidProjectExtension).target = androidTarget
|
||||
|
||||
applyToTarget(kotlinPluginVersion, androidTarget)
|
||||
|
||||
applyUserDefinedAttributes(androidTarget)
|
||||
|
||||
registry.register(KotlinModelBuilder(kotlinPluginVersion, androidTarget))
|
||||
|
||||
project.whenEvaluated { project.components.addAll(androidTarget.components) }
|
||||
|
||||
+51
-50
@@ -23,7 +23,10 @@ import org.gradle.api.tasks.compile.AbstractCompile
|
||||
import org.gradle.internal.reflect.Instantiator
|
||||
import org.gradle.jvm.tasks.Jar
|
||||
import org.gradle.util.ConfigureUtil
|
||||
import org.jetbrains.kotlin.gradle.dsl.*
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.configureOrCreate
|
||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
|
||||
import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild
|
||||
@@ -85,7 +88,7 @@ class KotlinMultiplatformPlugin(
|
||||
)
|
||||
configurePublishingWithMavenPublish(project)
|
||||
|
||||
setUpConfigurationAttributes(project)
|
||||
targetsContainer.all { applyUserDefinedAttributes(it) }
|
||||
|
||||
// propagate compiler plugin options to the source set language settings
|
||||
setupCompilerPluginOptions(project)
|
||||
@@ -226,54 +229,6 @@ class KotlinMultiplatformPlugin(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The attributes attached to the targets and compilations need to be propagated to the relevant Gradle configurations:
|
||||
* 1. Output configurations of each target need the corresponding compilation's attributes (and, indirectly, the target's attributes)
|
||||
* 2. Resolvable configurations of each compilation need the compilation's attributes
|
||||
*/
|
||||
private fun setUpConfigurationAttributes(project: Project) {
|
||||
val targets = project.multiplatformExtension.targets
|
||||
|
||||
project.afterEvaluate {
|
||||
targets.all { target ->
|
||||
fun copyAttributes(from: AttributeContainer, to: AttributeContainer) {
|
||||
fun <T> copyAttribute(key: Attribute<T>, from: AttributeContainer, to: AttributeContainer) {
|
||||
to.attribute(key, from.getAttribute(key)!!)
|
||||
}
|
||||
|
||||
from.keySet().forEach { key -> copyAttribute(key, from, to) }
|
||||
}
|
||||
|
||||
// To copy the attributes to the output configurations, find those output configurations and their producing compilations
|
||||
// based on the target's components:
|
||||
val outputConfigurationsWithCompilations =
|
||||
target.components.filterIsInstance<KotlinVariant>().flatMap { kotlinVariant ->
|
||||
kotlinVariant.usages.filterIsInstance<KotlinUsageContext>().mapNotNull { usageContext ->
|
||||
project.configurations.findByName(usageContext.dependencyConfigurationName)?.let { configuration ->
|
||||
configuration to usageContext.compilation
|
||||
}
|
||||
}
|
||||
} + listOfNotNull(
|
||||
target.compilations.findByName(KotlinCompilation.MAIN_COMPILATION_NAME)?.let { mainCompilation ->
|
||||
project.configurations.findByName(target.defaultConfigurationName)?.to(mainCompilation)
|
||||
}
|
||||
)
|
||||
|
||||
outputConfigurationsWithCompilations.forEach { (configuration, compilation) ->
|
||||
copyAttributes(compilation.attributes, configuration.attributes)
|
||||
}
|
||||
|
||||
target.compilations.all { compilation ->
|
||||
val compilationAttributes = compilation.attributes
|
||||
|
||||
compilation.relatedConfigurationNames
|
||||
.mapNotNull { configurationName -> target.project.configurations.findByName(configurationName) }
|
||||
.forEach { configuration -> copyAttributes(compilationAttributes, configuration.attributes) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val METADATA_TARGET_NAME = "metadata"
|
||||
|
||||
@@ -286,6 +241,52 @@ class KotlinMultiplatformPlugin(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The attributes attached to the targets and compilations need to be propagated to the relevant Gradle configurations:
|
||||
* 1. Output configurations of each target need the corresponding compilation's attributes (and, indirectly, the target's attributes)
|
||||
* 2. Resolvable configurations of each compilation need the compilation's attributes
|
||||
*/
|
||||
internal fun applyUserDefinedAttributes(target: KotlinTarget) {
|
||||
val project = target.project
|
||||
|
||||
project.whenEvaluated {
|
||||
fun copyAttributes(from: AttributeContainer, to: AttributeContainer) {
|
||||
fun <T> copyAttribute(key: Attribute<T>, from: AttributeContainer, to: AttributeContainer) {
|
||||
to.attribute(key, from.getAttribute(key)!!)
|
||||
}
|
||||
|
||||
from.keySet().forEach { key -> copyAttribute(key, from, to) }
|
||||
}
|
||||
|
||||
// To copy the attributes to the output configurations, find those output configurations and their producing compilations
|
||||
// based on the target's components:
|
||||
val outputConfigurationsWithCompilations =
|
||||
target.components.filterIsInstance<KotlinVariant>().flatMap { kotlinVariant ->
|
||||
kotlinVariant.usages.filterIsInstance<KotlinUsageContext>().mapNotNull { usageContext ->
|
||||
project.configurations.findByName(usageContext.dependencyConfigurationName)?.let { configuration ->
|
||||
configuration to usageContext.compilation
|
||||
}
|
||||
}
|
||||
} + listOfNotNull(
|
||||
target.compilations.findByName(KotlinCompilation.MAIN_COMPILATION_NAME)?.let { mainCompilation ->
|
||||
project.configurations.findByName(target.defaultConfigurationName)?.to(mainCompilation)
|
||||
}
|
||||
)
|
||||
|
||||
outputConfigurationsWithCompilations.forEach { (configuration, compilation) ->
|
||||
copyAttributes(compilation.attributes, configuration.attributes)
|
||||
}
|
||||
|
||||
target.compilations.all { compilation ->
|
||||
val compilationAttributes = compilation.attributes
|
||||
|
||||
compilation.relatedConfigurationNames
|
||||
.mapNotNull { configurationName -> target.project.configurations.findByName(configurationName) }
|
||||
.forEach { configuration -> copyAttributes(compilationAttributes, configuration.attributes) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun sourcesJarTask(compilation: KotlinCompilation<*>, componentName: String?, artifactNameAppendix: String): Jar {
|
||||
val project = compilation.target.project
|
||||
val taskName = lowerCamelCaseName(componentName, "sourcesJar")
|
||||
|
||||
Reference in New Issue
Block a user