From 988df517dd5c0159315b3d1da94712bdd635e681 Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Fri, 31 May 2019 17:44:30 +0300 Subject: [PATCH] Gradle HMPP support fixes after review * Add version to project structure metadata * Use a data class for module dependencies in project structure * Use task registering API for new tasks * Simplify code * Extract compatibility wrappers * Fix multi-file dependencies that transformations silently ignored --- .../kotlin/gradle/HierarchicalMppIT.kt | 14 ++-- .../mpp/GenerateProjectStructureMetadata.kt | 2 +- .../mpp/GranularMetadataTransformation.kt | 8 ++- .../plugin/mpp/KotlinMultiplatformPlugin.kt | 10 ++- .../mpp/KotlinProjectStructureMetadata.kt | 51 +++++++++---- .../plugin/mpp/KotlinSoftwareComponent.kt | 5 +- .../plugin/mpp/SourceSetVisibilityProvider.kt | 12 ++-- .../KotlinMetadataTargetConfigurator.kt | 72 ++++++++++--------- .../kotlin/gradle/tasks/TasksProvider.kt | 30 ++++++-- .../kotlin/gradle/utils/compatibiltiy.kt | 19 +++++ .../internals/ExposedForIntegrationTests.kt | 5 +- 11 files changed, 150 insertions(+), 78 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt index 3055338e7b1..4cb7313b000 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt @@ -5,11 +5,12 @@ package org.jetbrains.kotlin.gradle +import org.jetbrains.kotlin.gradle.internals.MULTIPLATFORM_PROJECT_METADATA_FILE_NAME import org.jetbrains.kotlin.gradle.internals.parseKotlinSourceSetMetadataFromXml import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinProjectStructureMetadata -import org.jetbrains.kotlin.gradle.plugin.mpp.MULTIPLATFORM_PROJECT_METADATA_FILE_NAME +import org.jetbrains.kotlin.gradle.plugin.mpp.ModuleDependencyIdentifier import org.jetbrains.kotlin.gradle.util.modify -import org.jetbrains.kotlin.konan.file.File +import java.io.File import java.util.zip.ZipFile import javax.xml.parsers.DocumentBuilderFactory import kotlin.test.Test @@ -79,9 +80,6 @@ class HierarchicalMppIT : BaseGradleIT() { } private fun checkMyLibFoo(compiledProject: CompiledProject, subprojectPrefix: String? = null) = with(compiledProject) { - val taskPrefix = subprojectPrefix?.let { ":$it" }.orEmpty() - val directoryPrefix = subprojectPrefix?.let { "$it/" }.orEmpty() - assertSuccessful() assertTasksExecuted(expectedTasks(subprojectPrefix)) @@ -297,7 +295,11 @@ class HierarchicalMppIT : BaseGradleIT() { "linuxAndJsMain" to setOf("commonMain"), "commonMain" to emptySet() ), - sourceSetModuleDependencies = sourceSetModuleDependencies + sourceSetModuleDependencies = sourceSetModuleDependencies.mapValues { (_, pairs) -> + pairs.map { + ModuleDependencyIdentifier(it.first, it.second) + }.toSet() + } ) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GenerateProjectStructureMetadata.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GenerateProjectStructureMetadata.kt index 7d091ef352f..b78e49dede1 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GenerateProjectStructureMetadata.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GenerateProjectStructureMetadata.kt @@ -41,4 +41,4 @@ open class GenerateProjectStructureMetadata : DefaultTask() { } } -const val MULTIPLATFORM_PROJECT_METADATA_FILE_NAME = "kotlin-project-structure-metadata.xml" \ No newline at end of file +internal const val MULTIPLATFORM_PROJECT_METADATA_FILE_NAME = "kotlin-project-structure-metadata.xml" \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt index 92ed1aa8556..3b6f3ec0123 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt @@ -239,9 +239,11 @@ internal class GranularMetadataTransformation( // concrete view on them: val requestedTransitiveDependencies: Set = mutableSetOf().apply { - projectStructureMetadata.sourceSetModuleDependencies - .filterKeys { it in allVisibleSourceSets } - .forEach { addAll(it.value) } + projectStructureMetadata.sourceSetModuleDependencies.forEach { (sourceSetName, moduleDependencies) -> + if (sourceSetName in allVisibleSourceSets) { + addAll(moduleDependencies.map { ModuleId(it.groupId, it.moduleId) }) + } + } } val transitiveDependenciesToVisit = module.children.filterTo(mutableSetOf()) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt index 69f2d49d2f0..4afa97aefe4 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt @@ -29,9 +29,7 @@ import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubplugin import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled -import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild -import org.jetbrains.kotlin.gradle.utils.checkGradleCompatibility -import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName +import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.presetName @@ -284,7 +282,7 @@ internal fun applyUserDefinedAttributes(target: AbstractKotlinTarget) { // based on the target's components: val outputConfigurationsWithCompilations = target.kotlinComponents.filterIsInstance().flatMap { kotlinVariant -> - kotlinVariant.usages.filterIsInstance().mapNotNull { usageContext -> + kotlinVariant.usages.mapNotNull { usageContext -> project.configurations.findByName(usageContext.dependencyConfigurationName)?.let { configuration -> configuration to usageContext.compilation } @@ -323,8 +321,8 @@ internal fun sourcesJarTask( (project.tasks.findByName(taskName) as? Jar)?.let { return it } val result = project.tasks.create(taskName, Jar::class.java) { sourcesJar -> - sourcesJar.appendix = artifactNameAppendix - sourcesJar.classifier = "sources" + sourcesJar.setArchiveAppendixCompatible { artifactNameAppendix } + sourcesJar.setArchiveClassifierCompatible { "sources" } } project.whenEvaluated { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt index 9ba32c6b3bf..76459c97c58 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import org.gradle.api.Project import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Internal import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull import org.jetbrains.kotlin.gradle.targets.metadata.getPublishedPlatformCompilations import org.w3c.dom.Document @@ -15,6 +16,11 @@ import org.w3c.dom.Node import org.w3c.dom.NodeList import javax.xml.parsers.DocumentBuilderFactory +data class ModuleDependencyIdentifier( + val groupId: String, + val moduleId: String +) + data class KotlinProjectStructureMetadata( @Input val sourceSetNamesByVariantName: Map>, @@ -22,9 +28,21 @@ data class KotlinProjectStructureMetadata( @Input val sourceSetsDependsOnRelation: Map>, + @Internal + val sourceSetModuleDependencies: Map>, + @Input - val sourceSetModuleDependencies: Map>> -) + val formatVersion: String = FORMAT_VERSION_0_1 +) { + @Suppress("UNUSED") // Gradle input + @get:Input + internal val sourceSetModuleDependenciesInput: Map>> + get() = sourceSetModuleDependencies.mapValues { (_, ids) -> ids.map { (group, module) -> group to module }.toSet() } + + companion object { + internal const val FORMAT_VERSION_0_1 = "0.1" + } +} internal fun buildKotlinProjectStructureMetadata(project: Project): KotlinProjectStructureMetadata? { val sourceSetsWithMetadataCompilations = @@ -43,19 +61,21 @@ internal fun buildKotlinProjectStructureMetadata(project: Project): KotlinProjec }, sourceSetModuleDependencies = sourceSetsWithMetadataCompilations.keys.associate { sourceSet -> sourceSet.name to project.configurations.getByName(sourceSet.apiConfigurationName).allDependencies.map { - it.group.orEmpty() to it.name + ModuleDependencyIdentifier(it.group.orEmpty(), it.name) }.toSet() } ) } internal fun KotlinProjectStructureMetadata.toXmlDocument(): Document { - val document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument().apply { + return DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument().apply { fun Node.node(name: String, action: Element.() -> Unit) = appendChild(createElement(name).apply(action)) fun Node.textNode(name: String, value: String) = appendChild(createElement(name).apply { appendChild(createTextNode(value)) }) node("projectStructure") { + textNode("formatVersion", formatVersion) + node("variants") { sourceSetNamesByVariantName.forEach { (variantName, sourceSets) -> node("variant") { @@ -74,14 +94,13 @@ internal fun KotlinProjectStructureMetadata.toXmlDocument(): Document { textNode("dependsOn", dependsOn) } sourceSetModuleDependencies[sourceSet].orEmpty().forEach { moduleDependency -> - textNode("moduleDependency", moduleDependency.first + ":" + moduleDependency.second) + textNode("moduleDependency", moduleDependency.groupId + ":" + moduleDependency.moduleId) } } } } } } - return document } private val NodeList.elements: Iterable get() = (0 until length).map { this@elements.item(it) }.filterIsInstance() @@ -89,6 +108,8 @@ private val NodeList.elements: Iterable get() = (0 until length).map { internal fun parseKotlinSourceSetMetadataFromXml(document: Document): KotlinProjectStructureMetadata? { val projectStructureNode = document.getElementsByTagName("projectStructure").elements.single() + val formatVersion = projectStructureNode.getElementsByTagName("formatVersion").item(0).textContent + val variantsNode = projectStructureNode.getElementsByTagName("variants").item(0) ?: return null val sourceSetsByVariant = mutableMapOf>() @@ -101,7 +122,7 @@ internal fun parseKotlinSourceSetMetadataFromXml(document: Document): KotlinProj } val sourceSetDependsOnRelation = mutableMapOf>() - val sourceSetModuleDependencies = mutableMapOf>>() + val sourceSetModuleDependencies = mutableMapOf>() val sourceSetsNode = projectStructureNode.getElementsByTagName("sourceSets").item(0) ?: return null @@ -109,12 +130,15 @@ internal fun parseKotlinSourceSetMetadataFromXml(document: Document): KotlinProj val sourceSetName = sourceSetNode.getElementsByTagName("name").elements.single().textContent val dependsOn = mutableSetOf() - val moduleDependencies = mutableSetOf>() + val moduleDependencies = mutableSetOf() - sourceSetNode.childNodes.elements.forEach { - when (it.tagName) { - "dependsOn" -> dependsOn.add(it.textContent) - "moduleDependency" -> moduleDependencies.add(it.textContent.split(":").let { (first, second) -> first to second }) + sourceSetNode.childNodes.elements.forEach { node -> + when (node.tagName) { + "dependsOn" -> dependsOn.add(node.textContent) + "moduleDependency" -> { + val (groupId, moduleId) = node.textContent.split(":") + moduleDependencies.add(ModuleDependencyIdentifier(groupId, moduleId)) + } } } @@ -125,6 +149,7 @@ internal fun parseKotlinSourceSetMetadataFromXml(document: Document): KotlinProj return KotlinProjectStructureMetadata( sourceSetsByVariant, sourceSetDependsOnRelation, - sourceSetModuleDependencies + sourceSetModuleDependencies, + formatVersion ) } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt index aca85f74842..5bf1818e3ec 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt @@ -61,8 +61,7 @@ class DefaultKotlinUsageContext( override val compilation: KotlinCompilation<*>, private val usage: Usage, override val dependencyConfigurationName: String, - private val overrideConfigurationArtifacts: Set? = null, - private val filterConfigurationAttributes: (Attribute<*>) -> Boolean = { true } + private val overrideConfigurationArtifacts: Set? = null ) : KotlinUsageContext { private val kotlinTarget: KotlinTarget get() = compilation.target @@ -107,7 +106,7 @@ class DefaultKotlinUsageContext( } configurationAttributes.keySet() - .filter { filterConfigurationAttributes(it) && it != ProjectLocalConfigurations.ATTRIBUTE } + .filter { it != ProjectLocalConfigurations.ATTRIBUTE } .forEach { copyAttribute(it, configurationAttributes, result) } return result diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/SourceSetVisibilityProvider.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/SourceSetVisibilityProvider.kt index 9e12def63e2..0f0657298e1 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/SourceSetVisibilityProvider.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/SourceSetVisibilityProvider.kt @@ -26,16 +26,20 @@ internal class SourceSetVisibilityProvider( fun getVisibleSourceSets( visibleFrom: KotlinSourceSet, dependencyScopes: Iterable, - mppDependency: ResolvedDependency, + resolvedMppDependency: ResolvedDependency, dependencyProjectStructureMetadata: KotlinProjectStructureMetadata, - otherProject: Project? + resolvedToOtherProject: Project? ): DependencySourceSetVisibilityResult { val visibleByThisSourceSet = - getVisibleSourceSetsImpl(visibleFrom, dependencyScopes, mppDependency, dependencyProjectStructureMetadata, otherProject) + getVisibleSourceSetsImpl( + visibleFrom, dependencyScopes, resolvedMppDependency, dependencyProjectStructureMetadata, resolvedToOtherProject + ) val visibleByParents = visibleFrom.dependsOn .flatMapTo(mutableSetOf()) { - getVisibleSourceSetsImpl(it, dependencyScopes, mppDependency, dependencyProjectStructureMetadata, otherProject) + getVisibleSourceSetsImpl( + it, dependencyScopes, resolvedMppDependency, dependencyProjectStructureMetadata, resolvedToOtherProject + ) } return DependencySourceSetVisibilityResult(visibleByThisSourceSet, visibleByParents) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt index 756588f66ae..f12879198e6 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt @@ -19,9 +19,12 @@ import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.sources.* import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider +import org.jetbrains.kotlin.gradle.tasks.createOrRegisterTask +import org.jetbrains.kotlin.gradle.tasks.locateTask import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation -import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName +import org.jetbrains.kotlin.gradle.utils.setArchiveAppendixCompatible +import org.jetbrains.kotlin.gradle.utils.setArchiveClassifierCompatible import java.io.File import java.util.concurrent.Callable @@ -88,14 +91,8 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : description = "Assembles a jar archive containing the metadata for all Kotlin source sets." group = BasePlugin.BUILD_GROUP - @Suppress("DEPRECATION") - if (isGradleVersionAtLeast(5, 2)) { - archiveAppendix.convention(target.name.toLowerCase()) - archiveClassifier.set("all") - } else { - appendix = target.name.toLowerCase() - classifier = "all" - } + setArchiveAppendixCompatible { target.name.toLowerCase() } + setArchiveClassifierCompatible { "all" } } } } @@ -127,7 +124,7 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : } sourceSetsWithMetadataCompilations.forEach { (sourceSet, metadataCompilation) -> - val compileMetadataTransformationTasksForHierarchy = mutableSetOf() + val compileMetadataTransformationTasksForHierarchy = mutableSetOf>() // Adjust metadata compilation to support source set hierarchies, i.e. use both the outputs of dependsOn source set compilation // and their dependencies metadata transformed for compilation: @@ -137,8 +134,7 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : metadataCompilation.compileDependencyFiles += dependencyCompilation.output.classesDirs.filter { it.exists() } } - project.tasks.withType(TransformKotlinGranularMetadata::class.java) - .findByName(transformGranularMetadataTaskName(hierarchySourceSet)) + project.locateTask(transformGranularMetadataTaskName(hierarchySourceSet)) ?.let(compileMetadataTransformationTasksForHierarchy::add) } @@ -149,10 +145,11 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : ) } - val generateMetadata = - createGenerateProjectStructureMetadataTask() + val generateMetadata = createGenerateProjectStructureMetadataTask() - allMetadataJar.from(project.files(Callable { generateMetadata.resultXmlFile }).builtBy(generateMetadata)) { spec -> + allMetadataJar.from(project.files(Callable { + generateMetadata.doGetTask().resultXmlFile + }).builtBy(generateMetadata.getTaskOrProvider())) { spec -> spec.into("META-INF").rename { MULTIPLATFORM_PROJECT_METADATA_FILE_NAME } } } @@ -182,7 +179,7 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : val metadataCompilation = when (sourceSet.name) { // Historically, we already had a 'main' compilation in metadata targets; TODO consider removing it instead KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME -> target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME) - else -> target.compilations.create(lowerCamelCaseName(sourceSet.name)) { compilation -> + else -> target.compilations.create(sourceSet.name) { compilation -> compilation.addExactSourceSetsEagerly(setOf(sourceSet)) } } @@ -193,12 +190,7 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : spec.into(metadataCompilation.defaultSourceSet.name) } - @Suppress("UnstableApiUsage") - project.tasks.create( - transformGranularMetadataTaskName(sourceSet), - TransformKotlinGranularMetadata::class.java, - sourceSet - ) + project.createOrRegisterTask(transformGranularMetadataTaskName(sourceSet), listOf(sourceSet)) { } return metadataCompilation } @@ -283,20 +275,30 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : private fun createTransformedMetadataClasspath( fromFiles: Iterable, project: Project, - granularMetadataTransformationTasks: Set + transformationTaskHolders: Set> ): FileCollection { return project.files(Callable { - val resolutionsByArtifactFile = granularMetadataTransformationTasks - .flatMap { it.metadataDependencyResolutions } - .groupBy { it.dependency } - .filterKeys { it.moduleArtifacts.size == 1 } // TODO do we have modules that resolve to more than one artifact? use sets? - .mapKeys { (dependency, _) -> dependency.moduleArtifacts.single().file } + val allResolutionsByArtifactFile: Map> = + mutableMapOf>().apply { + transformationTaskHolders.forEach { + val resolutions = it.doGetTask().metadataDependencyResolutions - val transformedFiles = granularMetadataTransformationTasks.flatMap { it.filesByResolution.toList() }.toMap() + resolutions.forEach { resolution -> + val artifacts = resolution.dependency.moduleArtifacts.map { it.file } + + artifacts.forEach { artifactFile -> + getOrPut(artifactFile) { mutableListOf() }.add(resolution) + } + } + } + } + + val transformedFilesByResolution: Map = + transformationTaskHolders.flatMap { it.doGetTask().filesByResolution.toList() }.toMap() mutableSetOf().apply { fromFiles.forEach { file -> - val resolutions = resolutionsByArtifactFile[file] + val resolutions = allResolutionsByArtifactFile[file] if (resolutions == null) { add(file) } else { @@ -304,14 +306,14 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : resolutions.filterIsInstance() if (chooseVisibleSourceSets.isNotEmpty()) { - add(chooseVisibleSourceSets.map { transformedFiles.getValue(it) }) + add(chooseVisibleSourceSets.map { transformedFilesByResolution.getValue(it) }) } else if (resolutions.any { it is MetadataDependencyResolution.KeepOriginalDependency }) { add(file) - } + } // else: all dependency transformations exclude this dependency as unrequested; don't add any files } } } - }).builtBy(granularMetadataTransformationTasks) + }).builtBy(transformationTaskHolders.map { it.getTaskOrProvider() }) } private fun getPublishedCommonSourceSets(project: Project): Set { @@ -333,8 +335,8 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : .keys } - private fun Project.createGenerateProjectStructureMetadataTask(): GenerateProjectStructureMetadata = - tasks.create("generateProjectStructureMetadata", GenerateProjectStructureMetadata::class.java) { task -> + private fun Project.createGenerateProjectStructureMetadataTask(): TaskHolder = + project.createOrRegisterTask("generateProjectStructureMetadata") { task -> task.lazyKotlinProjectStructureMetadata = lazy { checkNotNull(buildKotlinProjectStructureMetadata(project)) } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt index 998d2c7999c..12c443fe9dc 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.mpp.defaultSourceSetName import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinTask +import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast internal val useLazyTaskConfiguration = org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast(4, 9) internal val canLocateTask = org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast(5, 0) @@ -34,16 +35,33 @@ internal val canLocateTask = org.jetbrains.kotlin.gradle.utils.isGradleVersionAt @JvmName("registerTaskOld") @Deprecated("please use Project.createOrRegisterTask", ReplaceWith("project.createOrRegisterTask(name, body)")) internal fun registerTask(project: Project, name: String, type: Class, body: (T) -> (Unit)): TaskHolder = - project.createOrRegisterTask(name, type, body) + project.createOrRegisterTask(name, type, emptyList(), body) -internal inline fun Project.createOrRegisterTask(name: String, noinline body: (T) -> (Unit)): TaskHolder = - createOrRegisterTask(name, T::class.java, body) +internal inline fun Project.createOrRegisterTask( + name: String, + args: List = emptyList(), + noinline body: (T) -> (Unit) +): TaskHolder = + createOrRegisterTask(name, T::class.java, args, body) -internal fun Project.createOrRegisterTask(name: String, type: Class, body: (T) -> (Unit)): TaskHolder { +internal fun Project.createOrRegisterTask( + name: String, + type: Class, + constructorArgs: List = emptyList(), // note: args are only allowed with Gradle 4.7+ + body: (T) -> (Unit) +): TaskHolder { return if (useLazyTaskConfiguration) { - TaskProviderHolder(name, project, project.tasks.register(name, type) { with(it, body) }) + val provider = project.tasks.register(name, type, *constructorArgs.toTypedArray()).apply { configure(body) } + TaskProviderHolder(name, project, provider) } else { - val result = LegacyTaskHolder(project.tasks.create(name, type)) + val result = LegacyTaskHolder(if (constructorArgs.isEmpty()) { + project.tasks.create(name, type) + } else { + if (!isGradleVersionAtLeast(4, 7)) { + error("Cannot inject the arguments list into a task. This requires Gradle 4.7+.") + } + project.tasks.create(name, type, *constructorArgs.toTypedArray()) + }) with(result.doGetTask(), body) result } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/compatibiltiy.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/compatibiltiy.kt index c30ed4b9300..17d92111ebb 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/compatibiltiy.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/compatibiltiy.kt @@ -20,6 +20,7 @@ import org.gradle.api.GradleException import org.gradle.api.Task import org.gradle.api.tasks.TaskInputs import org.gradle.api.tasks.TaskOutputs +import org.gradle.api.tasks.bundling.AbstractArchiveTask import org.gradle.util.GradleVersion internal val Task.inputsCompatible: TaskInputs get() = inputs @@ -54,4 +55,22 @@ internal fun checkGradleCompatibility(minSupportedVersion: GradleVersion = Gradl "Please use Gradle $minSupportedVersion or newer or previous version of Kotlin plugin." ) } +} + +internal fun AbstractArchiveTask.setArchiveAppendixCompatible(appendixProvider: () -> String) { + if (isGradleVersionAtLeast(5, 2)) { + archiveAppendix.set(project.provider { appendixProvider() }) + } else { + @Suppress("DEPRECATION") + appendix = appendixProvider() + } +} + +internal fun AbstractArchiveTask.setArchiveClassifierCompatible(classifierProvider: () -> String) { + if (isGradleVersionAtLeast(5, 2)) { + archiveClassifier.set(project.provider { classifierProvider() }) + } else { + @Suppress("DEPRECATION") + classifier = classifierProvider() + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt index 73ff31a8e80..d1b6d1a24f1 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt @@ -9,4 +9,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinProjectStructureMetadata import org.w3c.dom.Document fun parseKotlinSourceSetMetadataFromXml(document: Document): KotlinProjectStructureMetadata? = - org.jetbrains.kotlin.gradle.plugin.mpp.parseKotlinSourceSetMetadataFromXml(document) \ No newline at end of file + org.jetbrains.kotlin.gradle.plugin.mpp.parseKotlinSourceSetMetadataFromXml(document) + +const val MULTIPLATFORM_PROJECT_METADATA_FILE_NAME = + org.jetbrains.kotlin.gradle.plugin.mpp.MULTIPLATFORM_PROJECT_METADATA_FILE_NAME \ No newline at end of file